authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-31 20:40:15-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-31 20:40:15-07:00
logf250802ce794589f77367113335216c1993f7412
tree80f260bc0447d67924caa4162344ad21bf71ea2a
parentfc23fe90ce1f3d28841c5a5a93a8bdf7edaefc54

compiler: introduce `@Restrict` builtin

conservative, incomplete change

8 files changed, 96 insertions(+), 0 deletions(-)

lib/std/zig/AstGen.zig+6
......@@ -2876,6 +2876,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
28762876 .validate_array_init_ref_ty,
28772877 .array_init_elem_type,
28782878 .array_init_elem_ptr,
2879 .restrict,
28792880 => break :b false,
28802881
28812882 .extended => switch (gz.astgen.instructions.items(.data)[@intFromEnum(inst)].extended.opcode) {
......@@ -9547,6 +9548,11 @@ fn builtinCall(
95479548 });
95489549 return rvalue(gz, ri, result, node);
95499550 },
9551 .Restrict => {
9552 const operand = try typeExpr(gz, scope, params[0]);
9553 const result = try gz.addUnNode(.restrict, operand, node);
9554 return rvalue(gz, ri, result, node);
9555 },
95509556
95519557 .add_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .add_with_overflow),
95529558 .sub_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .sub_with_overflow),
lib/std/zig/AstRlAnnotate.zig+1
......@@ -923,6 +923,7 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
923923 .work_item_id,
924924 .work_group_size,
925925 .work_group_id,
926 .Restrict,
926927 => {
927928 _ = try astrl.expr(args[0], block, ResultInfo.type_only);
928929 return false;
lib/std/zig/BuiltinFn.zig+8
......@@ -90,6 +90,7 @@ pub const Tag = enum {
9090 size_of,
9191 splat,
9292 reduce,
93 Restrict,
9394 src,
9495 sqrt,
9596 sin,
......@@ -795,6 +796,13 @@ pub const list = list: {
795796 .param_count = 2,
796797 },
797798 },
799 .{
800 "@Restrict",
801 .{
802 .tag = .Restrict,
803 .param_count = 1,
804 },
805 },
798806 .{
799807 "@src",
800808 .{
lib/std/zig/Zir.zig+11
......@@ -1071,6 +1071,12 @@ pub const Inst = struct {
10711071 /// Uses the `un_node` field.
10721072 restore_err_ret_index_fn_entry,
10731073
1074 /// Creates a new restricted function pointer type based on the
1075 /// provided function pointer type.
1076 ///
1077 /// Uses the `un_node` field.
1078 restrict,
1079
10741080 /// The ZIR instruction tag is one of the `Extended` ones.
10751081 /// Uses the `extended` union field.
10761082 extended,
......@@ -1315,6 +1321,7 @@ pub const Inst = struct {
13151321 .validate_const,
13161322 .restore_err_ret_index_unconditional,
13171323 .restore_err_ret_index_fn_entry,
1324 .restrict,
13181325 => false,
13191326
13201327 .@"break",
......@@ -1595,6 +1602,7 @@ pub const Inst = struct {
15951602 .validate_array_init_ref_ty,
15961603 .array_init_elem_type,
15971604 .array_init_elem_ptr,
1605 .restrict,
15981606 => false,
15991607
16001608 .extended => switch (data.extended.opcode) {
......@@ -1711,6 +1719,7 @@ pub const Inst = struct {
17111719 .merge_error_sets = .pl_node,
17121720 .mod_rem = .pl_node,
17131721 .ref = .un_tok,
1722 .restrict = .un_node,
17141723 .ret_node = .un_node,
17151724 .ret_load = .un_node,
17161725 .ret_implicit = .un_tok,
......@@ -4755,6 +4764,8 @@ fn findTrackableInner(
47554764 try zir.findTrackableBody(gpa, contents, defers, body);
47564765 }
47574766 },
4767 // Restricted function pointer types need tracking, but have no body.
4768 .restrict => return contents.other.append(gpa, inst),
47584769 }
47594770}
47604771
src/InternPool.zig+41
......@@ -117,6 +117,13 @@ pub const empty: InternPool = .{
117117 .free_dep_entries = .empty,
118118};
119119
120pub const RestrictedSetIndex = enum(u32) {
121 /// placeholder while I slowly work my way towards a more complete implementation
122 some = 0,
123 none = std.math.maxInt(u32),
124 _,
125};
126
120127/// A `TrackedInst.Index` provides a single, unchanging reference to a ZIR instruction across a whole
121128/// compilation. From this index, you can acquire a `TrackedInst`, which containss a reference to both
122129/// 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) {
20792086 sentinel: Index = .none,
20802087 flags: Flags = .{},
20812088 packed_offset: PackedOffset = .{ .bit_offset = 0, .host_size = 0 },
2089 restricted_set: RestrictedSetIndex = .none,
20822090
20832091 pub const VectorIndex = enum(u16) {
20842092 none = std.math.maxInt(u16),
......@@ -5389,6 +5397,9 @@ pub const Tag = enum(u8) {
53895397 type_vector,
53905398 /// A fully explicitly specified pointer type.
53915399 type_pointer,
5400 /// A pointer type created by using the `@Restrict` builtin.
5401 /// data is `Index` of underlying, non-restrict pointer type.
5402 type_pointer_restricted,
53925403 /// A slice type.
53935404 /// data is Index of underlying pointer type.
53945405 type_slice,
......@@ -5666,6 +5677,7 @@ pub const Tag = enum(u8) {
56665677 .type_array_small = .{ .summary = .@"[{.payload.len%value}]{.payload.child%summary}", .payload = Vector },
56675678 .type_vector = .{ .summary = .@"@Vector({.payload.len%value}, {.payload.child%summary})", .payload = Vector },
56685679 .type_pointer = .{ .summary = .@"*... {.payload.child%summary}", .payload = TypePointer },
5680 .type_pointer_restricted = .{ .summary = .@"@Restrict(*... {.payload.child%summary})", .data = Index },
56695681 .type_slice = .{ .summary = .@"[]... {.data.unwrapped.payload.child%summary}", .data = Index },
56705682 .type_optional = .{ .summary = .@"?{.data%summary}", .data = Index },
56715683 .type_anyframe = .{ .summary = .@"anyframe->{.data%summary}", .data = Index },
......@@ -6970,6 +6982,16 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
69706982
69716983 .type_pointer => .{ .ptr_type = extraData(unwrapped_index.getExtra(ip), Tag.TypePointer, data) },
69726984
6985 .type_pointer_restricted => {
6986 const child_ptr_index: Index = @enumFromInt(data);
6987 const child_ptr_unwrapped = child_ptr_index.unwrap(ip);
6988 const child_ptr_item = child_ptr_unwrapped.getItem(ip);
6989 assert(child_ptr_item.tag == .type_pointer);
6990 var ptr_info = extraData(child_ptr_unwrapped.getExtra(ip), Tag.TypePointer, child_ptr_item.data);
6991 ptr_info.restricted_set = .some;
6992 return .{ .ptr_type = ptr_info };
6993 },
6994
69736995 .type_slice => {
69746996 const many_ptr_index: Index = @enumFromInt(data);
69756997 const many_ptr_unwrapped = many_ptr_index.unwrap(ip);
......@@ -10388,6 +10410,7 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 {
1038810410 TrackedInst.Index,
1038910411 TrackedInst.Index.Optional,
1039010412 ComptimeAllocIndex,
10413 RestrictedSetIndex,
1039110414 => @intFromEnum(@field(item, field.name)),
1039210415
1039310416 u32,
......@@ -10451,6 +10474,7 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat
1045110474 TrackedInst.Index,
1045210475 TrackedInst.Index.Optional,
1045310476 ComptimeAllocIndex,
10477 RestrictedSetIndex,
1045410478 => @enumFromInt(extra_item),
1045510479
1045610480 u32,
......@@ -11092,6 +11116,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
1109211116 .type_array_big => @sizeOf(Array),
1109311117 .type_vector => @sizeOf(Vector),
1109411118 .type_pointer => @sizeOf(Tag.TypePointer),
11119 .type_pointer_restricted => 0,
1109511120 .type_slice => 0,
1109611121 .type_optional => 0,
1109711122 .type_anyframe => 0,
......@@ -11319,6 +11344,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
1131911344 .type_array_big,
1132011345 .type_vector,
1132111346 .type_pointer,
11347 .type_pointer_restricted,
1132211348 .type_optional,
1132311349 .type_anyframe,
1132411350 .type_error_union,
......@@ -11902,6 +11928,19 @@ pub fn getOrPutTrailingString(
1190211928 return value;
1190311929}
1190411930
11931pub fn restrictedFunctionPointerType(
11932 ip: *InternPool,
11933 gpa: Allocator,
11934 tid: Zcu.PerThread.Id,
11935 fn_ty: Index,
11936) Allocator.Error!Index {
11937 _ = ip;
11938 _ = gpa;
11939 _ = tid;
11940 _ = fn_ty;
11941 @panic("TODO");
11942}
11943
1190511944pub fn getString(ip: *InternPool, key: []const u8) OptionalNullTerminatedString {
1190611945 const full_hash = Hash.hash(0, key);
1190711946 const hash: u32 = @truncate(full_hash >> 32);
......@@ -12055,6 +12094,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
1205512094 .type_array_small,
1205612095 .type_vector,
1205712096 .type_pointer,
12097 .type_pointer_restricted,
1205812098 .type_slice,
1205912099 .type_optional,
1206012100 .type_anyframe,
......@@ -12411,6 +12451,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
1241112451 .type_vector => .vector,
1241212452
1241312453 .type_pointer,
12454 .type_pointer_restricted,
1241412455 .type_slice,
1241512456 => .pointer,
1241612457
src/Sema.zig+22
......@@ -1305,6 +1305,7 @@ fn analyzeBodyInner(
13051305 .validate_array_init_ref_ty => try sema.zirValidateArrayInitRefTy(block, inst),
13061306 .opt_eu_base_ptr_init => try sema.zirOptEuBasePtrInit(block, inst),
13071307 .coerce_ptr_elem_ty => try sema.zirCoercePtrElemTy(block, inst),
1308 .restrict => try sema.zirRestrict(block, inst),
13081309
13091310 .clz => try sema.zirBitCount(block, inst, .clz, Value.clz),
13101311 .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz),
......@@ -4681,6 +4682,26 @@ fn zirCoercePtrElemTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
46814682 }
46824683}
46834684
4685fn zirRestrict(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
4686 const pt = sema.pt;
4687 const zcu = pt.zcu;
4688
4689 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
4690 const ty_src = block.builtinCallArgSrc(inst_data.src_node, 0);
4691 const ptr_ty = try sema.resolveType(block, ty_src, inst_data.operand);
4692
4693 try sema.checkPtrOperand(block, ty_src, ptr_ty);
4694
4695 const ptr_info = ptr_ty.ptrInfo(zcu);
4696 const pointee_ty: Type = .fromInterned(ptr_info.child);
4697 if (ptr_info.flags.size != .one or pointee_ty.zigTypeTag(zcu) == .@"fn") {
4698 return sema.fail(block, ty_src, "expected function pointer type; found {f}", .{ptr_ty.fmt(pt)});
4699 }
4700
4701 const new_ty = try pt.restrictedFunctionPointerType(pointee_ty);
4702 return .fromType(new_ty);
4703}
4704
46844705fn zirTryOperandTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) CompileError!Air.Inst.Ref {
46854706 const pt = sema.pt;
46864707 const zcu = pt.zcu;
......@@ -36062,6 +36083,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3606236083 .type_int_signed, // i0 handled above
3606336084 .type_int_unsigned, // u0 handled above
3606436085 .type_pointer,
36086 .type_pointer_restricted,
3606536087 .type_slice,
3606636088 .type_anyframe,
3606736089 .type_error_union,
src/Zcu/PerThread.zig+6
......@@ -3420,6 +3420,8 @@ pub fn internUnion(pt: Zcu.PerThread, un: InternPool.Key.Union) Allocator.Error!
34203420/// this because it requires potentially pushing to the job queue.
34213421pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!Value {
34223422 const ip = &pt.zcu.intern_pool;
3423 // TODO: avoid indexToKey
3424 // TODO: check if dest is restricted function pointer type
34233425 switch (ip.indexToKey(val.toIntern())) {
34243426 .@"extern" => |e| {
34253427 const coerced = try pt.getExtern(.{
......@@ -3544,6 +3546,10 @@ pub fn funcType(pt: Zcu.PerThread, key: InternPool.GetFuncTypeKey) Allocator.Err
35443546 return Type.fromInterned(try pt.zcu.intern_pool.getFuncType(pt.zcu.gpa, pt.tid, key));
35453547}
35463548
3549pub fn restrictedFunctionPointerType(pt: Zcu.PerThread, fn_ty: Type) Allocator.Error!Type {
3550 return .fromInterned(try pt.zcu.intern_pool.restrictedFunctionPointerType(pt.zcu.gpa, pt.tid, fn_ty.toIntern()));
3551}
3552
35473553/// Use this for `anyframe->T` only.
35483554/// For `anyframe`, use the `InternPool.Index.anyframe` tag directly.
35493555pub fn anyframeType(pt: Zcu.PerThread, payload_ty: Type) Allocator.Error!Type {
src/print_zir.zig+1
......@@ -266,6 +266,7 @@ const Writer = struct {
266266 .opt_eu_base_ptr_init,
267267 .restore_err_ret_index_unconditional,
268268 .restore_err_ret_index_fn_entry,
269 .restrict,
269270 => try self.writeUnNode(stream, inst),
270271
271272 .ref,