mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
compiler: introduce @Restrict builtin
conservative, incomplete change
This commit is contained in:
parent
fc23fe90ce
commit
f250802ce7
8 changed files with 96 additions and 0 deletions
|
|
@ -2876,6 +2876,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
|
||||||
.validate_array_init_ref_ty,
|
.validate_array_init_ref_ty,
|
||||||
.array_init_elem_type,
|
.array_init_elem_type,
|
||||||
.array_init_elem_ptr,
|
.array_init_elem_ptr,
|
||||||
|
.restrict,
|
||||||
=> break :b false,
|
=> break :b false,
|
||||||
|
|
||||||
.extended => switch (gz.astgen.instructions.items(.data)[@intFromEnum(inst)].extended.opcode) {
|
.extended => switch (gz.astgen.instructions.items(.data)[@intFromEnum(inst)].extended.opcode) {
|
||||||
|
|
@ -9547,6 +9548,11 @@ fn builtinCall(
|
||||||
});
|
});
|
||||||
return rvalue(gz, ri, result, node);
|
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),
|
.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),
|
.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_item_id,
|
||||||
.work_group_size,
|
.work_group_size,
|
||||||
.work_group_id,
|
.work_group_id,
|
||||||
|
.Restrict,
|
||||||
=> {
|
=> {
|
||||||
_ = try astrl.expr(args[0], block, ResultInfo.type_only);
|
_ = try astrl.expr(args[0], block, ResultInfo.type_only);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ pub const Tag = enum {
|
||||||
size_of,
|
size_of,
|
||||||
splat,
|
splat,
|
||||||
reduce,
|
reduce,
|
||||||
|
Restrict,
|
||||||
src,
|
src,
|
||||||
sqrt,
|
sqrt,
|
||||||
sin,
|
sin,
|
||||||
|
|
@ -795,6 +796,13 @@ pub const list = list: {
|
||||||
.param_count = 2,
|
.param_count = 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
.{
|
||||||
|
"@Restrict",
|
||||||
|
.{
|
||||||
|
.tag = .Restrict,
|
||||||
|
.param_count = 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
.{
|
.{
|
||||||
"@src",
|
"@src",
|
||||||
.{
|
.{
|
||||||
|
|
|
||||||
|
|
@ -1071,6 +1071,12 @@ pub const Inst = struct {
|
||||||
/// Uses the `un_node` field.
|
/// Uses the `un_node` field.
|
||||||
restore_err_ret_index_fn_entry,
|
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.
|
/// The ZIR instruction tag is one of the `Extended` ones.
|
||||||
/// Uses the `extended` union field.
|
/// Uses the `extended` union field.
|
||||||
extended,
|
extended,
|
||||||
|
|
@ -1315,6 +1321,7 @@ pub const Inst = struct {
|
||||||
.validate_const,
|
.validate_const,
|
||||||
.restore_err_ret_index_unconditional,
|
.restore_err_ret_index_unconditional,
|
||||||
.restore_err_ret_index_fn_entry,
|
.restore_err_ret_index_fn_entry,
|
||||||
|
.restrict,
|
||||||
=> false,
|
=> false,
|
||||||
|
|
||||||
.@"break",
|
.@"break",
|
||||||
|
|
@ -1595,6 +1602,7 @@ pub const Inst = struct {
|
||||||
.validate_array_init_ref_ty,
|
.validate_array_init_ref_ty,
|
||||||
.array_init_elem_type,
|
.array_init_elem_type,
|
||||||
.array_init_elem_ptr,
|
.array_init_elem_ptr,
|
||||||
|
.restrict,
|
||||||
=> false,
|
=> false,
|
||||||
|
|
||||||
.extended => switch (data.extended.opcode) {
|
.extended => switch (data.extended.opcode) {
|
||||||
|
|
@ -1711,6 +1719,7 @@ pub const Inst = struct {
|
||||||
.merge_error_sets = .pl_node,
|
.merge_error_sets = .pl_node,
|
||||||
.mod_rem = .pl_node,
|
.mod_rem = .pl_node,
|
||||||
.ref = .un_tok,
|
.ref = .un_tok,
|
||||||
|
.restrict = .un_node,
|
||||||
.ret_node = .un_node,
|
.ret_node = .un_node,
|
||||||
.ret_load = .un_node,
|
.ret_load = .un_node,
|
||||||
.ret_implicit = .un_tok,
|
.ret_implicit = .un_tok,
|
||||||
|
|
@ -4755,6 +4764,8 @@ fn findTrackableInner(
|
||||||
try zir.findTrackableBody(gpa, contents, defers, body);
|
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,
|
.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
|
/// 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
|
/// 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
|
/// 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,
|
sentinel: Index = .none,
|
||||||
flags: Flags = .{},
|
flags: Flags = .{},
|
||||||
packed_offset: PackedOffset = .{ .bit_offset = 0, .host_size = 0 },
|
packed_offset: PackedOffset = .{ .bit_offset = 0, .host_size = 0 },
|
||||||
|
restricted_set: RestrictedSetIndex = .none,
|
||||||
|
|
||||||
pub const VectorIndex = enum(u16) {
|
pub const VectorIndex = enum(u16) {
|
||||||
none = std.math.maxInt(u16),
|
none = std.math.maxInt(u16),
|
||||||
|
|
@ -5389,6 +5397,9 @@ pub const Tag = enum(u8) {
|
||||||
type_vector,
|
type_vector,
|
||||||
/// A fully explicitly specified pointer type.
|
/// A fully explicitly specified pointer type.
|
||||||
type_pointer,
|
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.
|
/// A slice type.
|
||||||
/// data is Index of underlying pointer type.
|
/// data is Index of underlying pointer type.
|
||||||
type_slice,
|
type_slice,
|
||||||
|
|
@ -5666,6 +5677,7 @@ pub const Tag = enum(u8) {
|
||||||
.type_array_small = .{ .summary = .@"[{.payload.len%value}]{.payload.child%summary}", .payload = Vector },
|
.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_vector = .{ .summary = .@"@Vector({.payload.len%value}, {.payload.child%summary})", .payload = Vector },
|
||||||
.type_pointer = .{ .summary = .@"*... {.payload.child%summary}", .payload = TypePointer },
|
.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_slice = .{ .summary = .@"[]... {.data.unwrapped.payload.child%summary}", .data = Index },
|
||||||
.type_optional = .{ .summary = .@"?{.data%summary}", .data = Index },
|
.type_optional = .{ .summary = .@"?{.data%summary}", .data = Index },
|
||||||
.type_anyframe = .{ .summary = .@"anyframe->{.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 => .{ .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 => {
|
.type_slice => {
|
||||||
const many_ptr_index: Index = @enumFromInt(data);
|
const many_ptr_index: Index = @enumFromInt(data);
|
||||||
const many_ptr_unwrapped = many_ptr_index.unwrap(ip);
|
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,
|
||||||
TrackedInst.Index.Optional,
|
TrackedInst.Index.Optional,
|
||||||
ComptimeAllocIndex,
|
ComptimeAllocIndex,
|
||||||
|
RestrictedSetIndex,
|
||||||
=> @intFromEnum(@field(item, field.name)),
|
=> @intFromEnum(@field(item, field.name)),
|
||||||
|
|
||||||
u32,
|
u32,
|
||||||
|
|
@ -10451,6 +10474,7 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat
|
||||||
TrackedInst.Index,
|
TrackedInst.Index,
|
||||||
TrackedInst.Index.Optional,
|
TrackedInst.Index.Optional,
|
||||||
ComptimeAllocIndex,
|
ComptimeAllocIndex,
|
||||||
|
RestrictedSetIndex,
|
||||||
=> @enumFromInt(extra_item),
|
=> @enumFromInt(extra_item),
|
||||||
|
|
||||||
u32,
|
u32,
|
||||||
|
|
@ -11092,6 +11116,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
|
||||||
.type_array_big => @sizeOf(Array),
|
.type_array_big => @sizeOf(Array),
|
||||||
.type_vector => @sizeOf(Vector),
|
.type_vector => @sizeOf(Vector),
|
||||||
.type_pointer => @sizeOf(Tag.TypePointer),
|
.type_pointer => @sizeOf(Tag.TypePointer),
|
||||||
|
.type_pointer_restricted => 0,
|
||||||
.type_slice => 0,
|
.type_slice => 0,
|
||||||
.type_optional => 0,
|
.type_optional => 0,
|
||||||
.type_anyframe => 0,
|
.type_anyframe => 0,
|
||||||
|
|
@ -11319,6 +11344,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
|
||||||
.type_array_big,
|
.type_array_big,
|
||||||
.type_vector,
|
.type_vector,
|
||||||
.type_pointer,
|
.type_pointer,
|
||||||
|
.type_pointer_restricted,
|
||||||
.type_optional,
|
.type_optional,
|
||||||
.type_anyframe,
|
.type_anyframe,
|
||||||
.type_error_union,
|
.type_error_union,
|
||||||
|
|
@ -11902,6 +11928,19 @@ pub fn getOrPutTrailingString(
|
||||||
return value;
|
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 {
|
pub fn getString(ip: *InternPool, key: []const u8) OptionalNullTerminatedString {
|
||||||
const full_hash = Hash.hash(0, key);
|
const full_hash = Hash.hash(0, key);
|
||||||
const hash: u32 = @truncate(full_hash >> 32);
|
const hash: u32 = @truncate(full_hash >> 32);
|
||||||
|
|
@ -12055,6 +12094,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
|
||||||
.type_array_small,
|
.type_array_small,
|
||||||
.type_vector,
|
.type_vector,
|
||||||
.type_pointer,
|
.type_pointer,
|
||||||
|
.type_pointer_restricted,
|
||||||
.type_slice,
|
.type_slice,
|
||||||
.type_optional,
|
.type_optional,
|
||||||
.type_anyframe,
|
.type_anyframe,
|
||||||
|
|
@ -12411,6 +12451,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
|
||||||
.type_vector => .vector,
|
.type_vector => .vector,
|
||||||
|
|
||||||
.type_pointer,
|
.type_pointer,
|
||||||
|
.type_pointer_restricted,
|
||||||
.type_slice,
|
.type_slice,
|
||||||
=> .pointer,
|
=> .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),
|
.validate_array_init_ref_ty => try sema.zirValidateArrayInitRefTy(block, inst),
|
||||||
.opt_eu_base_ptr_init => try sema.zirOptEuBasePtrInit(block, inst),
|
.opt_eu_base_ptr_init => try sema.zirOptEuBasePtrInit(block, inst),
|
||||||
.coerce_ptr_elem_ty => try sema.zirCoercePtrElemTy(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),
|
.clz => try sema.zirBitCount(block, inst, .clz, Value.clz),
|
||||||
.ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz),
|
.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 {
|
fn zirTryOperandTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) CompileError!Air.Inst.Ref {
|
||||||
const pt = sema.pt;
|
const pt = sema.pt;
|
||||||
const zcu = pt.zcu;
|
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_signed, // i0 handled above
|
||||||
.type_int_unsigned, // u0 handled above
|
.type_int_unsigned, // u0 handled above
|
||||||
.type_pointer,
|
.type_pointer,
|
||||||
|
.type_pointer_restricted,
|
||||||
.type_slice,
|
.type_slice,
|
||||||
.type_anyframe,
|
.type_anyframe,
|
||||||
.type_error_union,
|
.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.
|
/// this because it requires potentially pushing to the job queue.
|
||||||
pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!Value {
|
pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!Value {
|
||||||
const ip = &pt.zcu.intern_pool;
|
const ip = &pt.zcu.intern_pool;
|
||||||
|
// TODO: avoid indexToKey
|
||||||
|
// TODO: check if dest is restricted function pointer type
|
||||||
switch (ip.indexToKey(val.toIntern())) {
|
switch (ip.indexToKey(val.toIntern())) {
|
||||||
.@"extern" => |e| {
|
.@"extern" => |e| {
|
||||||
const coerced = try pt.getExtern(.{
|
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));
|
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.
|
/// Use this for `anyframe->T` only.
|
||||||
/// For `anyframe`, use the `InternPool.Index.anyframe` tag directly.
|
/// For `anyframe`, use the `InternPool.Index.anyframe` tag directly.
|
||||||
pub fn anyframeType(pt: Zcu.PerThread, payload_ty: Type) Allocator.Error!Type {
|
pub fn anyframeType(pt: Zcu.PerThread, payload_ty: Type) Allocator.Error!Type {
|
||||||
|
|
|
||||||
|
|
@ -266,6 +266,7 @@ const Writer = struct {
|
||||||
.opt_eu_base_ptr_init,
|
.opt_eu_base_ptr_init,
|
||||||
.restore_err_ret_index_unconditional,
|
.restore_err_ret_index_unconditional,
|
||||||
.restore_err_ret_index_fn_entry,
|
.restore_err_ret_index_fn_entry,
|
||||||
|
.restrict,
|
||||||
=> try self.writeUnNode(stream, inst),
|
=> try self.writeUnNode(stream, inst),
|
||||||
|
|
||||||
.ref,
|
.ref,
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue