authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-01 22:04:18-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-08-01 22:04:18-07:00
logdae4c18aa7999a866b6b145ed3c88cb6c06852be
tree6aa41102b19c8e0af04bf1dd8af5158c4cc8b3a5
parentd5f173d28f2991e05dad399ed4d688297e0a5ca7

stage2: ZIR encodes comptime parameters

`func_extended` ZIR instructions now have a one of the unused flags used as a `has_comptime_bits` boolean. When set, it means 1 or more parameters are `comptime`. In this case, there is a u32 per every 32 parameters (usually just 1 u32) with each bit indicating whether the corresponding parameter is `comptime`. Sema uses this information to correctly mark generic functions as generic. There is now a TODO compile error in place in case a generic function call happens. A future commit will do the generic function call implementation.

4 files changed, 132 insertions(+), 6 deletions(-)

src/AstGen.zig+65-1
......@@ -1064,11 +1064,28 @@ fn fnProtoExpr(
10641064 const param_types = try gpa.alloc(Zir.Inst.Ref, param_count);
10651065 defer gpa.free(param_types);
10661066
1067 const bits_per_param = 1;
1068 const params_per_u32 = 32 / bits_per_param;
1069 // We only need this if there are greater than params_per_u32 fields.
1070 var bit_bag = ArrayListUnmanaged(u32){};
1071 defer bit_bag.deinit(gpa);
1072 var cur_bit_bag: u32 = 0;
10671073 var is_var_args = false;
10681074 {
10691075 var param_type_i: usize = 0;
10701076 var it = fn_proto.iterate(tree.*);
10711077 while (it.next()) |param| : (param_type_i += 1) {
1078 if (param_type_i % params_per_u32 == 0 and param_type_i != 0) {
1079 try bit_bag.append(gpa, cur_bit_bag);
1080 cur_bit_bag = 0;
1081 }
1082 const is_comptime = if (param.comptime_noalias) |token|
1083 token_tags[token] == .keyword_comptime
1084 else
1085 false;
1086 cur_bit_bag = (cur_bit_bag >> bits_per_param) |
1087 (@as(u32, @boolToInt(is_comptime)) << 31);
1088
10721089 if (param.anytype_ellipsis3) |token| {
10731090 switch (token_tags[token]) {
10741091 .keyword_anytype => {
......@@ -1088,6 +1105,11 @@ fn fnProtoExpr(
10881105 try expr(gz, scope, .{ .ty = .type_type }, param_type_node);
10891106 }
10901107 assert(param_type_i == param_count);
1108
1109 const empty_slot_count = params_per_u32 - (param_type_i % params_per_u32);
1110 if (empty_slot_count < params_per_u32) {
1111 cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_param);
1112 }
10911113 }
10921114
10931115 const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
......@@ -1131,6 +1153,8 @@ fn fnProtoExpr(
11311153 .is_inferred_error = false,
11321154 .is_test = false,
11331155 .is_extern = false,
1156 .cur_bit_bag = cur_bit_bag,
1157 .bit_bag = bit_bag.items,
11341158 });
11351159 return rvalue(gz, rl, result, fn_proto.ast.proto_node);
11361160}
......@@ -2916,11 +2940,28 @@ fn fnDecl(
29162940 const param_types = try gpa.alloc(Zir.Inst.Ref, param_count);
29172941 defer gpa.free(param_types);
29182942
2943 const bits_per_param = 1;
2944 const params_per_u32 = 32 / bits_per_param;
2945 // We only need this if there are greater than params_per_u32 fields.
2946 var bit_bag = ArrayListUnmanaged(u32){};
2947 defer bit_bag.deinit(gpa);
2948 var cur_bit_bag: u32 = 0;
29192949 var is_var_args = false;
29202950 {
29212951 var param_type_i: usize = 0;
29222952 var it = fn_proto.iterate(tree.*);
29232953 while (it.next()) |param| : (param_type_i += 1) {
2954 if (param_type_i % params_per_u32 == 0 and param_type_i != 0) {
2955 try bit_bag.append(gpa, cur_bit_bag);
2956 cur_bit_bag = 0;
2957 }
2958 const is_comptime = if (param.comptime_noalias) |token|
2959 token_tags[token] == .keyword_comptime
2960 else
2961 false;
2962 cur_bit_bag = (cur_bit_bag >> bits_per_param) |
2963 (@as(u32, @boolToInt(is_comptime)) << 31);
2964
29242965 if (param.anytype_ellipsis3) |token| {
29252966 switch (token_tags[token]) {
29262967 .keyword_anytype => {
......@@ -2940,6 +2981,11 @@ fn fnDecl(
29402981 try expr(&decl_gz, &decl_gz.base, .{ .ty = .type_type }, param_type_node);
29412982 }
29422983 assert(param_type_i == param_count);
2984
2985 const empty_slot_count = params_per_u32 - (param_type_i % params_per_u32);
2986 if (empty_slot_count < params_per_u32) {
2987 cur_bit_bag >>= @intCast(u5, empty_slot_count * bits_per_param);
2988 }
29432989 }
29442990
29452991 const lib_name: u32 = if (fn_proto.lib_name) |lib_name_token| blk: {
......@@ -3001,6 +3047,8 @@ fn fnDecl(
30013047 .is_inferred_error = false,
30023048 .is_test = false,
30033049 .is_extern = true,
3050 .cur_bit_bag = cur_bit_bag,
3051 .bit_bag = bit_bag.items,
30043052 });
30053053 } else func: {
30063054 if (is_var_args) {
......@@ -3094,6 +3142,8 @@ fn fnDecl(
30943142 .is_inferred_error = is_inferred_error,
30953143 .is_test = false,
30963144 .is_extern = false,
3145 .cur_bit_bag = cur_bit_bag,
3146 .bit_bag = bit_bag.items,
30973147 });
30983148 };
30993149
......@@ -3439,6 +3489,8 @@ fn testDecl(
34393489 .is_inferred_error = true,
34403490 .is_test = true,
34413491 .is_extern = false,
3492 .cur_bit_bag = 0,
3493 .bit_bag = &.{},
34423494 });
34433495
34443496 _ = try decl_block.addBreak(.break_inline, block_inst, func_inst);
......@@ -9135,6 +9187,8 @@ const GenZir = struct {
91359187 is_inferred_error: bool,
91369188 is_test: bool,
91379189 is_extern: bool,
9190 cur_bit_bag: u32,
9191 bit_bag: []const u32,
91389192 }) !Zir.Inst.Ref {
91399193 assert(args.src_node != 0);
91409194 assert(args.ret_ty != .none);
......@@ -9172,13 +9226,18 @@ const GenZir = struct {
91729226 src_locs = &src_locs_buffer;
91739227 }
91749228
9229 const any_are_comptime = args.cur_bit_bag != 0 or for (args.bit_bag) |x| {
9230 if (x != 0) break true;
9231 } else false;
9232
91759233 if (args.cc != .none or args.lib_name != 0 or
91769234 args.is_var_args or args.is_test or args.align_inst != .none or
9177 args.is_extern)
9235 args.is_extern or any_are_comptime)
91789236 {
91799237 try astgen.extra.ensureUnusedCapacity(
91809238 gpa,
91819239 @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len +
9240 @boolToInt(any_are_comptime) + args.bit_bag.len +
91829241 args.param_types.len + args.body.len + src_locs.len +
91839242 @boolToInt(args.lib_name != 0) +
91849243 @boolToInt(args.align_inst != .none) +
......@@ -9199,6 +9258,10 @@ const GenZir = struct {
91999258 if (args.align_inst != .none) {
92009259 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));
92019260 }
9261 if (any_are_comptime) {
9262 astgen.extra.appendSliceAssumeCapacity(args.bit_bag); // Likely empty.
9263 astgen.extra.appendAssumeCapacity(args.cur_bit_bag);
9264 }
92029265 astgen.appendRefsAssumeCapacity(args.param_types);
92039266 astgen.extra.appendSliceAssumeCapacity(args.body);
92049267 astgen.extra.appendSliceAssumeCapacity(src_locs);
......@@ -9216,6 +9279,7 @@ const GenZir = struct {
92169279 .has_align = args.align_inst != .none,
92179280 .is_test = args.is_test,
92189281 .is_extern = args.is_extern,
9282 .has_comptime_bits = any_are_comptime,
92199283 }),
92209284 .operand = payload_index,
92219285 } },
src/Sema.zig+28-1
......@@ -104,6 +104,9 @@ pub fn analyzeFnBody(
104104 extra_index += @boolToInt(small.has_lib_name);
105105 extra_index += @boolToInt(small.has_cc);
106106 extra_index += @boolToInt(small.has_align);
107 if (small.has_comptime_bits) {
108 extra_index += (extra.data.param_types_len + 31) / 32;
109 }
107110 extra_index += extra.data.param_types_len;
108111 const body = sema.code.extra[extra_index..][0..extra.data.body_len];
109112 break :blk body;
......@@ -2533,6 +2536,9 @@ fn analyzeCall(
25332536
25342537 break :res result;
25352538 } else res: {
2539 if (func_ty.fnIsGeneric()) {
2540 return sema.mod.fail(&block.base, func_src, "TODO implement generic fn call", .{});
2541 }
25362542 try sema.requireRuntimeBlock(block, call_src);
25372543 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
25382544 args.len);
......@@ -3208,6 +3214,7 @@ fn zirFunc(
32083214 false,
32093215 src_locs,
32103216 null,
3217 &.{},
32113218 );
32123219}
32133220
......@@ -3225,6 +3232,7 @@ fn funcCommon(
32253232 is_extern: bool,
32263233 src_locs: Zir.Inst.Func.SrcLocs,
32273234 opt_lib_name: ?[]const u8,
3235 comptime_bits: []const u32,
32283236) CompileError!Air.Inst.Ref {
32293237 const src: LazySrcLoc = .{ .node_offset = src_node_offset };
32303238 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
......@@ -3257,13 +3265,23 @@ fn funcCommon(
32573265 }
32583266 }
32593267
3268 var any_are_comptime = false;
32603269 const param_types = try sema.arena.alloc(Type, zir_param_types.len);
32613270 for (zir_param_types) |param_type, i| {
32623271 // TODO make a compile error from `resolveType` report the source location
32633272 // of the specific parameter. Will need to take a similar strategy as
32643273 // `resolveSwitchItemVal` to avoid resolving the source location unless
32653274 // we actually need to report an error.
3266 param_types[i] = try sema.resolveType(block, src, param_type);
3275 const param_src = src;
3276 param_types[i] = try sema.resolveType(block, param_src, param_type);
3277
3278 any_are_comptime = any_are_comptime or blk: {
3279 if (comptime_bits.len == 0)
3280 break :blk false;
3281 const bag = comptime_bits[i / 32];
3282 const is_comptime = @truncate(u1, bag >> @intCast(u5, i % 32)) != 0;
3283 break :blk is_comptime;
3284 };
32673285 }
32683286
32693287 if (align_val.tag() != .null_value) {
......@@ -3286,6 +3304,7 @@ fn funcCommon(
32863304 .return_type = return_type,
32873305 .cc = cc,
32883306 .is_var_args = var_args,
3307 .is_generic = any_are_comptime,
32893308 });
32903309 };
32913310
......@@ -6526,6 +6545,13 @@ fn zirFuncExtended(
65266545 break :blk align_tv.val;
65276546 } else Value.initTag(.null_value);
65286547
6548 const comptime_bits: []const u32 = if (!small.has_comptime_bits) &.{} else blk: {
6549 const amt = (extra.data.param_types_len + 31) / 32;
6550 const bit_bags = sema.code.extra[extra_index..][0..amt];
6551 extra_index += amt;
6552 break :blk bit_bags;
6553 };
6554
65296555 const param_types = sema.code.refSlice(extra_index, extra.data.param_types_len);
65306556 extra_index += param_types.len;
65316557
......@@ -6554,6 +6580,7 @@ fn zirFuncExtended(
65546580 is_extern,
65556581 src_locs,
65566582 lib_name,
6583 comptime_bits,
65576584 );
65586585}
65596586
src/Zir.zig+24-4
......@@ -2226,9 +2226,13 @@ pub const Inst = struct {
22262226 /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set
22272227 /// 1. cc: Ref, // if has_cc is set
22282228 /// 2. align: Ref, // if has_align is set
2229 /// 3. param_type: Ref // for each param_types_len
2230 /// 4. body: Index // for each body_len
2231 /// 5. src_locs: Func.SrcLocs // if body_len != 0
2229 /// 3. comptime_bits: u32 // for every 32 parameters, if has_comptime_bits is set
2230 /// - sets of 1 bit:
2231 /// 0bX: whether corresponding parameter is comptime
2232 /// 4. param_type: Ref // for each param_types_len
2233 /// - `none` indicates that the param type is `anytype`.
2234 /// 5. body: Index // for each body_len
2235 /// 6. src_locs: Func.SrcLocs // if body_len != 0
22322236 pub const ExtendedFunc = struct {
22332237 src_node: i32,
22342238 return_type: Ref,
......@@ -2243,7 +2247,8 @@ pub const Inst = struct {
22432247 has_align: bool,
22442248 is_test: bool,
22452249 is_extern: bool,
2246 _: u9 = undefined,
2250 has_comptime_bits: bool,
2251 _: u8 = undefined,
22472252 };
22482253 };
22492254
......@@ -4291,6 +4296,7 @@ const Writer = struct {
42914296 body,
42924297 src,
42934298 src_locs,
4299 &.{},
42944300 );
42954301 }
42964302
......@@ -4317,6 +4323,13 @@ const Writer = struct {
43174323 break :blk align_inst;
43184324 };
43194325
4326 const comptime_bits: []const u32 = if (!small.has_comptime_bits) &.{} else blk: {
4327 const amt = (extra.data.param_types_len + 31) / 32;
4328 const bit_bags = self.code.extra[extra_index..][0..amt];
4329 extra_index += amt;
4330 break :blk bit_bags;
4331 };
4332
43204333 const param_types = self.code.refSlice(extra_index, extra.data.param_types_len);
43214334 extra_index += param_types.len;
43224335
......@@ -4339,6 +4352,7 @@ const Writer = struct {
43394352 body,
43404353 src,
43414354 src_locs,
4355 comptime_bits,
43424356 );
43434357 }
43444358
......@@ -4422,10 +4436,16 @@ const Writer = struct {
44224436 body: []const Inst.Index,
44234437 src: LazySrcLoc,
44244438 src_locs: Zir.Inst.Func.SrcLocs,
4439 comptime_bits: []const u32,
44254440 ) !void {
44264441 try stream.writeAll("[");
44274442 for (param_types) |param_type, i| {
44284443 if (i != 0) try stream.writeAll(", ");
4444 if (comptime_bits.len != 0) {
4445 const bag = comptime_bits[i / 32];
4446 const is_comptime = @truncate(u1, bag >> @intCast(u5, i % 32)) != 0;
4447 try self.writeFlag(stream, "comptime ", is_comptime);
4448 }
44294449 try self.writeInstRef(stream, param_type);
44304450 }
44314451 try stream.writeAll("], ");
src/type.zig+15
......@@ -764,6 +764,7 @@ pub const Type = extern union {
764764 .param_types = param_types,
765765 .cc = payload.cc,
766766 .is_var_args = payload.is_var_args,
767 .is_generic = payload.is_generic,
767768 });
768769 },
769770 .pointer => {
......@@ -2407,6 +2408,19 @@ pub const Type = extern union {
24072408 };
24082409 }
24092410
2411 /// Asserts the type is a function.
2412 pub fn fnIsGeneric(self: Type) bool {
2413 return switch (self.tag()) {
2414 .fn_noreturn_no_args => false,
2415 .fn_void_no_args => false,
2416 .fn_naked_noreturn_no_args => false,
2417 .fn_ccc_void_no_args => false,
2418 .function => self.castTag(.function).?.data.is_generic,
2419
2420 else => unreachable,
2421 };
2422 }
2423
24102424 pub fn isNumeric(self: Type) bool {
24112425 return switch (self.tag()) {
24122426 .f16,
......@@ -3214,6 +3228,7 @@ pub const Type = extern union {
32143228 return_type: Type,
32153229 cc: std.builtin.CallingConvention,
32163230 is_var_args: bool,
3231 is_generic: bool,
32173232 },
32183233 };
32193234