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(...@@ -1064,11 +1064,28 @@ fn fnProtoExpr(
1064 const param_types = try gpa.alloc(Zir.Inst.Ref, param_count);1064 const param_types = try gpa.alloc(Zir.Inst.Ref, param_count);
1065 defer gpa.free(param_types);1065 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;
1067 var is_var_args = false;1073 var is_var_args = false;
1068 {1074 {
1069 var param_type_i: usize = 0;1075 var param_type_i: usize = 0;
1070 var it = fn_proto.iterate(tree.*);1076 var it = fn_proto.iterate(tree.*);
1071 while (it.next()) |param| : (param_type_i += 1) {1077 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
1072 if (param.anytype_ellipsis3) |token| {1089 if (param.anytype_ellipsis3) |token| {
1073 switch (token_tags[token]) {1090 switch (token_tags[token]) {
1074 .keyword_anytype => {1091 .keyword_anytype => {
...@@ -1088,6 +1105,11 @@ fn fnProtoExpr(...@@ -1088,6 +1105,11 @@ fn fnProtoExpr(
1088 try expr(gz, scope, .{ .ty = .type_type }, param_type_node);1105 try expr(gz, scope, .{ .ty = .type_type }, param_type_node);
1089 }1106 }
1090 assert(param_type_i == param_count);1107 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 }
1091 }1113 }
10921114
1093 const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {1115 const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
...@@ -1131,6 +1153,8 @@ fn fnProtoExpr(...@@ -1131,6 +1153,8 @@ fn fnProtoExpr(
1131 .is_inferred_error = false,1153 .is_inferred_error = false,
1132 .is_test = false,1154 .is_test = false,
1133 .is_extern = false,1155 .is_extern = false,
1156 .cur_bit_bag = cur_bit_bag,
1157 .bit_bag = bit_bag.items,
1134 });1158 });
1135 return rvalue(gz, rl, result, fn_proto.ast.proto_node);1159 return rvalue(gz, rl, result, fn_proto.ast.proto_node);
1136}1160}
...@@ -2916,11 +2940,28 @@ fn fnDecl(...@@ -2916,11 +2940,28 @@ fn fnDecl(
2916 const param_types = try gpa.alloc(Zir.Inst.Ref, param_count);2940 const param_types = try gpa.alloc(Zir.Inst.Ref, param_count);
2917 defer gpa.free(param_types);2941 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;
2919 var is_var_args = false;2949 var is_var_args = false;
2920 {2950 {
2921 var param_type_i: usize = 0;2951 var param_type_i: usize = 0;
2922 var it = fn_proto.iterate(tree.*);2952 var it = fn_proto.iterate(tree.*);
2923 while (it.next()) |param| : (param_type_i += 1) {2953 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
2924 if (param.anytype_ellipsis3) |token| {2965 if (param.anytype_ellipsis3) |token| {
2925 switch (token_tags[token]) {2966 switch (token_tags[token]) {
2926 .keyword_anytype => {2967 .keyword_anytype => {
...@@ -2940,6 +2981,11 @@ fn fnDecl(...@@ -2940,6 +2981,11 @@ fn fnDecl(
2940 try expr(&decl_gz, &decl_gz.base, .{ .ty = .type_type }, param_type_node);2981 try expr(&decl_gz, &decl_gz.base, .{ .ty = .type_type }, param_type_node);
2941 }2982 }
2942 assert(param_type_i == param_count);2983 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 }
2943 }2989 }
29442990
2945 const lib_name: u32 = if (fn_proto.lib_name) |lib_name_token| blk: {2991 const lib_name: u32 = if (fn_proto.lib_name) |lib_name_token| blk: {
...@@ -3001,6 +3047,8 @@ fn fnDecl(...@@ -3001,6 +3047,8 @@ fn fnDecl(
3001 .is_inferred_error = false,3047 .is_inferred_error = false,
3002 .is_test = false,3048 .is_test = false,
3003 .is_extern = true,3049 .is_extern = true,
3050 .cur_bit_bag = cur_bit_bag,
3051 .bit_bag = bit_bag.items,
3004 });3052 });
3005 } else func: {3053 } else func: {
3006 if (is_var_args) {3054 if (is_var_args) {
...@@ -3094,6 +3142,8 @@ fn fnDecl(...@@ -3094,6 +3142,8 @@ fn fnDecl(
3094 .is_inferred_error = is_inferred_error,3142 .is_inferred_error = is_inferred_error,
3095 .is_test = false,3143 .is_test = false,
3096 .is_extern = false,3144 .is_extern = false,
3145 .cur_bit_bag = cur_bit_bag,
3146 .bit_bag = bit_bag.items,
3097 });3147 });
3098 };3148 };
30993149
...@@ -3439,6 +3489,8 @@ fn testDecl(...@@ -3439,6 +3489,8 @@ fn testDecl(
3439 .is_inferred_error = true,3489 .is_inferred_error = true,
3440 .is_test = true,3490 .is_test = true,
3441 .is_extern = false,3491 .is_extern = false,
3492 .cur_bit_bag = 0,
3493 .bit_bag = &.{},
3442 });3494 });
34433495
3444 _ = try decl_block.addBreak(.break_inline, block_inst, func_inst);3496 _ = try decl_block.addBreak(.break_inline, block_inst, func_inst);
...@@ -9135,6 +9187,8 @@ const GenZir = struct {...@@ -9135,6 +9187,8 @@ const GenZir = struct {
9135 is_inferred_error: bool,9187 is_inferred_error: bool,
9136 is_test: bool,9188 is_test: bool,
9137 is_extern: bool,9189 is_extern: bool,
9190 cur_bit_bag: u32,
9191 bit_bag: []const u32,
9138 }) !Zir.Inst.Ref {9192 }) !Zir.Inst.Ref {
9139 assert(args.src_node != 0);9193 assert(args.src_node != 0);
9140 assert(args.ret_ty != .none);9194 assert(args.ret_ty != .none);
...@@ -9172,13 +9226,18 @@ const GenZir = struct {...@@ -9172,13 +9226,18 @@ const GenZir = struct {
9172 src_locs = &src_locs_buffer;9226 src_locs = &src_locs_buffer;
9173 }9227 }
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
9175 if (args.cc != .none or args.lib_name != 0 or9233 if (args.cc != .none or args.lib_name != 0 or
9176 args.is_var_args or args.is_test or args.align_inst != .none or9234 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)
9178 {9236 {
9179 try astgen.extra.ensureUnusedCapacity(9237 try astgen.extra.ensureUnusedCapacity(
9180 gpa,9238 gpa,
9181 @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len +9239 @typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len +
9240 @boolToInt(any_are_comptime) + args.bit_bag.len +
9182 args.param_types.len + args.body.len + src_locs.len +9241 args.param_types.len + args.body.len + src_locs.len +
9183 @boolToInt(args.lib_name != 0) +9242 @boolToInt(args.lib_name != 0) +
9184 @boolToInt(args.align_inst != .none) +9243 @boolToInt(args.align_inst != .none) +
...@@ -9199,6 +9258,10 @@ const GenZir = struct {...@@ -9199,6 +9258,10 @@ const GenZir = struct {
9199 if (args.align_inst != .none) {9258 if (args.align_inst != .none) {
9200 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));9259 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));
9201 }9260 }
9261 if (any_are_comptime) {
9262 astgen.extra.appendSliceAssumeCapacity(args.bit_bag); // Likely empty.
9263 astgen.extra.appendAssumeCapacity(args.cur_bit_bag);
9264 }
9202 astgen.appendRefsAssumeCapacity(args.param_types);9265 astgen.appendRefsAssumeCapacity(args.param_types);
9203 astgen.extra.appendSliceAssumeCapacity(args.body);9266 astgen.extra.appendSliceAssumeCapacity(args.body);
9204 astgen.extra.appendSliceAssumeCapacity(src_locs);9267 astgen.extra.appendSliceAssumeCapacity(src_locs);
...@@ -9216,6 +9279,7 @@ const GenZir = struct {...@@ -9216,6 +9279,7 @@ const GenZir = struct {
9216 .has_align = args.align_inst != .none,9279 .has_align = args.align_inst != .none,
9217 .is_test = args.is_test,9280 .is_test = args.is_test,
9218 .is_extern = args.is_extern,9281 .is_extern = args.is_extern,
9282 .has_comptime_bits = any_are_comptime,
9219 }),9283 }),
9220 .operand = payload_index,9284 .operand = payload_index,
9221 } },9285 } },
src/Sema.zig+28-1
...@@ -104,6 +104,9 @@ pub fn analyzeFnBody(...@@ -104,6 +104,9 @@ pub fn analyzeFnBody(
104 extra_index += @boolToInt(small.has_lib_name);104 extra_index += @boolToInt(small.has_lib_name);
105 extra_index += @boolToInt(small.has_cc);105 extra_index += @boolToInt(small.has_cc);
106 extra_index += @boolToInt(small.has_align);106 extra_index += @boolToInt(small.has_align);
107 if (small.has_comptime_bits) {
108 extra_index += (extra.data.param_types_len + 31) / 32;
109 }
107 extra_index += extra.data.param_types_len;110 extra_index += extra.data.param_types_len;
108 const body = sema.code.extra[extra_index..][0..extra.data.body_len];111 const body = sema.code.extra[extra_index..][0..extra.data.body_len];
109 break :blk body;112 break :blk body;
...@@ -2533,6 +2536,9 @@ fn analyzeCall(...@@ -2533,6 +2536,9 @@ fn analyzeCall(
25332536
2534 break :res result;2537 break :res result;
2535 } else res: {2538 } else res: {
2539 if (func_ty.fnIsGeneric()) {
2540 return sema.mod.fail(&block.base, func_src, "TODO implement generic fn call", .{});
2541 }
2536 try sema.requireRuntimeBlock(block, call_src);2542 try sema.requireRuntimeBlock(block, call_src);
2537 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +2543 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
2538 args.len);2544 args.len);
...@@ -3208,6 +3214,7 @@ fn zirFunc(...@@ -3208,6 +3214,7 @@ fn zirFunc(
3208 false,3214 false,
3209 src_locs,3215 src_locs,
3210 null,3216 null,
3217 &.{},
3211 );3218 );
3212}3219}
32133220
...@@ -3225,6 +3232,7 @@ fn funcCommon(...@@ -3225,6 +3232,7 @@ fn funcCommon(
3225 is_extern: bool,3232 is_extern: bool,
3226 src_locs: Zir.Inst.Func.SrcLocs,3233 src_locs: Zir.Inst.Func.SrcLocs,
3227 opt_lib_name: ?[]const u8,3234 opt_lib_name: ?[]const u8,
3235 comptime_bits: []const u32,
3228) CompileError!Air.Inst.Ref {3236) CompileError!Air.Inst.Ref {
3229 const src: LazySrcLoc = .{ .node_offset = src_node_offset };3237 const src: LazySrcLoc = .{ .node_offset = src_node_offset };
3230 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };3238 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
...@@ -3257,13 +3265,23 @@ fn funcCommon(...@@ -3257,13 +3265,23 @@ fn funcCommon(
3257 }3265 }
3258 }3266 }
32593267
3268 var any_are_comptime = false;
3260 const param_types = try sema.arena.alloc(Type, zir_param_types.len);3269 const param_types = try sema.arena.alloc(Type, zir_param_types.len);
3261 for (zir_param_types) |param_type, i| {3270 for (zir_param_types) |param_type, i| {
3262 // TODO make a compile error from `resolveType` report the source location3271 // TODO make a compile error from `resolveType` report the source location
3263 // of the specific parameter. Will need to take a similar strategy as3272 // of the specific parameter. Will need to take a similar strategy as
3264 // `resolveSwitchItemVal` to avoid resolving the source location unless3273 // `resolveSwitchItemVal` to avoid resolving the source location unless
3265 // we actually need to report an error.3274 // 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 };
3267 }3285 }
32683286
3269 if (align_val.tag() != .null_value) {3287 if (align_val.tag() != .null_value) {
...@@ -3286,6 +3304,7 @@ fn funcCommon(...@@ -3286,6 +3304,7 @@ fn funcCommon(
3286 .return_type = return_type,3304 .return_type = return_type,
3287 .cc = cc,3305 .cc = cc,
3288 .is_var_args = var_args,3306 .is_var_args = var_args,
3307 .is_generic = any_are_comptime,
3289 });3308 });
3290 };3309 };
32913310
...@@ -6526,6 +6545,13 @@ fn zirFuncExtended(...@@ -6526,6 +6545,13 @@ fn zirFuncExtended(
6526 break :blk align_tv.val;6545 break :blk align_tv.val;
6527 } else Value.initTag(.null_value);6546 } 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
6529 const param_types = sema.code.refSlice(extra_index, extra.data.param_types_len);6555 const param_types = sema.code.refSlice(extra_index, extra.data.param_types_len);
6530 extra_index += param_types.len;6556 extra_index += param_types.len;
65316557
...@@ -6554,6 +6580,7 @@ fn zirFuncExtended(...@@ -6554,6 +6580,7 @@ fn zirFuncExtended(
6554 is_extern,6580 is_extern,
6555 src_locs,6581 src_locs,
6556 lib_name,6582 lib_name,
6583 comptime_bits,
6557 );6584 );
6558}6585}
65596586
src/Zir.zig+24-4
...@@ -2226,9 +2226,13 @@ pub const Inst = struct {...@@ -2226,9 +2226,13 @@ pub const Inst = struct {
2226 /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set2226 /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set
2227 /// 1. cc: Ref, // if has_cc is set2227 /// 1. cc: Ref, // if has_cc is set
2228 /// 2. align: Ref, // if has_align is set2228 /// 2. align: Ref, // if has_align is set
2229 /// 3. param_type: Ref // for each param_types_len2229 /// 3. comptime_bits: u32 // for every 32 parameters, if has_comptime_bits is set
2230 /// 4. body: Index // for each body_len2230 /// - sets of 1 bit:
2231 /// 5. src_locs: Func.SrcLocs // if body_len != 02231 /// 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
2232 pub const ExtendedFunc = struct {2236 pub const ExtendedFunc = struct {
2233 src_node: i32,2237 src_node: i32,
2234 return_type: Ref,2238 return_type: Ref,
...@@ -2243,7 +2247,8 @@ pub const Inst = struct {...@@ -2243,7 +2247,8 @@ pub const Inst = struct {
2243 has_align: bool,2247 has_align: bool,
2244 is_test: bool,2248 is_test: bool,
2245 is_extern: bool,2249 is_extern: bool,
2246 _: u9 = undefined,2250 has_comptime_bits: bool,
2251 _: u8 = undefined,
2247 };2252 };
2248 };2253 };
22492254
...@@ -4291,6 +4296,7 @@ const Writer = struct {...@@ -4291,6 +4296,7 @@ const Writer = struct {
4291 body,4296 body,
4292 src,4297 src,
4293 src_locs,4298 src_locs,
4299 &.{},
4294 );4300 );
4295 }4301 }
42964302
...@@ -4317,6 +4323,13 @@ const Writer = struct {...@@ -4317,6 +4323,13 @@ const Writer = struct {
4317 break :blk align_inst;4323 break :blk align_inst;
4318 };4324 };
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
4320 const param_types = self.code.refSlice(extra_index, extra.data.param_types_len);4333 const param_types = self.code.refSlice(extra_index, extra.data.param_types_len);
4321 extra_index += param_types.len;4334 extra_index += param_types.len;
43224335
...@@ -4339,6 +4352,7 @@ const Writer = struct {...@@ -4339,6 +4352,7 @@ const Writer = struct {
4339 body,4352 body,
4340 src,4353 src,
4341 src_locs,4354 src_locs,
4355 comptime_bits,
4342 );4356 );
4343 }4357 }
43444358
...@@ -4422,10 +4436,16 @@ const Writer = struct {...@@ -4422,10 +4436,16 @@ const Writer = struct {
4422 body: []const Inst.Index,4436 body: []const Inst.Index,
4423 src: LazySrcLoc,4437 src: LazySrcLoc,
4424 src_locs: Zir.Inst.Func.SrcLocs,4438 src_locs: Zir.Inst.Func.SrcLocs,
4439 comptime_bits: []const u32,
4425 ) !void {4440 ) !void {
4426 try stream.writeAll("[");4441 try stream.writeAll("[");
4427 for (param_types) |param_type, i| {4442 for (param_types) |param_type, i| {
4428 if (i != 0) try stream.writeAll(", ");4443 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 }
4429 try self.writeInstRef(stream, param_type);4449 try self.writeInstRef(stream, param_type);
4430 }4450 }
4431 try stream.writeAll("], ");4451 try stream.writeAll("], ");
src/type.zig+15
...@@ -764,6 +764,7 @@ pub const Type = extern union {...@@ -764,6 +764,7 @@ pub const Type = extern union {
764 .param_types = param_types,764 .param_types = param_types,
765 .cc = payload.cc,765 .cc = payload.cc,
766 .is_var_args = payload.is_var_args,766 .is_var_args = payload.is_var_args,
767 .is_generic = payload.is_generic,
767 });768 });
768 },769 },
769 .pointer => {770 .pointer => {
...@@ -2407,6 +2408,19 @@ pub const Type = extern union {...@@ -2407,6 +2408,19 @@ pub const Type = extern union {
2407 };2408 };
2408 }2409 }
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
2410 pub fn isNumeric(self: Type) bool {2424 pub fn isNumeric(self: Type) bool {
2411 return switch (self.tag()) {2425 return switch (self.tag()) {
2412 .f16,2426 .f16,
...@@ -3214,6 +3228,7 @@ pub const Type = extern union {...@@ -3214,6 +3228,7 @@ pub const Type = extern union {
3214 return_type: Type,3228 return_type: Type,
3215 cc: std.builtin.CallingConvention,3229 cc: std.builtin.CallingConvention,
3216 is_var_args: bool,3230 is_var_args: bool,
3231 is_generic: bool,
3217 },3232 },
3218 };3233 };
32193234