mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
compiler: introduce @Restrict builtin
conservative, incomplete change
This commit is contained in:
parent
fc23fe90ce
commit
f250802ce7
@ -2876,6 +2876,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
|
||||
.validate_array_init_ref_ty,
|
||||
.array_init_elem_type,
|
||||
.array_init_elem_ptr,
|
||||
.restrict,
|
||||
=> break :b false,
|
||||
|
||||
.extended => switch (gz.astgen.instructions.items(.data)[@intFromEnum(inst)].extended.opcode) {
|
||||
@ -9547,6 +9548,11 @@ fn builtinCall(
|
||||
});
|
||||
return rvalue(gz, ri, result, node);
|
||||
},
|
||||
.Restrict => {
|
||||
const operand = try typeExpr(gz, scope, params[0]);
|
||||
const result = try gz.addUnNode(.restrict, operand, node);
|
||||
return rvalue(gz, ri, result, node);
|
||||
},
|
||||
|
||||
.add_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .add_with_overflow),
|
||||
.sub_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .sub_with_overflow),
|
||||
|
||||
@ -923,6 +923,7 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
|
||||
.work_item_id,
|
||||
.work_group_size,
|
||||
.work_group_id,
|
||||
.Restrict,
|
||||
=> {
|
||||
_ = try astrl.expr(args[0], block, ResultInfo.type_only);
|
||||
return false;
|
||||
|
||||
@ -90,6 +90,7 @@ pub const Tag = enum {
|
||||
size_of,
|
||||
splat,
|
||||
reduce,
|
||||
Restrict,
|
||||
src,
|
||||
sqrt,
|
||||
sin,
|
||||
@ -795,6 +796,13 @@ pub const list = list: {
|
||||
.param_count = 2,
|
||||
},
|
||||
},
|
||||
.{
|
||||
"@Restrict",
|
||||
.{
|
||||
.tag = .Restrict,
|
||||
.param_count = 1,
|
||||
},
|
||||
},
|
||||
.{
|
||||
"@src",
|
||||
.{
|
||||
|
||||
@ -1071,6 +1071,12 @@ pub const Inst = struct {
|
||||
/// Uses the `un_node` field.
|
||||
restore_err_ret_index_fn_entry,
|
||||
|
||||
/// Creates a new restricted function pointer type based on the
|
||||
/// provided function pointer type.
|
||||
///
|
||||
/// Uses the `un_node` field.
|
||||
restrict,
|
||||
|
||||
/// The ZIR instruction tag is one of the `Extended` ones.
|
||||
/// Uses the `extended` union field.
|
||||
extended,
|
||||
@ -1315,6 +1321,7 @@ pub const Inst = struct {
|
||||
.validate_const,
|
||||
.restore_err_ret_index_unconditional,
|
||||
.restore_err_ret_index_fn_entry,
|
||||
.restrict,
|
||||
=> false,
|
||||
|
||||
.@"break",
|
||||
@ -1595,6 +1602,7 @@ pub const Inst = struct {
|
||||
.validate_array_init_ref_ty,
|
||||
.array_init_elem_type,
|
||||
.array_init_elem_ptr,
|
||||
.restrict,
|
||||
=> false,
|
||||
|
||||
.extended => switch (data.extended.opcode) {
|
||||
@ -1711,6 +1719,7 @@ pub const Inst = struct {
|
||||
.merge_error_sets = .pl_node,
|
||||
.mod_rem = .pl_node,
|
||||
.ref = .un_tok,
|
||||
.restrict = .un_node,
|
||||
.ret_node = .un_node,
|
||||
.ret_load = .un_node,
|
||||
.ret_implicit = .un_tok,
|
||||
@ -4755,6 +4764,8 @@ fn findTrackableInner(
|
||||
try zir.findTrackableBody(gpa, contents, defers, body);
|
||||
}
|
||||
},
|
||||
// Restricted function pointer types need tracking, but have no body.
|
||||
.restrict => return contents.other.append(gpa, inst),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -117,6 +117,13 @@ pub const empty: InternPool = .{
|
||||
.free_dep_entries = .empty,
|
||||
};
|
||||
|
||||
pub const RestrictedSetIndex = enum(u32) {
|
||||
/// placeholder while I slowly work my way towards a more complete implementation
|
||||
some = 0,
|
||||
none = std.math.maxInt(u32),
|
||||
_,
|
||||
};
|
||||
|
||||
/// A `TrackedInst.Index` provides a single, unchanging reference to a ZIR instruction across a whole
|
||||
/// compilation. From this index, you can acquire a `TrackedInst`, which containss a reference to both
|
||||
/// the file which the instruction lives in, and the instruction index itself, which is updated on
|
||||
@ -2079,6 +2086,7 @@ pub const Key = union(enum) {
|
||||
sentinel: Index = .none,
|
||||
flags: Flags = .{},
|
||||
packed_offset: PackedOffset = .{ .bit_offset = 0, .host_size = 0 },
|
||||
restricted_set: RestrictedSetIndex = .none,
|
||||
|
||||
pub const VectorIndex = enum(u16) {
|
||||
none = std.math.maxInt(u16),
|
||||
@ -5389,6 +5397,9 @@ pub const Tag = enum(u8) {
|
||||
type_vector,
|
||||
/// A fully explicitly specified pointer type.
|
||||
type_pointer,
|
||||
/// A pointer type created by using the `@Restrict` builtin.
|
||||
/// data is `Index` of underlying, non-restrict pointer type.
|
||||
type_pointer_restricted,
|
||||
/// A slice type.
|
||||
/// data is Index of underlying pointer type.
|
||||
type_slice,
|
||||
@ -5666,6 +5677,7 @@ pub const Tag = enum(u8) {
|
||||
.type_array_small = .{ .summary = .@"[{.payload.len%value}]{.payload.child%summary}", .payload = Vector },
|
||||
.type_vector = .{ .summary = .@"@Vector({.payload.len%value}, {.payload.child%summary})", .payload = Vector },
|
||||
.type_pointer = .{ .summary = .@"*... {.payload.child%summary}", .payload = TypePointer },
|
||||
.type_pointer_restricted = .{ .summary = .@"@Restrict(*... {.payload.child%summary})", .data = Index },
|
||||
.type_slice = .{ .summary = .@"[]... {.data.unwrapped.payload.child%summary}", .data = Index },
|
||||
.type_optional = .{ .summary = .@"?{.data%summary}", .data = Index },
|
||||
.type_anyframe = .{ .summary = .@"anyframe->{.data%summary}", .data = Index },
|
||||
@ -6970,6 +6982,16 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
|
||||
|
||||
.type_pointer => .{ .ptr_type = extraData(unwrapped_index.getExtra(ip), Tag.TypePointer, data) },
|
||||
|
||||
.type_pointer_restricted => {
|
||||
const child_ptr_index: Index = @enumFromInt(data);
|
||||
const child_ptr_unwrapped = child_ptr_index.unwrap(ip);
|
||||
const child_ptr_item = child_ptr_unwrapped.getItem(ip);
|
||||
assert(child_ptr_item.tag == .type_pointer);
|
||||
var ptr_info = extraData(child_ptr_unwrapped.getExtra(ip), Tag.TypePointer, child_ptr_item.data);
|
||||
ptr_info.restricted_set = .some;
|
||||
return .{ .ptr_type = ptr_info };
|
||||
},
|
||||
|
||||
.type_slice => {
|
||||
const many_ptr_index: Index = @enumFromInt(data);
|
||||
const many_ptr_unwrapped = many_ptr_index.unwrap(ip);
|
||||
@ -10388,6 +10410,7 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 {
|
||||
TrackedInst.Index,
|
||||
TrackedInst.Index.Optional,
|
||||
ComptimeAllocIndex,
|
||||
RestrictedSetIndex,
|
||||
=> @intFromEnum(@field(item, field.name)),
|
||||
|
||||
u32,
|
||||
@ -10451,6 +10474,7 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat
|
||||
TrackedInst.Index,
|
||||
TrackedInst.Index.Optional,
|
||||
ComptimeAllocIndex,
|
||||
RestrictedSetIndex,
|
||||
=> @enumFromInt(extra_item),
|
||||
|
||||
u32,
|
||||
@ -11092,6 +11116,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
|
||||
.type_array_big => @sizeOf(Array),
|
||||
.type_vector => @sizeOf(Vector),
|
||||
.type_pointer => @sizeOf(Tag.TypePointer),
|
||||
.type_pointer_restricted => 0,
|
||||
.type_slice => 0,
|
||||
.type_optional => 0,
|
||||
.type_anyframe => 0,
|
||||
@ -11319,6 +11344,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
|
||||
.type_array_big,
|
||||
.type_vector,
|
||||
.type_pointer,
|
||||
.type_pointer_restricted,
|
||||
.type_optional,
|
||||
.type_anyframe,
|
||||
.type_error_union,
|
||||
@ -11902,6 +11928,19 @@ pub fn getOrPutTrailingString(
|
||||
return value;
|
||||
}
|
||||
|
||||
pub fn restrictedFunctionPointerType(
|
||||
ip: *InternPool,
|
||||
gpa: Allocator,
|
||||
tid: Zcu.PerThread.Id,
|
||||
fn_ty: Index,
|
||||
) Allocator.Error!Index {
|
||||
_ = ip;
|
||||
_ = gpa;
|
||||
_ = tid;
|
||||
_ = fn_ty;
|
||||
@panic("TODO");
|
||||
}
|
||||
|
||||
pub fn getString(ip: *InternPool, key: []const u8) OptionalNullTerminatedString {
|
||||
const full_hash = Hash.hash(0, key);
|
||||
const hash: u32 = @truncate(full_hash >> 32);
|
||||
@ -12055,6 +12094,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
|
||||
.type_array_small,
|
||||
.type_vector,
|
||||
.type_pointer,
|
||||
.type_pointer_restricted,
|
||||
.type_slice,
|
||||
.type_optional,
|
||||
.type_anyframe,
|
||||
@ -12411,6 +12451,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
|
||||
.type_vector => .vector,
|
||||
|
||||
.type_pointer,
|
||||
.type_pointer_restricted,
|
||||
.type_slice,
|
||||
=> .pointer,
|
||||
|
||||
|
||||
22
src/Sema.zig
22
src/Sema.zig
@ -1305,6 +1305,7 @@ fn analyzeBodyInner(
|
||||
.validate_array_init_ref_ty => try sema.zirValidateArrayInitRefTy(block, inst),
|
||||
.opt_eu_base_ptr_init => try sema.zirOptEuBasePtrInit(block, inst),
|
||||
.coerce_ptr_elem_ty => try sema.zirCoercePtrElemTy(block, inst),
|
||||
.restrict => try sema.zirRestrict(block, inst),
|
||||
|
||||
.clz => try sema.zirBitCount(block, inst, .clz, Value.clz),
|
||||
.ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz),
|
||||
@ -4681,6 +4682,26 @@ fn zirCoercePtrElemTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
|
||||
}
|
||||
}
|
||||
|
||||
fn zirRestrict(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
|
||||
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
|
||||
const ty_src = block.builtinCallArgSrc(inst_data.src_node, 0);
|
||||
const ptr_ty = try sema.resolveType(block, ty_src, inst_data.operand);
|
||||
|
||||
try sema.checkPtrOperand(block, ty_src, ptr_ty);
|
||||
|
||||
const ptr_info = ptr_ty.ptrInfo(zcu);
|
||||
const pointee_ty: Type = .fromInterned(ptr_info.child);
|
||||
if (ptr_info.flags.size != .one or pointee_ty.zigTypeTag(zcu) == .@"fn") {
|
||||
return sema.fail(block, ty_src, "expected function pointer type; found {f}", .{ptr_ty.fmt(pt)});
|
||||
}
|
||||
|
||||
const new_ty = try pt.restrictedFunctionPointerType(pointee_ty);
|
||||
return .fromType(new_ty);
|
||||
}
|
||||
|
||||
fn zirTryOperandTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) CompileError!Air.Inst.Ref {
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
@ -36062,6 +36083,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
|
||||
.type_int_signed, // i0 handled above
|
||||
.type_int_unsigned, // u0 handled above
|
||||
.type_pointer,
|
||||
.type_pointer_restricted,
|
||||
.type_slice,
|
||||
.type_anyframe,
|
||||
.type_error_union,
|
||||
|
||||
@ -3420,6 +3420,8 @@ pub fn internUnion(pt: Zcu.PerThread, un: InternPool.Key.Union) Allocator.Error!
|
||||
/// this because it requires potentially pushing to the job queue.
|
||||
pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!Value {
|
||||
const ip = &pt.zcu.intern_pool;
|
||||
// TODO: avoid indexToKey
|
||||
// TODO: check if dest is restricted function pointer type
|
||||
switch (ip.indexToKey(val.toIntern())) {
|
||||
.@"extern" => |e| {
|
||||
const coerced = try pt.getExtern(.{
|
||||
@ -3544,6 +3546,10 @@ pub fn funcType(pt: Zcu.PerThread, key: InternPool.GetFuncTypeKey) Allocator.Err
|
||||
return Type.fromInterned(try pt.zcu.intern_pool.getFuncType(pt.zcu.gpa, pt.tid, key));
|
||||
}
|
||||
|
||||
pub fn restrictedFunctionPointerType(pt: Zcu.PerThread, fn_ty: Type) Allocator.Error!Type {
|
||||
return .fromInterned(try pt.zcu.intern_pool.restrictedFunctionPointerType(pt.zcu.gpa, pt.tid, fn_ty.toIntern()));
|
||||
}
|
||||
|
||||
/// Use this for `anyframe->T` only.
|
||||
/// For `anyframe`, use the `InternPool.Index.anyframe` tag directly.
|
||||
pub fn anyframeType(pt: Zcu.PerThread, payload_ty: Type) Allocator.Error!Type {
|
||||
|
||||
@ -266,6 +266,7 @@ const Writer = struct {
|
||||
.opt_eu_base_ptr_init,
|
||||
.restore_err_ret_index_unconditional,
|
||||
.restore_err_ret_index_fn_entry,
|
||||
.restrict,
|
||||
=> try self.writeUnNode(stream, inst),
|
||||
|
||||
.ref,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user