authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-26 15:51:33-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-01-26 15:51:33-08:00
logb96fb858c88b97617e6fa0e3c6966a8e900caf7f
treee1729e12109e85e1ed2d4b7eb06187206e9bd8d3
parent8a0429e885489eac497aa97fdfcaaa1befb2b6d4
parent06d8bb32e3edfb4a26c6d3ecdf198574f4bd3f87
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #18654 from mlugg/incremental-the-second

InternPool: introduce TrackedInst to prepare for incremental compilation

9 files changed, 969 insertions(+), 1058 deletions(-)

src/AstGen.zig+225-159
......@@ -86,6 +86,7 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void {
8686
8787 Zir.Inst.Ref,
8888 Zir.Inst.Index,
89 Zir.Inst.Declaration.Name,
8990 Zir.NullTerminatedString,
9091 => @intFromEnum(@field(extra, field.name)),
9192
......@@ -95,6 +96,7 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void {
9596 Zir.Inst.SwitchBlock.Bits,
9697 Zir.Inst.SwitchBlockErrUnion.Bits,
9798 Zir.Inst.FuncFancy.Bits,
99 Zir.Inst.Declaration.Flags,
98100 => @bitCast(@field(extra, field.name)),
99101
100102 else => @compileError("bad field type"),
......@@ -132,8 +134,8 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
132134 };
133135 defer astgen.deinit(gpa);
134136
135 // String table indexes 0, 1, 2 are reserved for special meaning.
136 try astgen.string_bytes.appendSlice(gpa, &[_]u8{ 0, 0, 0 });
137 // String table index 0 is reserved for `NullTerminatedString.empty`.
138 try astgen.string_bytes.append(gpa, 0);
137139
138140 // We expect at least as many ZIR instructions and extra data items
139141 // as AST nodes.
......@@ -355,8 +357,13 @@ const ResultInfo = struct {
355357 };
356358};
357359
360/// TODO: modify Sema to remove in favour of `coerced_align_ri`
358361const align_ri: ResultInfo = .{ .rl = .{ .ty = .u29_type } };
359362const coerced_align_ri: ResultInfo = .{ .rl = .{ .coerced_ty = .u29_type } };
363/// TODO: modify Sema to remove in favour of `coerced_addrspace_ri`
364const addrspace_ri: ResultInfo = .{ .rl = .{ .ty = .address_space_type } };
365const coerced_addrspace_ri: ResultInfo = .{ .rl = .{ .coerced_ty = .address_space_type } };
366const coerced_linksection_ri: ResultInfo = .{ .rl = .{ .coerced_ty = .slice_const_u8_type } };
360367const bool_ri: ResultInfo = .{ .rl = .{ .ty = .bool_type } };
361368const type_ri: ResultInfo = .{ .rl = .{ .ty = .type_type } };
362369const coerced_type_ri: ResultInfo = .{ .rl = .{ .coerced_ty = .type_type } };
......@@ -2592,6 +2599,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
25922599 .block,
25932600 .block_comptime,
25942601 .block_inline,
2602 .declaration,
25952603 .suspend_block,
25962604 .loop,
25972605 .bool_br_and,
......@@ -3783,7 +3791,7 @@ fn ptrType(
37833791 gz.astgen.source_line = source_line;
37843792 gz.astgen.source_column = source_column;
37853793
3786 addrspace_ref = try expr(gz, scope, .{ .rl = .{ .ty = .address_space_type } }, ptr_info.ast.addrspace_node);
3794 addrspace_ref = try expr(gz, scope, addrspace_ri, ptr_info.ast.addrspace_node);
37873795 trailing_count += 1;
37883796 }
37893797 if (ptr_info.ast.align_node != 0) {
......@@ -3899,8 +3907,6 @@ fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.
38993907const WipMembers = struct {
39003908 payload: *ArrayListUnmanaged(u32),
39013909 payload_top: usize,
3902 decls_start: u32,
3903 decls_end: u32,
39043910 field_bits_start: u32,
39053911 fields_start: u32,
39063912 fields_end: u32,
......@@ -3908,43 +3914,27 @@ const WipMembers = struct {
39083914 field_index: u32 = 0,
39093915
39103916 const Self = @This();
3911 /// struct, union, enum, and opaque decls all use same 4 bits per decl
3912 const bits_per_decl = 4;
3913 const decls_per_u32 = 32 / bits_per_decl;
3914 /// struct, union, enum, and opaque decls all have maximum size of 11 u32 slots
3915 /// (4 for src_hash + line + name + value + doc_comment + align + link_section + address_space )
3916 const max_decl_size = 11;
39173917
39183918 fn init(gpa: Allocator, payload: *ArrayListUnmanaged(u32), decl_count: u32, field_count: u32, comptime bits_per_field: u32, comptime max_field_size: u32) Allocator.Error!Self {
39193919 const payload_top: u32 = @intCast(payload.items.len);
3920 const decls_start = payload_top + (decl_count + decls_per_u32 - 1) / decls_per_u32;
3921 const field_bits_start = decls_start + decl_count * max_decl_size;
3920 const field_bits_start = payload_top + decl_count;
39223921 const fields_start = field_bits_start + if (bits_per_field > 0) blk: {
39233922 const fields_per_u32 = 32 / bits_per_field;
39243923 break :blk (field_count + fields_per_u32 - 1) / fields_per_u32;
39253924 } else 0;
39263925 const payload_end = fields_start + field_count * max_field_size;
39273926 try payload.resize(gpa, payload_end);
3928 return Self{
3927 return .{
39293928 .payload = payload,
39303929 .payload_top = payload_top,
3931 .decls_start = decls_start,
39323930 .field_bits_start = field_bits_start,
39333931 .fields_start = fields_start,
3934 .decls_end = decls_start,
39353932 .fields_end = fields_start,
39363933 };
39373934 }
39383935
3939 fn nextDecl(self: *Self, is_pub: bool, is_export: bool, has_align: bool, has_section_or_addrspace: bool) void {
3940 const index = self.payload_top + self.decl_index / decls_per_u32;
3941 assert(index < self.decls_start);
3942 const bit_bag: u32 = if (self.decl_index % decls_per_u32 == 0) 0 else self.payload.items[index];
3943 self.payload.items[index] = (bit_bag >> bits_per_decl) |
3944 (@as(u32, @intFromBool(is_pub)) << 28) |
3945 (@as(u32, @intFromBool(is_export)) << 29) |
3946 (@as(u32, @intFromBool(has_align)) << 30) |
3947 (@as(u32, @intFromBool(has_section_or_addrspace)) << 31);
3936 fn nextDecl(self: *Self, decl_inst: Zir.Inst.Index) void {
3937 self.payload.items[self.payload_top + self.decl_index] = @intFromEnum(decl_inst);
39483938 self.decl_index += 1;
39493939 }
39503940
......@@ -3962,18 +3952,6 @@ const WipMembers = struct {
39623952 self.field_index += 1;
39633953 }
39643954
3965 fn appendToDecl(self: *Self, data: u32) void {
3966 assert(self.decls_end < self.field_bits_start);
3967 self.payload.items[self.decls_end] = data;
3968 self.decls_end += 1;
3969 }
3970
3971 fn appendToDeclSlice(self: *Self, data: []const u32) void {
3972 assert(self.decls_end + data.len <= self.field_bits_start);
3973 @memcpy(self.payload.items[self.decls_end..][0..data.len], data);
3974 self.decls_end += @intCast(data.len);
3975 }
3976
39773955 fn appendToField(self: *Self, data: u32) void {
39783956 assert(self.fields_end < self.payload.items.len);
39793957 self.payload.items[self.fields_end] = data;
......@@ -3981,11 +3959,6 @@ const WipMembers = struct {
39813959 }
39823960
39833961 fn finishBits(self: *Self, comptime bits_per_field: u32) void {
3984 const empty_decl_slots = decls_per_u32 - (self.decl_index % decls_per_u32);
3985 if (self.decl_index > 0 and empty_decl_slots < decls_per_u32) {
3986 const index = self.payload_top + self.decl_index / decls_per_u32;
3987 self.payload.items[index] >>= @intCast(empty_decl_slots * bits_per_decl);
3988 }
39893962 if (bits_per_field > 0) {
39903963 const fields_per_u32 = 32 / bits_per_field;
39913964 const empty_field_slots = fields_per_u32 - (self.field_index % fields_per_u32);
......@@ -3997,7 +3970,7 @@ const WipMembers = struct {
39973970 }
39983971
39993972 fn declsSlice(self: *Self) []u32 {
4000 return self.payload.items[self.payload_top..self.decls_end];
3973 return self.payload.items[self.payload_top..][0..self.decl_index];
40013974 }
40023975
40033976 fn fieldsSlice(self: *Self) []u32 {
......@@ -4023,11 +3996,10 @@ fn fnDecl(
40233996
40243997 // missing function name already happened in scanDecls()
40253998 const fn_name_token = fn_proto.name_token orelse return error.AnalysisFail;
4026 const fn_name_str_index = try astgen.identAsString(fn_name_token);
40273999
40284000 // We insert this at the beginning so that its instruction index marks the
40294001 // start of the top level declaration.
4030 const block_inst = try gz.makeBlockInst(.block_inline, fn_proto.ast.proto_node);
4002 const decl_inst = try gz.makeBlockInst(.declaration, fn_proto.ast.proto_node);
40314003 astgen.advanceSourceCursorToNode(decl_node);
40324004
40334005 var decl_gz: GenZir = .{
......@@ -4072,8 +4044,7 @@ fn fnDecl(
40724044
40734045 const doc_comment_index = try astgen.docCommentAsString(fn_proto.firstToken());
40744046
4075 // align, linksection, and addrspace is passed in the func instruction in this case.
4076 wip_members.nextDecl(is_pub, is_export, false, false);
4047 wip_members.nextDecl(decl_inst);
40774048
40784049 var noalias_bits: u32 = 0;
40794050 var params_scope = &fn_gz.base;
......@@ -4213,7 +4184,7 @@ fn fnDecl(
42134184 var addrspace_gz = decl_gz.makeSubBlock(params_scope);
42144185 defer addrspace_gz.unstack();
42154186 const addrspace_ref: Zir.Inst.Ref = if (fn_proto.ast.addrspace_expr == 0) .none else inst: {
4216 const inst = try expr(&decl_gz, params_scope, .{ .rl = .{ .coerced_ty = .address_space_type } }, fn_proto.ast.addrspace_expr);
4187 const inst = try expr(&decl_gz, params_scope, addrspace_ri, fn_proto.ast.addrspace_expr);
42174188 if (addrspace_gz.instructionsSlice().len == 0) {
42184189 // In this case we will send a len=0 body which can be encoded more efficiently.
42194190 break :inst inst;
......@@ -4298,7 +4269,7 @@ fn fnDecl(
42984269 .section_gz = &section_gz,
42994270 .addrspace_ref = addrspace_ref,
43004271 .addrspace_gz = &addrspace_gz,
4301 .param_block = block_inst,
4272 .param_block = decl_inst,
43024273 .body_gz = null,
43034274 .lib_name = lib_name,
43044275 .is_var_args = is_var_args,
......@@ -4349,7 +4320,7 @@ fn fnDecl(
43494320 .addrspace_gz = &addrspace_gz,
43504321 .lbrace_line = lbrace_line,
43514322 .lbrace_column = lbrace_column,
4352 .param_block = block_inst,
4323 .param_block = decl_inst,
43534324 .body_gz = &fn_gz,
43544325 .lib_name = lib_name,
43554326 .is_var_args = is_var_args,
......@@ -4363,20 +4334,21 @@ fn fnDecl(
43634334
43644335 // We add this at the end so that its instruction index marks the end range
43654336 // of the top level declaration. addFunc already unstacked fn_gz and ret_gz.
4366 _ = try decl_gz.addBreak(.break_inline, block_inst, func_inst);
4367 try decl_gz.setBlockBody(block_inst);
4368
4369 {
4370 const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(decl_node));
4371 wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));
4372 }
4373 {
4374 const line_delta = decl_gz.decl_line - gz.decl_line;
4375 wip_members.appendToDecl(line_delta);
4376 }
4377 wip_members.appendToDecl(@intFromEnum(fn_name_str_index));
4378 wip_members.appendToDecl(@intFromEnum(block_inst));
4379 wip_members.appendToDecl(@intFromEnum(doc_comment_index));
4337 _ = try decl_gz.addBreak(.break_inline, decl_inst, func_inst);
4338
4339 try setDeclaration(
4340 decl_inst,
4341 std.zig.hashSrc(tree.getNodeSource(decl_node)),
4342 .{ .named = fn_name_token },
4343 decl_gz.decl_line - gz.decl_line,
4344 is_pub,
4345 is_export,
4346 doc_comment_index,
4347 &decl_gz,
4348 // align, linksection, and addrspace are passed in the func instruction in this case.
4349 // TODO: move them from the function instruction to the declaration instruction?
4350 null,
4351 );
43804352}
43814353
43824354fn globalVarDecl(
......@@ -4393,10 +4365,9 @@ fn globalVarDecl(
43934365 const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
43944366 // We do this at the beginning so that the instruction index marks the range start
43954367 // of the top level declaration.
4396 const block_inst = try gz.makeBlockInst(.block_inline, node);
4368 const decl_inst = try gz.makeBlockInst(.declaration, node);
43974369
43984370 const name_token = var_decl.ast.mut_token + 1;
4399 const name_str_index = try astgen.identAsString(name_token);
44004371 astgen.advanceSourceCursorToNode(node);
44014372
44024373 var block_scope: GenZir = .{
......@@ -4420,17 +4391,7 @@ fn globalVarDecl(
44204391 const maybe_extern_token = var_decl.extern_export_token orelse break :blk false;
44214392 break :blk token_tags[maybe_extern_token] == .keyword_extern;
44224393 };
4423 const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node == 0) .none else inst: {
4424 break :inst try expr(&block_scope, &block_scope.base, align_ri, var_decl.ast.align_node);
4425 };
4426 const addrspace_inst: Zir.Inst.Ref = if (var_decl.ast.addrspace_node == 0) .none else inst: {
4427 break :inst try expr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .address_space_type } }, var_decl.ast.addrspace_node);
4428 };
4429 const section_inst: Zir.Inst.Ref = if (var_decl.ast.section_node == 0) .none else inst: {
4430 break :inst try comptimeExpr(&block_scope, &block_scope.base, .{ .rl = .{ .ty = .slice_const_u8_type } }, var_decl.ast.section_node);
4431 };
4432 const has_section_or_addrspace = section_inst != .none or addrspace_inst != .none;
4433 wip_members.nextDecl(is_pub, is_export, align_inst != .none, has_section_or_addrspace);
4394 wip_members.nextDecl(decl_inst);
44344395
44354396 const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: {
44364397 if (!is_mutable) {
......@@ -4513,29 +4474,44 @@ fn globalVarDecl(
45134474 } else {
45144475 return astgen.failNode(node, "unable to infer variable type", .{});
45154476 };
4477
45164478 // We do this at the end so that the instruction index marks the end
45174479 // range of a top level declaration.
4518 _ = try block_scope.addBreakWithSrcNode(.break_inline, block_inst, var_inst, node);
4519 try block_scope.setBlockBody(block_inst);
4480 _ = try block_scope.addBreakWithSrcNode(.break_inline, decl_inst, var_inst, node);
45204481
4521 {
4522 const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(node));
4523 wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));
4482 var align_gz = block_scope.makeSubBlock(scope);
4483 if (var_decl.ast.align_node != 0) {
4484 const align_inst = try expr(&align_gz, &align_gz.base, coerced_align_ri, var_decl.ast.align_node);
4485 _ = try align_gz.addBreakWithSrcNode(.break_inline, decl_inst, align_inst, node);
45244486 }
4525 {
4526 const line_delta = block_scope.decl_line - gz.decl_line;
4527 wip_members.appendToDecl(line_delta);
4528 }
4529 wip_members.appendToDecl(@intFromEnum(name_str_index));
4530 wip_members.appendToDecl(@intFromEnum(block_inst));
4531 wip_members.appendToDecl(@intFromEnum(doc_comment_index)); // doc_comment wip
4532 if (align_inst != .none) {
4533 wip_members.appendToDecl(@intFromEnum(align_inst));
4534 }
4535 if (has_section_or_addrspace) {
4536 wip_members.appendToDecl(@intFromEnum(section_inst));
4537 wip_members.appendToDecl(@intFromEnum(addrspace_inst));
4487
4488 var linksection_gz = align_gz.makeSubBlock(scope);
4489 if (var_decl.ast.section_node != 0) {
4490 const linksection_inst = try expr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, var_decl.ast.section_node);
4491 _ = try linksection_gz.addBreakWithSrcNode(.break_inline, decl_inst, linksection_inst, node);
45384492 }
4493
4494 var addrspace_gz = linksection_gz.makeSubBlock(scope);
4495 if (var_decl.ast.addrspace_node != 0) {
4496 const addrspace_inst = try expr(&addrspace_gz, &addrspace_gz.base, coerced_addrspace_ri, var_decl.ast.addrspace_node);
4497 _ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, addrspace_inst, node);
4498 }
4499
4500 try setDeclaration(
4501 decl_inst,
4502 std.zig.hashSrc(tree.getNodeSource(node)),
4503 .{ .named = name_token },
4504 block_scope.decl_line - gz.decl_line,
4505 is_pub,
4506 is_export,
4507 doc_comment_index,
4508 &block_scope,
4509 .{
4510 .align_gz = &align_gz,
4511 .linksection_gz = &linksection_gz,
4512 .addrspace_gz = &addrspace_gz,
4513 },
4514 );
45394515}
45404516
45414517fn comptimeDecl(
......@@ -4551,8 +4527,8 @@ fn comptimeDecl(
45514527
45524528 // Up top so the ZIR instruction index marks the start range of this
45534529 // top-level declaration.
4554 const block_inst = try gz.makeBlockInst(.block_inline, node);
4555 wip_members.nextDecl(false, false, false, false);
4530 const decl_inst = try gz.makeBlockInst(.declaration, node);
4531 wip_members.nextDecl(decl_inst);
45564532 astgen.advanceSourceCursorToNode(node);
45574533
45584534 var decl_block: GenZir = .{
......@@ -4568,21 +4544,20 @@ fn comptimeDecl(
45684544
45694545 const block_result = try expr(&decl_block, &decl_block.base, .{ .rl = .none }, body_node);
45704546 if (decl_block.isEmpty() or !decl_block.refIsNoReturn(block_result)) {
4571 _ = try decl_block.addBreak(.break_inline, block_inst, .void_value);
4547 _ = try decl_block.addBreak(.break_inline, decl_inst, .void_value);
45724548 }
4573 try decl_block.setBlockBody(block_inst);
45744549
4575 {
4576 const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(node));
4577 wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));
4578 }
4579 {
4580 const line_delta = decl_block.decl_line - gz.decl_line;
4581 wip_members.appendToDecl(line_delta);
4582 }
4583 wip_members.appendToDecl(0);
4584 wip_members.appendToDecl(@intFromEnum(block_inst));
4585 wip_members.appendToDecl(0); // no doc comments on comptime decls
4550 try setDeclaration(
4551 decl_inst,
4552 std.zig.hashSrc(tree.getNodeSource(node)),
4553 .@"comptime",
4554 decl_block.decl_line - gz.decl_line,
4555 false,
4556 false,
4557 .empty,
4558 &decl_block,
4559 null,
4560 );
45864561}
45874562
45884563fn usingnamespaceDecl(
......@@ -4604,8 +4579,8 @@ fn usingnamespaceDecl(
46044579 };
46054580 // Up top so the ZIR instruction index marks the start range of this
46064581 // top-level declaration.
4607 const block_inst = try gz.makeBlockInst(.block_inline, node);
4608 wip_members.nextDecl(is_pub, true, false, false);
4582 const decl_inst = try gz.makeBlockInst(.declaration, node);
4583 wip_members.nextDecl(decl_inst);
46094584 astgen.advanceSourceCursorToNode(node);
46104585
46114586 var decl_block: GenZir = .{
......@@ -4620,20 +4595,19 @@ fn usingnamespaceDecl(
46204595 defer decl_block.unstack();
46214596
46224597 const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr);
4623 _ = try decl_block.addBreak(.break_inline, block_inst, namespace_inst);
4624 try decl_block.setBlockBody(block_inst);
4625
4626 {
4627 const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(node));
4628 wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));
4629 }
4630 {
4631 const line_delta = decl_block.decl_line - gz.decl_line;
4632 wip_members.appendToDecl(line_delta);
4633 }
4634 wip_members.appendToDecl(0);
4635 wip_members.appendToDecl(@intFromEnum(block_inst));
4636 wip_members.appendToDecl(0); // no doc comments on usingnamespace decls
4598 _ = try decl_block.addBreak(.break_inline, decl_inst, namespace_inst);
4599
4600 try setDeclaration(
4601 decl_inst,
4602 std.zig.hashSrc(tree.getNodeSource(node)),
4603 .@"usingnamespace",
4604 decl_block.decl_line - gz.decl_line,
4605 is_pub,
4606 false,
4607 .empty,
4608 &decl_block,
4609 null,
4610 );
46374611}
46384612
46394613fn testDecl(
......@@ -4649,9 +4623,9 @@ fn testDecl(
46494623
46504624 // Up top so the ZIR instruction index marks the start range of this
46514625 // top-level declaration.
4652 const block_inst = try gz.makeBlockInst(.block_inline, node);
4626 const decl_inst = try gz.makeBlockInst(.declaration, node);
46534627
4654 wip_members.nextDecl(false, false, false, false);
4628 wip_members.nextDecl(decl_inst);
46554629 astgen.advanceSourceCursorToNode(node);
46564630
46574631 var decl_block: GenZir = .{
......@@ -4669,12 +4643,10 @@ fn testDecl(
46694643 const token_tags = tree.tokens.items(.tag);
46704644 const test_token = main_tokens[node];
46714645 const test_name_token = test_token + 1;
4672 const test_name_token_tag = token_tags[test_name_token];
4673 const is_decltest = test_name_token_tag == .identifier;
4674 const test_name: Zir.NullTerminatedString = blk: {
4675 if (test_name_token_tag == .string_literal) {
4676 break :blk try astgen.testNameString(test_name_token);
4677 } else if (test_name_token_tag == .identifier) {
4646 const test_name: DeclarationName = switch (token_tags[test_name_token]) {
4647 else => .unnamed_test,
4648 .string_literal => .{ .named_test = test_name_token },
4649 .identifier => blk: {
46784650 const ident_name_raw = tree.tokenSlice(test_name_token);
46794651
46804652 if (mem.eql(u8, ident_name_raw, "_")) return astgen.failTok(test_name_token, "'_' used as an identifier without @\"_\" syntax", .{});
......@@ -4744,10 +4716,8 @@ fn testDecl(
47444716 return astgen.failTok(test_name_token, "use of undeclared identifier '{s}'", .{ident_name});
47454717 }
47464718
4747 break :blk name_str_index;
4748 }
4749 // String table index 1 has a special meaning here of test decl with no name.
4750 break :blk .unnamed_test_decl;
4719 break :blk .{ .decltest = name_str_index };
4720 },
47514721 };
47524722
47534723 var fn_block: GenZir = .{
......@@ -4795,7 +4765,7 @@ fn testDecl(
47954765
47964766 .lbrace_line = lbrace_line,
47974767 .lbrace_column = lbrace_column,
4798 .param_block = block_inst,
4768 .param_block = decl_inst,
47994769 .body_gz = &fn_block,
48004770 .lib_name = .empty,
48014771 .is_var_args = false,
......@@ -4806,26 +4776,19 @@ fn testDecl(
48064776 .noalias_bits = 0,
48074777 });
48084778
4809 _ = try decl_block.addBreak(.break_inline, block_inst, func_inst);
4810 try decl_block.setBlockBody(block_inst);
4811
4812 {
4813 const contents_hash align(@alignOf(u32)) = std.zig.hashSrc(tree.getNodeSource(node));
4814 wip_members.appendToDeclSlice(std.mem.bytesAsSlice(u32, &contents_hash));
4815 }
4816 {
4817 const line_delta = decl_block.decl_line - gz.decl_line;
4818 wip_members.appendToDecl(line_delta);
4819 }
4820 if (is_decltest)
4821 wip_members.appendToDecl(2) // 2 here means that it is a decltest, look at doc comment for name
4822 else
4823 wip_members.appendToDecl(@intFromEnum(test_name));
4824 wip_members.appendToDecl(@intFromEnum(block_inst));
4825 if (is_decltest)
4826 wip_members.appendToDecl(@intFromEnum(test_name)) // the doc comment on a decltest represents it's name
4827 else
4828 wip_members.appendToDecl(0); // no doc comments on test decls
4779 _ = try decl_block.addBreak(.break_inline, decl_inst, func_inst);
4780
4781 try setDeclaration(
4782 decl_inst,
4783 std.zig.hashSrc(tree.getNodeSource(node)),
4784 test_name,
4785 decl_block.decl_line - gz.decl_line,
4786 false,
4787 false,
4788 .empty,
4789 &decl_block,
4790 null,
4791 );
48294792}
48304793
48314794fn structDeclInner(
......@@ -13524,3 +13487,106 @@ fn lowerAstErrors(astgen: *AstGen) !void {
1352413487 try tree.renderError(parse_err, msg.writer(gpa));
1352513488 try astgen.appendErrorTokNotesOff(parse_err.token, extra_offset, "{s}", .{msg.items}, notes.items);
1352613489}
13490
13491const DeclarationName = union(enum) {
13492 named: Ast.TokenIndex,
13493 named_test: Ast.TokenIndex,
13494 unnamed_test,
13495 decltest: Zir.NullTerminatedString,
13496 @"comptime",
13497 @"usingnamespace",
13498};
13499
13500/// Sets all extra data for a `declaration` instruction.
13501/// Unstacks `value_gz`, `align_gz`, `linksection_gz`, and `addrspace_gz`.
13502fn setDeclaration(
13503 decl_inst: Zir.Inst.Index,
13504 src_hash: std.zig.SrcHash,
13505 name: DeclarationName,
13506 line_offset: u32,
13507 is_pub: bool,
13508 is_export: bool,
13509 doc_comment: Zir.NullTerminatedString,
13510 value_gz: *GenZir,
13511 /// May be `null` if all these blocks would be empty.
13512 /// If `null`, then `value_gz` must have nothing stacked on it.
13513 extra_gzs: ?struct {
13514 /// Must be stacked on `value_gz`.
13515 align_gz: *GenZir,
13516 /// Must be stacked on `align_gz`.
13517 linksection_gz: *GenZir,
13518 /// Must be stacked on `linksection_gz`, and have nothing stacked on it.
13519 addrspace_gz: *GenZir,
13520 },
13521) !void {
13522 const astgen = value_gz.astgen;
13523 const gpa = astgen.gpa;
13524
13525 const empty_body: []Zir.Inst.Index = &.{};
13526 const value_body, const align_body, const linksection_body, const addrspace_body = if (extra_gzs) |e| .{
13527 value_gz.instructionsSliceUpto(e.align_gz),
13528 e.align_gz.instructionsSliceUpto(e.linksection_gz),
13529 e.linksection_gz.instructionsSliceUpto(e.addrspace_gz),
13530 e.addrspace_gz.instructionsSlice(),
13531 } else .{ value_gz.instructionsSlice(), empty_body, empty_body, empty_body };
13532
13533 const value_len = astgen.countBodyLenAfterFixups(value_body);
13534 const align_len = astgen.countBodyLenAfterFixups(align_body);
13535 const linksection_len = astgen.countBodyLenAfterFixups(linksection_body);
13536 const addrspace_len = astgen.countBodyLenAfterFixups(addrspace_body);
13537
13538 const true_doc_comment: Zir.NullTerminatedString = switch (name) {
13539 .decltest => |test_name| test_name,
13540 else => doc_comment,
13541 };
13542
13543 const src_hash_arr: [4]u32 = @bitCast(src_hash);
13544
13545 const extra: Zir.Inst.Declaration = .{
13546 .src_hash_0 = src_hash_arr[0],
13547 .src_hash_1 = src_hash_arr[1],
13548 .src_hash_2 = src_hash_arr[2],
13549 .src_hash_3 = src_hash_arr[3],
13550 .name = switch (name) {
13551 .named => |tok| @enumFromInt(@intFromEnum(try astgen.identAsString(tok))),
13552 .named_test => |tok| @enumFromInt(@intFromEnum(try astgen.testNameString(tok))),
13553 .unnamed_test => .unnamed_test,
13554 .decltest => .decltest,
13555 .@"comptime" => .@"comptime",
13556 .@"usingnamespace" => .@"usingnamespace",
13557 },
13558 .line_offset = line_offset,
13559 .flags = .{
13560 .value_body_len = @intCast(value_len),
13561 .is_pub = is_pub,
13562 .is_export = is_export,
13563 .has_doc_comment = true_doc_comment != .empty,
13564 .has_align_linksection_addrspace = align_len != 0 or linksection_len != 0 or addrspace_len != 0,
13565 },
13566 };
13567 astgen.instructions.items(.data)[@intFromEnum(decl_inst)].pl_node.payload_index = try astgen.addExtra(extra);
13568 if (extra.flags.has_doc_comment) {
13569 try astgen.extra.append(gpa, @intFromEnum(true_doc_comment));
13570 }
13571 if (extra.flags.has_align_linksection_addrspace) {
13572 try astgen.extra.appendSlice(gpa, &.{
13573 align_len,
13574 linksection_len,
13575 addrspace_len,
13576 });
13577 }
13578 try astgen.extra.ensureUnusedCapacity(gpa, value_len + align_len + linksection_len + addrspace_len);
13579 astgen.appendBodyWithFixups(value_body);
13580 if (extra.flags.has_align_linksection_addrspace) {
13581 astgen.appendBodyWithFixups(align_body);
13582 astgen.appendBodyWithFixups(linksection_body);
13583 astgen.appendBodyWithFixups(addrspace_body);
13584 }
13585
13586 if (extra_gzs) |e| {
13587 e.addrspace_gz.unstack();
13588 e.linksection_gz.unstack();
13589 e.align_gz.unstack();
13590 }
13591 value_gz.unstack();
13592}
src/Autodoc.zig+119-183
......@@ -2846,22 +2846,14 @@ fn walkInstruction(
28462846 return res;
28472847 },
28482848 .block_inline => {
2849 return self.walkRef(
2849 const pl_node = data[@intFromEnum(inst)].pl_node;
2850 const extra = file.zir.extraData(Zir.Inst.Block, pl_node.payload_index);
2851 return self.walkInlineBody(
28502852 file,
28512853 parent_scope,
2854 try self.srcLocInfo(file, pl_node.src_node, parent_src),
28522855 parent_src,
2853 getBlockInlineBreak(file.zir, inst) orelse {
2854 const res = DocData.WalkResult{
2855 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
2856 .expr = .{ .comptimeExpr = self.comptime_exprs.items.len },
2857 };
2858 const pl_node = data[@intFromEnum(inst)].pl_node;
2859 const block_inline_expr = try self.getBlockSource(file, parent_src, pl_node.src_node);
2860 try self.comptime_exprs.append(self.arena, .{
2861 .code = block_inline_expr,
2862 });
2863 return res;
2864 },
2856 file.zir.bodySlice(extra.end, extra.data.body_len),
28652857 need_type,
28662858 call_ctx,
28672859 );
......@@ -4084,19 +4076,11 @@ fn analyzeAllDecls(
40844076 // First loop to discover decl names
40854077 {
40864078 var it = original_it;
4087 while (it.next()) |d| {
4088 const decl_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[@intFromEnum(d.sub_index) + 5]);
4089 switch (decl_name_index) {
4090 .empty,
4091 .unnamed_test_decl,
4092 .decltest,
4093 => continue,
4094 _ => if (file.zir.nullTerminatedString(decl_name_index).len == 0) {
4095 continue;
4096 },
4097 }
4098
4099 try scope.insertDeclRef(self.arena, decl_name_index, .Pending);
4079 while (it.next()) |zir_index| {
4080 const declaration, _ = file.zir.getDeclaration(zir_index);
4081 if (declaration.name.isNamedTest(file.zir)) continue;
4082 const decl_name = declaration.name.toString(file.zir) orelse continue;
4083 try scope.insertDeclRef(self.arena, decl_name, .Pending);
41004084 }
41014085 }
41024086
......@@ -4104,147 +4088,114 @@ fn analyzeAllDecls(
41044088 {
41054089 var it = original_it;
41064090 var decl_indexes_slot = first_decl_indexes_slot;
4107 while (it.next()) |d| : (decl_indexes_slot += 1) {
4108 const decl_name_index = file.zir.extra[@intFromEnum(d.sub_index) + 5];
4109 switch (decl_name_index) {
4110 0 => {
4111 const is_exported = @as(u1, @truncate(d.flags >> 1));
4112 switch (is_exported) {
4113 0 => continue, // comptime decl
4114 1 => {
4115 try self.analyzeUsingnamespaceDecl(
4116 file,
4117 scope,
4118 parent_src,
4119 decl_indexes,
4120 priv_decl_indexes,
4121 d,
4122 call_ctx,
4123 );
4124 },
4125 }
4126 },
4127 else => continue,
4128 }
4091 while (it.next()) |zir_index| : (decl_indexes_slot += 1) {
4092 const pl_node = file.zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
4093 const extra = file.zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
4094 if (extra.data.name != .@"usingnamespace") continue;
4095 try self.analyzeUsingnamespaceDecl(
4096 file,
4097 scope,
4098 try self.srcLocInfo(file, pl_node.src_node, parent_src),
4099 decl_indexes,
4100 priv_decl_indexes,
4101 extra.data,
4102 @intCast(extra.end),
4103 call_ctx,
4104 );
41294105 }
41304106 }
41314107
41324108 // Third loop to analyze all remaining decls
4133 var it = original_it;
4134 while (it.next()) |d| {
4135 const decl_name_index = file.zir.extra[@intFromEnum(d.sub_index) + 5];
4136 switch (decl_name_index) {
4137 0, 1 => continue, // skip over usingnamespace decls
4138 2 => continue, // skip decltests
4139
4140 else => if (file.zir.string_bytes[decl_name_index] == 0) {
4141 continue;
4142 },
4109 {
4110 var it = original_it;
4111 while (it.next()) |zir_index| {
4112 const pl_node = file.zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
4113 const extra = file.zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
4114 switch (extra.data.name) {
4115 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
4116 _ => if (extra.data.name.isNamedTest(file.zir)) continue,
4117 }
4118 try self.analyzeDecl(
4119 file,
4120 scope,
4121 try self.srcLocInfo(file, pl_node.src_node, parent_src),
4122 decl_indexes,
4123 priv_decl_indexes,
4124 zir_index,
4125 extra.data,
4126 @intCast(extra.end),
4127 call_ctx,
4128 );
41434129 }
4144
4145 try self.analyzeDecl(
4146 file,
4147 scope,
4148 parent_src,
4149 decl_indexes,
4150 priv_decl_indexes,
4151 d,
4152 call_ctx,
4153 );
41544130 }
41554131
41564132 // Fourth loop to analyze decltests
4157 it = original_it;
4158 while (it.next()) |d| {
4159 const decl_name_index = file.zir.extra[@intFromEnum(d.sub_index) + 5];
4160 switch (decl_name_index) {
4161 0, 1 => continue, // skip over usingnamespace decls
4162 2 => {},
4163 else => continue, // skip tests and normal decls
4164 }
4165
4133 var it = original_it;
4134 while (it.next()) |zir_index| {
4135 const pl_node = file.zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
4136 const extra = file.zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
4137 if (extra.data.name != .decltest) continue;
41664138 try self.analyzeDecltest(
41674139 file,
41684140 scope,
4169 parent_src,
4170 d,
4141 try self.srcLocInfo(file, pl_node.src_node, parent_src),
4142 extra.data,
4143 @intCast(extra.end),
41714144 );
41724145 }
41734146
41744147 return it.extra_index;
41754148}
41764149
4150fn walkInlineBody(
4151 autodoc: *Autodoc,
4152 file: *File,
4153 scope: *Scope,
4154 block_src: SrcLocInfo,
4155 parent_src: SrcLocInfo,
4156 body: []const Zir.Inst.Index,
4157 need_type: bool,
4158 call_ctx: ?*const CallContext,
4159) AutodocErrors!DocData.WalkResult {
4160 const tags = file.zir.instructions.items(.tag);
4161 const break_inst = switch (tags[@intFromEnum(body[body.len - 1])]) {
4162 .condbr_inline => {
4163 // Unresolvable.
4164 const res: DocData.WalkResult = .{
4165 .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
4166 .expr = .{ .comptimeExpr = autodoc.comptime_exprs.items.len },
4167 };
4168 const source = (try file.getTree(autodoc.zcu.gpa)).getNodeSource(block_src.src_node);
4169 try autodoc.comptime_exprs.append(autodoc.arena, .{
4170 .code = source,
4171 });
4172 return res;
4173 },
4174 .break_inline => body[body.len - 1],
4175 else => unreachable,
4176 };
4177 const break_data = file.zir.instructions.items(.data)[@intFromEnum(break_inst)].@"break";
4178 return autodoc.walkRef(file, scope, parent_src, break_data.operand, need_type, call_ctx);
4179}
4180
41774181// Asserts the given decl is public
41784182fn analyzeDecl(
41794183 self: *Autodoc,
41804184 file: *File,
41814185 scope: *Scope,
4182 parent_src: SrcLocInfo,
4186 decl_src: SrcLocInfo,
41834187 decl_indexes: *std.ArrayListUnmanaged(usize),
41844188 priv_decl_indexes: *std.ArrayListUnmanaged(usize),
4185 d: Zir.DeclIterator.Item,
4189 decl_inst: Zir.Inst.Index,
4190 declaration: Zir.Inst.Declaration,
4191 extra_index: u32,
41864192 call_ctx: ?*const CallContext,
41874193) AutodocErrors!void {
4188 const data = file.zir.instructions.items(.data);
4189 const is_pub = @as(u1, @truncate(d.flags >> 0)) != 0;
4190 // const is_exported = @truncate(u1, d.flags >> 1) != 0;
4191 const has_align = @as(u1, @truncate(d.flags >> 2)) != 0;
4192 const has_section_or_addrspace = @as(u1, @truncate(d.flags >> 3)) != 0;
4193
4194 var extra_index = @intFromEnum(d.sub_index);
4195 // const hash_u32s = file.zir.extra[extra_index..][0..4];
4196
4197 extra_index += 4;
4198 // const line = file.zir.extra[extra_index];
4199
4200 extra_index += 1;
4201 const decl_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
4202
4203 extra_index += 1;
4204 const value_index: Zir.Inst.Index = @enumFromInt(file.zir.extra[extra_index]);
4205
4206 extra_index += 1;
4207 const doc_comment_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
4208
4209 extra_index += 1;
4210 const align_inst: Zir.Inst.Ref = if (!has_align) .none else inst: {
4211 const inst: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
4212 extra_index += 1;
4213 break :inst inst;
4214 };
4215 _ = align_inst;
4216
4217 const section_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
4218 const inst: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
4219 extra_index += 1;
4220 break :inst inst;
4221 };
4222 _ = section_inst;
4194 const bodies = declaration.getBodies(extra_index, file.zir);
4195 const name = file.zir.nullTerminatedString(declaration.name.toString(file.zir).?);
42234196
4224 const addrspace_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
4225 const inst: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
4226 extra_index += 1;
4227 break :inst inst;
4228 };
4229 _ = addrspace_inst;
4230
4231 // This is known to work because decl values are always block_inlines
4232 const value_pl_node = data[@intFromEnum(value_index)].pl_node;
4233 const decl_src = try self.srcLocInfo(file, value_pl_node.src_node, parent_src);
4234
4235 const name: []const u8 = switch (decl_name_index) {
4236 .empty, .unnamed_test_decl, .decltest => unreachable,
4237 _ => blk: {
4238 if (decl_name_index == .empty) {
4239 // test decl
4240 unreachable;
4241 }
4242 break :blk file.zir.nullTerminatedString(decl_name_index);
4243 },
4244 };
4245
4246 const doc_comment: ?[]const u8 = if (doc_comment_index != .empty)
4247 file.zir.nullTerminatedString(doc_comment_index)
4197 const doc_comment: ?[]const u8 = if (declaration.flags.has_doc_comment)
4198 file.zir.nullTerminatedString(@enumFromInt(file.zir.extra[extra_index]))
42484199 else
42494200 null;
42504201
......@@ -4261,16 +4212,22 @@ fn analyzeDecl(
42614212 break :idx idx;
42624213 };
42634214
4264 const walk_result = try self.walkInstruction(
4215 const walk_result = try self.walkInlineBody(
42654216 file,
42664217 scope,
42674218 decl_src,
4268 value_index,
4219 decl_src,
4220 bodies.value_body,
42694221 true,
42704222 call_ctx,
42714223 );
42724224
4273 const kind: []const u8 = if (try self.declIsVar(file, value_pl_node.src_node, parent_src)) "var" else "const";
4225 const tree = try file.getTree(self.zcu.gpa);
4226 const kind_token = tree.nodes.items(.main_token)[decl_src.src_node];
4227 const kind: []const u8 = switch (tree.tokens.items(.tag)[kind_token]) {
4228 .keyword_var => "var",
4229 else => "const",
4230 };
42744231
42754232 const decls_slot_index = self.decls.items.len;
42764233 try self.decls.append(self.arena, .{
......@@ -4281,13 +4238,13 @@ fn analyzeDecl(
42814238 .parent_container = scope.enclosing_type,
42824239 });
42834240
4284 if (is_pub) {
4241 if (declaration.flags.is_pub) {
42854242 try decl_indexes.append(self.arena, decls_slot_index);
42864243 } else {
42874244 try priv_decl_indexes.append(self.arena, decls_slot_index);
42884245 }
42894246
4290 const decl_status_ptr = scope.resolveDeclName(decl_name_index, file, .none);
4247 const decl_status_ptr = scope.resolveDeclName(declaration.name.toString(file.zir).?, file, .none);
42914248 std.debug.assert(decl_status_ptr.* == .Pending);
42924249 decl_status_ptr.* = .{ .Analyzed = decls_slot_index };
42934250
......@@ -4296,7 +4253,7 @@ fn analyzeDecl(
42964253 for (paths.items) |resume_info| {
42974254 try self.tryResolveRefPath(
42984255 resume_info.file,
4299 value_index,
4256 decl_inst,
43004257 resume_info.ref_path,
43014258 );
43024259 }
......@@ -4312,24 +4269,17 @@ fn analyzeUsingnamespaceDecl(
43124269 self: *Autodoc,
43134270 file: *File,
43144271 scope: *Scope,
4315 parent_src: SrcLocInfo,
4272 decl_src: SrcLocInfo,
43164273 decl_indexes: *std.ArrayListUnmanaged(usize),
43174274 priv_decl_indexes: *std.ArrayListUnmanaged(usize),
4318 d: Zir.DeclIterator.Item,
4275 declaration: Zir.Inst.Declaration,
4276 extra_index: u32,
43194277 call_ctx: ?*const CallContext,
43204278) AutodocErrors!void {
4321 const data = file.zir.instructions.items(.data);
4279 const bodies = declaration.getBodies(extra_index, file.zir);
43224280
4323 const is_pub = @as(u1, @truncate(d.flags)) != 0;
4324 const value_index: Zir.Inst.Index = @enumFromInt(file.zir.extra[@intFromEnum(d.sub_index) + 6]);
4325 const doc_comment_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[@intFromEnum(d.sub_index) + 7]);
4326
4327 // This is known to work because decl values are always block_inlines
4328 const value_pl_node = data[@intFromEnum(value_index)].pl_node;
4329 const decl_src = try self.srcLocInfo(file, value_pl_node.src_node, parent_src);
4330
4331 const doc_comment: ?[]const u8 = if (doc_comment_index != .empty)
4332 file.zir.nullTerminatedString(doc_comment_index)
4281 const doc_comment: ?[]const u8 = if (declaration.flags.has_doc_comment)
4282 file.zir.nullTerminatedString(@enumFromInt(file.zir.extra[extra_index]))
43334283 else
43344284 null;
43354285
......@@ -4346,11 +4296,12 @@ fn analyzeUsingnamespaceDecl(
43464296 break :idx idx;
43474297 };
43484298
4349 const walk_result = try self.walkInstruction(
4299 const walk_result = try self.walkInlineBody(
43504300 file,
43514301 scope,
43524302 decl_src,
4353 value_index,
4303 decl_src,
4304 bodies.value_body,
43544305 true,
43554306 call_ctx,
43564307 );
......@@ -4365,7 +4316,7 @@ fn analyzeUsingnamespaceDecl(
43654316 .parent_container = scope.enclosing_type,
43664317 });
43674318
4368 if (is_pub) {
4319 if (declaration.flags.is_pub) {
43694320 try decl_indexes.append(self.arena, decl_slot_index);
43704321 } else {
43714322 try priv_decl_indexes.append(self.arena, decl_slot_index);
......@@ -4376,18 +4327,14 @@ fn analyzeDecltest(
43764327 self: *Autodoc,
43774328 file: *File,
43784329 scope: *Scope,
4379 parent_src: SrcLocInfo,
4380 d: Zir.DeclIterator.Item,
4330 decl_src: SrcLocInfo,
4331 declaration: Zir.Inst.Declaration,
4332 extra_index: u32,
43814333) AutodocErrors!void {
4382 const data = file.zir.instructions.items(.data);
4383
4384 const value_index = file.zir.extra[@intFromEnum(d.sub_index) + 6];
4385 const decl_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[@intFromEnum(d.sub_index) + 7]);
4386
4387 const value_pl_node = data[value_index].pl_node;
4388 const decl_src = try self.srcLocInfo(file, value_pl_node.src_node, parent_src);
4334 std.debug.assert(declaration.flags.has_doc_comment);
4335 const decl_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
43894336
4390 const test_source_code = try self.getBlockSource(file, parent_src, value_pl_node.src_node);
4337 const test_source_code = (try file.getTree(self.zcu.gpa)).getNodeSource(decl_src.src_node);
43914338
43924339 const decl_name: ?[]const u8 = if (decl_name_index != .empty)
43934340 file.zir.nullTerminatedString(decl_name_index)
......@@ -5830,17 +5777,6 @@ fn walkRef(
58305777 }
58315778}
58325779
5833fn getBlockInlineBreak(zir: Zir, inst: Zir.Inst.Index) ?Zir.Inst.Ref {
5834 const tags = zir.instructions.items(.tag);
5835 const data = zir.instructions.items(.data);
5836 const pl_node = data[@intFromEnum(inst)].pl_node;
5837 const extra = zir.extraData(Zir.Inst.Block, pl_node.payload_index);
5838 const break_index = zir.extra[extra.end..][extra.data.body_len - 1];
5839 if (tags[break_index] == .condbr_inline) return null;
5840 std.debug.assert(tags[break_index] == .break_inline);
5841 return data[break_index].@"break".operand;
5842}
5843
58445780fn printWithContext(
58455781 file: *File,
58465782 inst: Zir.Inst.Index,
src/Compilation.zig+4-1
......@@ -2802,6 +2802,7 @@ const Header = extern struct {
28022802 extra_len: u32,
28032803 limbs_len: u32,
28042804 string_bytes_len: u32,
2805 tracked_insts_len: u32,
28052806 },
28062807};
28072808
......@@ -2809,7 +2810,7 @@ const Header = extern struct {
28092810/// saved, such as the target and most CLI flags. A cache hit will only occur
28102811/// when subsequent compiler invocations use the same set of flags.
28112812pub fn saveState(comp: *Compilation) !void {
2812 var bufs_list: [6]std.os.iovec_const = undefined;
2813 var bufs_list: [7]std.os.iovec_const = undefined;
28132814 var bufs_len: usize = 0;
28142815
28152816 const lf = comp.bin_file orelse return;
......@@ -2822,6 +2823,7 @@ pub fn saveState(comp: *Compilation) !void {
28222823 .extra_len = @intCast(ip.extra.items.len),
28232824 .limbs_len = @intCast(ip.limbs.items.len),
28242825 .string_bytes_len = @intCast(ip.string_bytes.items.len),
2826 .tracked_insts_len = @intCast(ip.tracked_insts.count()),
28252827 },
28262828 };
28272829 addBuf(&bufs_list, &bufs_len, mem.asBytes(&header));
......@@ -2830,6 +2832,7 @@ pub fn saveState(comp: *Compilation) !void {
28302832 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.items.items(.data)));
28312833 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.items.items(.tag)));
28322834 addBuf(&bufs_list, &bufs_len, ip.string_bytes.items);
2835 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.tracked_insts.keys()));
28332836
28342837 // TODO: compilation errors
28352838 // TODO: files
src/InternPool.zig+51-21
......@@ -54,6 +54,34 @@ string_table: std.HashMapUnmanaged(
5454 std.hash_map.default_max_load_percentage,
5555) = .{},
5656
57/// An index into `tracked_insts` gives a reference to a single ZIR instruction which
58/// persists across incremental updates.
59tracked_insts: std.AutoArrayHashMapUnmanaged(TrackedInst, void) = .{},
60
61pub const TrackedInst = extern struct {
62 path_digest: Cache.BinDigest,
63 inst: Zir.Inst.Index,
64 comptime {
65 // The fields should be tightly packed. See also serialiation logic in `Compilation.saveState`.
66 assert(@sizeOf(@This()) == Cache.bin_digest_len + @sizeOf(Zir.Inst.Index));
67 }
68 pub const Index = enum(u32) {
69 _,
70 pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) Zir.Inst.Index {
71 return ip.tracked_insts.keys()[@intFromEnum(i)].inst;
72 }
73 };
74};
75
76pub fn trackZir(ip: *InternPool, gpa: Allocator, file: *Module.File, inst: Zir.Inst.Index) Allocator.Error!TrackedInst.Index {
77 const key: TrackedInst = .{
78 .path_digest = file.path_digest,
79 .inst = inst,
80 };
81 const gop = try ip.tracked_insts.getOrPut(gpa, key);
82 return @enumFromInt(gop.index);
83}
84
5785const FieldMap = std.ArrayHashMapUnmanaged(void, void, std.array_hash_map.AutoContext(void), false);
5886
5987const builtin = @import("builtin");
......@@ -62,11 +90,13 @@ const Allocator = std.mem.Allocator;
6290const assert = std.debug.assert;
6391const BigIntConst = std.math.big.int.Const;
6492const BigIntMutable = std.math.big.int.Mutable;
93const Cache = std.Build.Cache;
6594const Limb = std.math.big.Limb;
6695const Hash = std.hash.Wyhash;
6796
6897const InternPool = @This();
6998const Module = @import("Module.zig");
99const Zcu = Module;
70100const Zir = @import("Zir.zig");
71101
72102const KeyAdapter = struct {
......@@ -409,7 +439,7 @@ pub const Key = union(enum) {
409439 /// `none` when the struct has no declarations.
410440 namespace: OptionalNamespaceIndex,
411441 /// Index of the struct_decl ZIR instruction.
412 zir_index: Zir.Inst.Index,
442 zir_index: TrackedInst.Index,
413443 layout: std.builtin.Type.ContainerLayout,
414444 field_names: NullTerminatedString.Slice,
415445 field_types: Index.Slice,
......@@ -653,7 +683,7 @@ pub const Key = union(enum) {
653683 }
654684
655685 /// Asserts the struct is not packed.
656 pub fn setZirIndex(s: @This(), ip: *InternPool, new_zir_index: Zir.Inst.Index) void {
686 pub fn setZirIndex(s: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index) void {
657687 assert(s.layout != .Packed);
658688 const field_index = std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?;
659689 ip.extra.items[s.extra_index + field_index] = @intFromEnum(new_zir_index);
......@@ -769,7 +799,7 @@ pub const Key = union(enum) {
769799 flags: Tag.TypeUnion.Flags,
770800 /// The enum that provides the list of field names and values.
771801 enum_tag_ty: Index,
772 zir_index: Zir.Inst.Index,
802 zir_index: TrackedInst.Index,
773803
774804 /// The returned pointer expires with any addition to the `InternPool`.
775805 pub fn flagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeUnion.Flags {
......@@ -1056,7 +1086,7 @@ pub const Key = union(enum) {
10561086 /// the body. We store this rather than the body directly so that when ZIR
10571087 /// is regenerated on update(), we can map this to the new corresponding
10581088 /// ZIR instruction.
1059 zir_body_inst: Zir.Inst.Index,
1089 zir_body_inst: TrackedInst.Index,
10601090 /// Relative to owner Decl.
10611091 lbrace_line: u32,
10621092 /// Relative to owner Decl.
......@@ -1082,7 +1112,7 @@ pub const Key = union(enum) {
10821112 }
10831113
10841114 /// Returns a pointer that becomes invalid after any additions to the `InternPool`.
1085 pub fn zirBodyInst(func: *const Func, ip: *const InternPool) *Zir.Inst.Index {
1115 pub fn zirBodyInst(func: *const Func, ip: *const InternPool) *TrackedInst.Index {
10861116 return @ptrCast(&ip.extra.items[func.zir_body_inst_extra_index]);
10871117 }
10881118
......@@ -1860,7 +1890,7 @@ pub const UnionType = struct {
18601890 /// If this slice has length 0 it means all elements are `none`.
18611891 field_aligns: Alignment.Slice,
18621892 /// Index of the union_decl ZIR instruction.
1863 zir_index: Zir.Inst.Index,
1893 zir_index: TrackedInst.Index,
18641894 /// Index into extra array of the `flags` field.
18651895 flags_index: u32,
18661896 /// Copied from `enum_tag_ty`.
......@@ -1954,10 +1984,10 @@ pub const UnionType = struct {
19541984 }
19551985
19561986 /// This does not mutate the field of UnionType.
1957 pub fn setZirIndex(self: @This(), ip: *InternPool, new_zir_index: Zir.Inst.Index) void {
1987 pub fn setZirIndex(self: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index) void {
19581988 const flags_field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;
19591989 const zir_index_field_index = std.meta.fieldIndex(Tag.TypeUnion, "zir_index").?;
1960 const ptr: *Zir.Inst.Index =
1990 const ptr: *TrackedInst.Index =
19611991 @ptrCast(&ip.extra.items[self.flags_index - flags_field_index + zir_index_field_index]);
19621992 ptr.* = new_zir_index;
19631993 }
......@@ -2976,7 +3006,7 @@ pub const Tag = enum(u8) {
29763006 analysis: FuncAnalysis,
29773007 owner_decl: DeclIndex,
29783008 ty: Index,
2979 zir_body_inst: Zir.Inst.Index,
3009 zir_body_inst: TrackedInst.Index,
29803010 lbrace_line: u32,
29813011 rbrace_line: u32,
29823012 lbrace_column: u32,
......@@ -3050,7 +3080,7 @@ pub const Tag = enum(u8) {
30503080 namespace: NamespaceIndex,
30513081 /// The enum that provides the list of field names and values.
30523082 tag_ty: Index,
3053 zir_index: Zir.Inst.Index,
3083 zir_index: TrackedInst.Index,
30543084
30553085 pub const Flags = packed struct(u32) {
30563086 runtime_tag: UnionType.RuntimeTag,
......@@ -3072,7 +3102,7 @@ pub const Tag = enum(u8) {
30723102 /// 2. init: Index for each fields_len // if tag is type_struct_packed_inits
30733103 pub const TypeStructPacked = struct {
30743104 decl: DeclIndex,
3075 zir_index: Zir.Inst.Index,
3105 zir_index: TrackedInst.Index,
30763106 fields_len: u32,
30773107 namespace: OptionalNamespaceIndex,
30783108 backing_int_ty: Index,
......@@ -3119,7 +3149,7 @@ pub const Tag = enum(u8) {
31193149 /// 7. field_offset: u32 // for each field in declared order, undef until layout_resolved
31203150 pub const TypeStruct = struct {
31213151 decl: DeclIndex,
3122 zir_index: Zir.Inst.Index,
3152 zir_index: TrackedInst.Index,
31233153 fields_len: u32,
31243154 flags: Flags,
31253155 size: u32,
......@@ -3708,6 +3738,8 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
37083738
37093739 ip.string_table.deinit(gpa);
37103740
3741 ip.tracked_insts.deinit(gpa);
3742
37113743 ip.* = undefined;
37123744}
37133745
......@@ -5358,7 +5390,7 @@ pub const UnionTypeInit = struct {
53585390 flags: Tag.TypeUnion.Flags,
53595391 decl: DeclIndex,
53605392 namespace: NamespaceIndex,
5361 zir_index: Zir.Inst.Index,
5393 zir_index: TrackedInst.Index,
53625394 fields_len: u32,
53635395 enum_tag_ty: Index,
53645396 /// May have length 0 which leaves the values unset until later.
......@@ -5430,7 +5462,7 @@ pub const StructTypeInit = struct {
54305462 decl: DeclIndex,
54315463 namespace: OptionalNamespaceIndex,
54325464 layout: std.builtin.Type.ContainerLayout,
5433 zir_index: Zir.Inst.Index,
5465 zir_index: TrackedInst.Index,
54345466 fields_len: u32,
54355467 known_non_opv: bool,
54365468 requires_comptime: RequiresComptime,
......@@ -5704,7 +5736,7 @@ pub fn getExternFunc(ip: *InternPool, gpa: Allocator, key: Key.ExternFunc) Alloc
57045736pub const GetFuncDeclKey = struct {
57055737 owner_decl: DeclIndex,
57065738 ty: Index,
5707 zir_body_inst: Zir.Inst.Index,
5739 zir_body_inst: TrackedInst.Index,
57085740 lbrace_line: u32,
57095741 rbrace_line: u32,
57105742 lbrace_column: u32,
......@@ -5773,7 +5805,7 @@ pub const GetFuncDeclIesKey = struct {
57735805 is_var_args: bool,
57745806 is_generic: bool,
57755807 is_noinline: bool,
5776 zir_body_inst: Zir.Inst.Index,
5808 zir_body_inst: TrackedInst.Index,
57775809 lbrace_line: u32,
57785810 rbrace_line: u32,
57795811 lbrace_column: u32,
......@@ -6186,8 +6218,6 @@ fn finishFuncInstance(
61866218 .generation = generation,
61876219 .is_pub = fn_owner_decl.is_pub,
61886220 .is_exported = fn_owner_decl.is_exported,
6189 .has_linksection_or_addrspace = fn_owner_decl.has_linksection_or_addrspace,
6190 .has_align = fn_owner_decl.has_align,
61916221 .alive = true,
61926222 .kind = .anon,
61936223 });
......@@ -6537,7 +6567,7 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
65376567 NullTerminatedString,
65386568 OptionalNullTerminatedString,
65396569 Tag.TypePointer.VectorIndex,
6540 Zir.Inst.Index,
6570 TrackedInst.Index,
65416571 => @intFromEnum(@field(extra, field.name)),
65426572
65436573 u32,
......@@ -6613,7 +6643,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct
66136643 NullTerminatedString,
66146644 OptionalNullTerminatedString,
66156645 Tag.TypePointer.VectorIndex,
6616 Zir.Inst.Index,
6646 TrackedInst.Index,
66176647 => @enumFromInt(int32),
66186648
66196649 u32,
......@@ -8319,7 +8349,7 @@ pub fn funcHasInferredErrorSet(ip: *const InternPool, i: Index) bool {
83198349 return funcAnalysis(ip, i).inferred_error_set;
83208350}
83218351
8322pub fn funcZirBodyInst(ip: *const InternPool, i: Index) Zir.Inst.Index {
8352pub fn funcZirBodyInst(ip: *const InternPool, i: Index) TrackedInst.Index {
83238353 assert(i != .none);
83248354 const item = ip.items.get(@intFromEnum(i));
83258355 const zir_body_inst_field_index = std.meta.fieldIndex(Tag.FuncDecl, "zir_body_inst").?;
src/Module.zig+246-342
......@@ -386,11 +386,9 @@ pub const Decl = struct {
386386 /// do not need to be loaded into memory in order to compute debug line numbers.
387387 /// This value is absolute.
388388 src_line: u32,
389 /// Index to ZIR `extra` array to the entry in the parent's decl structure
390 /// (the part that says "for every decls_len"). The first item at this index is
391 /// the contents hash, followed by line, name, etc.
392 /// For anonymous decls and also the root Decl for a File, this is `none`.
393 zir_decl_index: Zir.OptionalExtraIndex,
389 /// Index of the ZIR `declaration` instruction from which this `Decl` was created.
390 /// For the root `Decl` of a `File` and legacy anonymous decls, this is `.none`.
391 zir_decl_index: Zir.Inst.OptionalIndex,
394392
395393 /// Represents the "shallow" analysis status. For example, for decls that are functions,
396394 /// the function type is analyzed with this set to `in_progress`, however, the semantic
......@@ -442,10 +440,6 @@ pub const Decl = struct {
442440 is_pub: bool,
443441 /// Whether the corresponding AST decl has a `export` keyword.
444442 is_exported: bool,
445 /// Whether the ZIR code provides an align instruction.
446 has_align: bool,
447 /// Whether the ZIR code provides a linksection and address space instruction.
448 has_linksection_or_addrspace: bool,
449443 /// Flag used by garbage collection to mark and sweep.
450444 /// Decls which correspond to an AST node always have this field set to `true`.
451445 /// Anonymous Decls are initialized with this field set to `false` and then it
......@@ -471,81 +465,19 @@ pub const Decl = struct {
471465 const Index = InternPool.DeclIndex;
472466 const OptionalIndex = InternPool.OptionalDeclIndex;
473467
474 pub const DepsTable = std.AutoArrayHashMapUnmanaged(Decl.Index, DepType);
475
476 /// Later types take priority; e.g. if a dependent decl has both `normal`
477 /// and `function_body` dependencies on another decl, it will be marked as
478 /// having a `function_body` dependency.
479 pub const DepType = enum {
480 /// The dependent references or uses the dependency's value, so must be
481 /// updated whenever it is changed. However, if the dependency is a
482 /// function and its type is unchanged, the dependent does not need to
483 /// be updated.
484 normal,
485 /// The dependent performs an inline or comptime call to the dependency,
486 /// or is a generic instantiation of it. It must therefore be updated
487 /// whenever the dependency is updated, even if the function type
488 /// remained the same.
489 function_body,
490 };
491
492 /// This name is relative to the containing namespace of the decl.
493 /// The memory is owned by the containing File ZIR.
494 pub fn getName(decl: Decl, mod: *Module) ?[:0]const u8 {
495 const zir = decl.getFileScope(mod).zir;
496 return decl.getNameZir(zir);
497 }
498
499 pub fn getNameZir(decl: Decl, zir: Zir) ?[:0]const u8 {
500 assert(decl.zir_decl_index != .none);
501 const name_index = zir.extra[@intFromEnum(decl.zir_decl_index) + 5];
502 if (name_index <= 1) return null;
503 return zir.nullTerminatedString(name_index);
468 /// Asserts that `zir_decl_index` is not `.none`.
469 fn getDeclaration(decl: Decl, zir: Zir) Zir.Inst.Declaration {
470 const zir_index = decl.zir_decl_index.unwrap().?;
471 const pl_node = zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
472 return zir.extraData(Zir.Inst.Declaration, pl_node.payload_index).data;
504473 }
505474
506 pub fn contentsHash(decl: Decl, mod: *Module) std.zig.SrcHash {
507 const zir = decl.getFileScope(mod).zir;
508 return decl.contentsHashZir(zir);
509 }
510
511 pub fn contentsHashZir(decl: Decl, zir: Zir) std.zig.SrcHash {
512 assert(decl.zir_decl_index != .none);
513 const hash_u32s = zir.extra[@intFromEnum(decl.zir_decl_index)..][0..4];
514 const contents_hash = @as(std.zig.SrcHash, @bitCast(hash_u32s.*));
515 return contents_hash;
516 }
517
518 pub fn zirBlockIndex(decl: *const Decl, mod: *Module) Zir.Inst.Index {
519 assert(decl.zir_decl_index != .none);
520 const zir = decl.getFileScope(mod).zir;
521 return @enumFromInt(zir.extra[@intFromEnum(decl.zir_decl_index) + 6]);
522 }
523
524 pub fn zirAlignRef(decl: Decl, mod: *Module) Zir.Inst.Ref {
525 if (!decl.has_align) return .none;
526 assert(decl.zir_decl_index != .none);
527 const zir = decl.getFileScope(mod).zir;
528 return @enumFromInt(zir.extra[@intFromEnum(decl.zir_decl_index) + 8]);
529 }
530
531 pub fn zirLinksectionRef(decl: Decl, mod: *Module) Zir.Inst.Ref {
532 if (!decl.has_linksection_or_addrspace) return .none;
533 assert(decl.zir_decl_index != .none);
534 const zir = decl.getFileScope(mod).zir;
535 const extra_index = @intFromEnum(decl.zir_decl_index) + 8 + @intFromBool(decl.has_align);
536 return @enumFromInt(zir.extra[extra_index]);
537 }
538
539 pub fn zirAddrspaceRef(decl: Decl, mod: *Module) Zir.Inst.Ref {
540 if (!decl.has_linksection_or_addrspace) return .none;
541 assert(decl.zir_decl_index != .none);
542 const zir = decl.getFileScope(mod).zir;
543 const extra_index = @intFromEnum(decl.zir_decl_index) + 8 + @intFromBool(decl.has_align) + 1;
544 return @enumFromInt(zir.extra[extra_index]);
545 }
546
547 pub fn relativeToLine(decl: Decl, offset: u32) u32 {
548 return decl.src_line + offset;
475 pub fn zirBodies(decl: Decl, zcu: *Zcu) Zir.Inst.Declaration.Bodies {
476 const zir = decl.getFileScope(zcu).zir;
477 const zir_index = decl.zir_decl_index.unwrap().?;
478 const pl_node = zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
479 const extra = zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
480 return extra.data.getBodies(@intCast(extra.end), zir);
549481 }
550482
551483 pub fn relativeToNodeIndex(decl: Decl, offset: i32) Ast.Node.Index {
......@@ -902,6 +834,9 @@ pub const File = struct {
902834 multi_pkg: bool = false,
903835 /// List of references to this file, used for multi-package errors.
904836 references: std.ArrayListUnmanaged(Reference) = .{},
837 /// The hash of the path to this file, used to store `InternPool.TrackedInst`.
838 /// undefined until `zir_loaded == true`.
839 path_digest: Cache.BinDigest = undefined,
905840
906841 /// Used by change detection algorithm, after astgen, contains the
907842 /// set of decls that existed in the previous ZIR but not in the new one.
......@@ -2662,7 +2597,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
26622597 const stat = try source_file.stat();
26632598
26642599 const want_local_cache = file.mod == mod.main_mod;
2665 const digest = hash: {
2600 const bin_digest = hash: {
26662601 var path_hash: Cache.HashHelper = .{};
26672602 path_hash.addBytes(build_options.version);
26682603 path_hash.add(builtin.zig_backend);
......@@ -2671,7 +2606,19 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
26712606 path_hash.addBytes(file.mod.root.sub_path);
26722607 }
26732608 path_hash.addBytes(file.sub_file_path);
2674 break :hash path_hash.final();
2609 var bin: Cache.BinDigest = undefined;
2610 path_hash.hasher.final(&bin);
2611 break :hash bin;
2612 };
2613 file.path_digest = bin_digest;
2614 const hex_digest = hex: {
2615 var hex: Cache.HexDigest = undefined;
2616 _ = std.fmt.bufPrint(
2617 &hex,
2618 "{s}",
2619 .{std.fmt.fmtSliceHexLower(&bin_digest)},
2620 ) catch unreachable;
2621 break :hex hex;
26752622 };
26762623 const cache_directory = if (want_local_cache) mod.local_zir_cache else mod.global_zir_cache;
26772624 const zir_dir = cache_directory.handle;
......@@ -2681,7 +2628,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
26812628 .never_loaded, .retryable_failure => lock: {
26822629 // First, load the cached ZIR code, if any.
26832630 log.debug("AstGen checking cache: {s} (local={}, digest={s})", .{
2684 file.sub_file_path, want_local_cache, &digest,
2631 file.sub_file_path, want_local_cache, &hex_digest,
26852632 });
26862633
26872634 break :lock .shared;
......@@ -2708,7 +2655,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
27082655 // version. Likewise if we're working on AstGen and another process asks for
27092656 // the cached file, they'll get it.
27102657 const cache_file = while (true) {
2711 break zir_dir.createFile(&digest, .{
2658 break zir_dir.createFile(&hex_digest, .{
27122659 .read = true,
27132660 .truncate = false,
27142661 .lock = lock,
......@@ -2894,7 +2841,7 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
28942841 };
28952842 cache_file.writevAll(&iovecs) catch |err| {
28962843 log.warn("unable to write cached ZIR code for {}{s} to {}{s}: {s}", .{
2897 file.mod.root, file.sub_file_path, cache_directory, &digest, @errorName(err),
2844 file.mod.root, file.sub_file_path, cache_directory, &hex_digest, @errorName(err),
28982845 });
28992846 };
29002847
......@@ -3003,93 +2950,22 @@ fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.File)
30032950 return zir;
30042951}
30052952
3006/// Patch ups:
3007/// * Struct.zir_index
3008/// * Decl.zir_index
3009/// * Fn.zir_body_inst
3010/// * Decl.zir_decl_index
3011fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {
3012 const gpa = mod.gpa;
3013 const new_zir = file.zir;
3014
3015 // The root decl will be null if the previous ZIR had AST errors.
3016 const root_decl = file.root_decl.unwrap() orelse return;
2953fn updateZirRefs(zcu: *Module, file: *File, old_zir: Zir) !void {
2954 const gpa = zcu.gpa;
30172955
3018 // Maps from old ZIR to new ZIR, struct_decl, enum_decl, etc. Any instruction which
3019 // creates a namespace, gets mapped from old to new here.
30202956 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};
30212957 defer inst_map.deinit(gpa);
3022 // Maps from old ZIR to new ZIR, the extra data index for the sub-decl item.
3023 // e.g. the thing that Decl.zir_decl_index points to.
3024 var extra_map: std.AutoHashMapUnmanaged(Zir.ExtraIndex, Zir.ExtraIndex) = .{};
3025 defer extra_map.deinit(gpa);
3026
3027 try mapOldZirToNew(gpa, old_zir, new_zir, &inst_map, &extra_map);
3028
3029 // Walk the Decl graph, updating ZIR indexes, strings, and populating
3030 // the deleted and outdated lists.
3031
3032 var decl_stack: ArrayListUnmanaged(Decl.Index) = .{};
3033 defer decl_stack.deinit(gpa);
3034
3035 try decl_stack.append(gpa, root_decl);
3036
3037 file.deleted_decls.clearRetainingCapacity();
3038 file.outdated_decls.clearRetainingCapacity();
30392958
3040 // The root decl is always outdated; otherwise we would not have had
3041 // to re-generate ZIR for the File.
3042 try file.outdated_decls.append(gpa, root_decl);
2959 try mapOldZirToNew(gpa, old_zir, file.zir, &inst_map);
30432960
3044 const ip = &mod.intern_pool;
3045
3046 while (decl_stack.popOrNull()) |decl_index| {
3047 const decl = mod.declPtr(decl_index);
3048 // Anonymous decls and the root decl have this set to 0. We still need
3049 // to walk them but we do not need to modify this value.
3050 // Anonymous decls should not be marked outdated. They will be re-generated
3051 // if their owner decl is marked outdated.
3052 if (decl.zir_decl_index.unwrap()) |old_zir_decl_index| {
3053 const new_zir_decl_index = extra_map.get(old_zir_decl_index) orelse {
3054 try file.deleted_decls.append(gpa, decl_index);
3055 continue;
3056 };
3057 const old_hash = decl.contentsHashZir(old_zir);
3058 decl.zir_decl_index = new_zir_decl_index.toOptional();
3059 const new_hash = decl.contentsHashZir(new_zir);
3060 if (!std.zig.srcHashEql(old_hash, new_hash)) {
3061 try file.outdated_decls.append(gpa, decl_index);
3062 }
3063 }
3064
3065 if (!decl.owns_tv) continue;
3066
3067 if (decl.getOwnedStruct(mod)) |struct_type| {
3068 struct_type.setZirIndex(ip, inst_map.get(struct_type.zir_index) orelse {
3069 try file.deleted_decls.append(gpa, decl_index);
3070 continue;
3071 });
3072 }
3073
3074 if (decl.getOwnedUnion(mod)) |union_type| {
3075 union_type.setZirIndex(ip, inst_map.get(union_type.zir_index) orelse {
3076 try file.deleted_decls.append(gpa, decl_index);
3077 continue;
3078 });
3079 }
3080
3081 if (decl.getOwnedFunction(mod)) |func| {
3082 func.zirBodyInst(ip).* = inst_map.get(func.zir_body_inst) orelse {
3083 try file.deleted_decls.append(gpa, decl_index);
3084 continue;
3085 };
3086 }
3087
3088 if (decl.getOwnedInnerNamespace(mod)) |namespace| {
3089 for (namespace.decls.keys()) |sub_decl| {
3090 try decl_stack.append(gpa, sub_decl);
3091 }
3092 }
2961 // TODO: this should be done after all AstGen workers complete, to avoid
2962 // iterating over this full set for every updated file.
2963 for (zcu.intern_pool.tracked_insts.keys()) |*ti| {
2964 if (!std.mem.eql(u8, &ti.path_digest, &file.path_digest)) continue;
2965 ti.inst = inst_map.get(ti.inst) orelse {
2966 // TODO: invalidate this `TrackedInst` via the dependency mechanism
2967 continue;
2968 };
30932969 }
30942970}
30952971
......@@ -3098,9 +2974,9 @@ pub fn mapOldZirToNew(
30982974 old_zir: Zir,
30992975 new_zir: Zir,
31002976 inst_map: *std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index),
3101 extra_map: *std.AutoHashMapUnmanaged(Zir.ExtraIndex, Zir.ExtraIndex),
31022977) Allocator.Error!void {
3103 // Contain ZIR indexes of declaration instructions.
2978 // Contain ZIR indexes of namespace declaration instructions, e.g. struct_decl, union_decl, etc.
2979 // Not `declaration`, as this does not create a namespace.
31042980 const MatchedZirDecl = struct {
31052981 old_inst: Zir.Inst.Index,
31062982 new_inst: Zir.Inst.Index,
......@@ -3108,47 +2984,113 @@ pub fn mapOldZirToNew(
31082984 var match_stack: ArrayListUnmanaged(MatchedZirDecl) = .{};
31092985 defer match_stack.deinit(gpa);
31102986
3111 // Main struct inst is always the same
2987 // Main struct inst is always matched
31122988 try match_stack.append(gpa, .{
31132989 .old_inst = .main_struct_inst,
31142990 .new_inst = .main_struct_inst,
31152991 });
31162992
2993 // Used as temporary buffers for namespace declaration instructions
31172994 var old_decls = std.ArrayList(Zir.Inst.Index).init(gpa);
31182995 defer old_decls.deinit();
31192996 var new_decls = std.ArrayList(Zir.Inst.Index).init(gpa);
31202997 defer new_decls.deinit();
31212998
31222999 while (match_stack.popOrNull()) |match_item| {
3000 // Match the namespace declaration itself
31233001 try inst_map.put(gpa, match_item.old_inst, match_item.new_inst);
31243002
3125 // Maps name to extra index of decl sub item.
3126 var decl_map: std.StringHashMapUnmanaged(Zir.ExtraIndex) = .{};
3127 defer decl_map.deinit(gpa);
3003 // Maps decl name to `declaration` instruction.
3004 var named_decls: std.StringHashMapUnmanaged(Zir.Inst.Index) = .{};
3005 defer named_decls.deinit(gpa);
3006 // Maps test name to `declaration` instruction.
3007 var named_tests: std.StringHashMapUnmanaged(Zir.Inst.Index) = .{};
3008 defer named_tests.deinit(gpa);
3009 // All unnamed tests, in order, for a best-effort match.
3010 var unnamed_tests: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
3011 defer unnamed_tests.deinit(gpa);
3012 // All comptime declarations, in order, for a best-effort match.
3013 var comptime_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
3014 defer comptime_decls.deinit(gpa);
3015 // All usingnamespace declarations, in order, for a best-effort match.
3016 var usingnamespace_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
3017 defer usingnamespace_decls.deinit(gpa);
31283018
31293019 {
31303020 var old_decl_it = old_zir.declIterator(match_item.old_inst);
3131 while (old_decl_it.next()) |old_decl| {
3132 try decl_map.put(gpa, old_decl.name, old_decl.sub_index);
3021 while (old_decl_it.next()) |old_decl_inst| {
3022 const old_decl, _ = old_zir.getDeclaration(old_decl_inst);
3023 switch (old_decl.name) {
3024 .@"comptime" => try comptime_decls.append(gpa, old_decl_inst),
3025 .@"usingnamespace" => try usingnamespace_decls.append(gpa, old_decl_inst),
3026 .unnamed_test, .decltest => try unnamed_tests.append(gpa, old_decl_inst),
3027 _ => {
3028 const name_nts = old_decl.name.toString(old_zir).?;
3029 const name = old_zir.nullTerminatedString(name_nts);
3030 if (old_decl.name.isNamedTest(old_zir)) {
3031 try named_tests.put(gpa, name, old_decl_inst);
3032 } else {
3033 try named_decls.put(gpa, name, old_decl_inst);
3034 }
3035 },
3036 }
31333037 }
31343038 }
31353039
3040 var unnamed_test_idx: u32 = 0;
3041 var comptime_decl_idx: u32 = 0;
3042 var usingnamespace_decl_idx: u32 = 0;
3043
31363044 var new_decl_it = new_zir.declIterator(match_item.new_inst);
3137 while (new_decl_it.next()) |new_decl| {
3138 const old_extra_index = decl_map.get(new_decl.name) orelse continue;
3139 const new_extra_index = new_decl.sub_index;
3140 try extra_map.put(gpa, old_extra_index, new_extra_index);
3141
3142 try old_zir.findDecls(&old_decls, old_extra_index);
3143 try new_zir.findDecls(&new_decls, new_extra_index);
3144 var i: usize = 0;
3145 while (true) : (i += 1) {
3146 if (i >= old_decls.items.len) break;
3147 if (i >= new_decls.items.len) break;
3148 try match_stack.append(gpa, .{
3149 .old_inst = old_decls.items[i],
3150 .new_inst = new_decls.items[i],
3151 });
3045 while (new_decl_it.next()) |new_decl_inst| {
3046 const new_decl, _ = new_zir.getDeclaration(new_decl_inst);
3047 // Attempt to match this to a declaration in the old ZIR:
3048 // * For named declarations (`const`/`var`/`fn`), we match based on name.
3049 // * For named tests (`test "foo"`), we also match based on name.
3050 // * For unnamed tests and decltests, we match based on order.
3051 // * For comptime blocks, we match based on order.
3052 // * For usingnamespace decls, we match based on order.
3053 // If we cannot match this declaration, we can't match anything nested inside of it either, so we just `continue`.
3054 const old_decl_inst = switch (new_decl.name) {
3055 .@"comptime" => inst: {
3056 if (comptime_decl_idx == comptime_decls.items.len) continue;
3057 defer comptime_decl_idx += 1;
3058 break :inst comptime_decls.items[comptime_decl_idx];
3059 },
3060 .@"usingnamespace" => inst: {
3061 if (usingnamespace_decl_idx == usingnamespace_decls.items.len) continue;
3062 defer usingnamespace_decl_idx += 1;
3063 break :inst usingnamespace_decls.items[usingnamespace_decl_idx];
3064 },
3065 .unnamed_test, .decltest => inst: {
3066 if (unnamed_test_idx == unnamed_tests.items.len) continue;
3067 defer unnamed_test_idx += 1;
3068 break :inst unnamed_tests.items[unnamed_test_idx];
3069 },
3070 _ => inst: {
3071 const name_nts = new_decl.name.toString(old_zir).?;
3072 const name = new_zir.nullTerminatedString(name_nts);
3073 if (new_decl.name.isNamedTest(new_zir)) {
3074 break :inst named_tests.get(name) orelse continue;
3075 } else {
3076 break :inst named_decls.get(name) orelse continue;
3077 }
3078 },
3079 };
3080
3081 // Match the `declaration` instruction
3082 try inst_map.put(gpa, old_decl_inst, new_decl_inst);
3083
3084 // Find namespace declarations within this declaration
3085 try old_zir.findDecls(&old_decls, old_decl_inst);
3086 try new_zir.findDecls(&new_decls, new_decl_inst);
3087
3088 // We don't have any smart way of matching up these namespace declarations, so we always
3089 // correlate them based on source order.
3090 const n = @min(old_decls.items.len, new_decls.items.len);
3091 try match_stack.ensureUnusedCapacity(gpa, n);
3092 for (old_decls.items[0..n], new_decls.items[0..n]) |old_inst, new_inst| {
3093 match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });
31523094 }
31533095 }
31543096 }
......@@ -3457,8 +3399,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
34573399 new_decl.src_line = 0;
34583400 new_decl.is_pub = true;
34593401 new_decl.is_exported = false;
3460 new_decl.has_align = false;
3461 new_decl.has_linksection_or_addrspace = false;
34623402 new_decl.ty = Type.type;
34633403 new_decl.alignment = .none;
34643404 new_decl.@"linksection" = .none;
......@@ -3502,7 +3442,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
35023442 const struct_ty = sema.getStructType(
35033443 new_decl_index,
35043444 new_namespace_index,
3505 .main_struct_inst,
3445 try mod.intern_pool.trackZir(gpa, file, .main_struct_inst),
35063446 ) catch |err| switch (err) {
35073447 error.OutOfMemory => return error.OutOfMemory,
35083448 };
......@@ -3561,7 +3501,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
35613501
35623502 const gpa = mod.gpa;
35633503 const zir = decl.getFileScope(mod).zir;
3564 const zir_datas = zir.instructions.items(.data);
35653504
35663505 const builtin_type_target_index: InternPool.Index = blk: {
35673506 const std_mod = mod.std_mod;
......@@ -3639,11 +3578,9 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
36393578 };
36403579 defer block_scope.instructions.deinit(gpa);
36413580
3642 const zir_block_index = decl.zirBlockIndex(mod);
3643 const inst_data = zir_datas[@intFromEnum(zir_block_index)].pl_node;
3644 const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index);
3645 const body = zir.extra[extra.end..][0..extra.data.body_len];
3646 const result_ref = (try sema.analyzeBodyBreak(&block_scope, @ptrCast(body))).?.operand;
3581 const decl_bodies = decl.zirBodies(mod);
3582
3583 const result_ref = (try sema.analyzeBodyBreak(&block_scope, decl_bodies.value_body)).?.operand;
36473584 // We'll do some other bits with the Sema. Clear the type target index just
36483585 // in case they analyze any type.
36493586 sema.builtin_type_target_index = .none;
......@@ -3760,13 +3697,13 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
37603697 decl.ty = decl_tv.ty;
37613698 decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod)));
37623699 decl.alignment = blk: {
3763 const align_ref = decl.zirAlignRef(mod);
3764 if (align_ref == .none) break :blk .none;
3700 const align_body = decl_bodies.align_body orelse break :blk .none;
3701 const align_ref = (try sema.analyzeBodyBreak(&block_scope, align_body)).?.operand;
37653702 break :blk try sema.resolveAlign(&block_scope, align_src, align_ref);
37663703 };
37673704 decl.@"linksection" = blk: {
3768 const linksection_ref = decl.zirLinksectionRef(mod);
3769 if (linksection_ref == .none) break :blk .none;
3705 const linksection_body = decl_bodies.linksection_body orelse break :blk .none;
3706 const linksection_ref = (try sema.analyzeBodyBreak(&block_scope, linksection_body)).?.operand;
37703707 const bytes = try sema.resolveConstString(&block_scope, section_src, linksection_ref, .{
37713708 .needed_comptime_reason = "linksection must be comptime-known",
37723709 });
......@@ -3786,15 +3723,15 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
37863723 };
37873724
37883725 const target = sema.mod.getTarget();
3789 break :blk switch (decl.zirAddrspaceRef(mod)) {
3790 .none => switch (addrspace_ctx) {
3791 .function => target_util.defaultAddressSpace(target, .function),
3792 .variable => target_util.defaultAddressSpace(target, .global_mutable),
3793 .constant => target_util.defaultAddressSpace(target, .global_constant),
3794 else => unreachable,
3795 },
3796 else => |addrspace_ref| try sema.analyzeAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx),
3726
3727 const addrspace_body = decl_bodies.addrspace_body orelse break :blk switch (addrspace_ctx) {
3728 .function => target_util.defaultAddressSpace(target, .function),
3729 .variable => target_util.defaultAddressSpace(target, .global_mutable),
3730 .constant => target_util.defaultAddressSpace(target, .global_constant),
3731 else => unreachable,
37973732 };
3733 const addrspace_ref = (try sema.analyzeBodyBreak(&block_scope, addrspace_body)).?.operand;
3734 break :blk try sema.analyzeAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx);
37983735 };
37993736 decl.has_tv = true;
38003737 decl.analysis = .complete;
......@@ -4133,52 +4070,32 @@ fn newEmbedFile(
41334070}
41344071
41354072pub fn scanNamespace(
4136 mod: *Module,
4073 zcu: *Zcu,
41374074 namespace_index: Namespace.Index,
4138 extra_start: usize,
4139 decls_len: u32,
4075 decls: []const Zir.Inst.Index,
41404076 parent_decl: *Decl,
4141) Allocator.Error!usize {
4077) Allocator.Error!void {
41424078 const tracy = trace(@src());
41434079 defer tracy.end();
41444080
4145 const gpa = mod.gpa;
4146 const namespace = mod.namespacePtr(namespace_index);
4147 const zir = namespace.file_scope.zir;
4081 const gpa = zcu.gpa;
4082 const namespace = zcu.namespacePtr(namespace_index);
41484083
4149 try mod.comp.work_queue.ensureUnusedCapacity(decls_len);
4150 try namespace.decls.ensureTotalCapacity(gpa, decls_len);
4084 try zcu.comp.work_queue.ensureUnusedCapacity(decls.len);
4085 try namespace.decls.ensureTotalCapacity(gpa, decls.len);
41514086
4152 const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable;
4153 var extra_index = extra_start + bit_bags_count;
4154 var bit_bag_index: usize = extra_start;
4155 var cur_bit_bag: u32 = undefined;
4156 var decl_i: u32 = 0;
41574087 var scan_decl_iter: ScanDeclIter = .{
4158 .module = mod,
4088 .zcu = zcu,
41594089 .namespace_index = namespace_index,
41604090 .parent_decl = parent_decl,
41614091 };
4162 while (decl_i < decls_len) : (decl_i += 1) {
4163 if (decl_i % 8 == 0) {
4164 cur_bit_bag = zir.extra[bit_bag_index];
4165 bit_bag_index += 1;
4166 }
4167 const flags = @as(u4, @truncate(cur_bit_bag));
4168 cur_bit_bag >>= 4;
4169
4170 const decl_sub_index = extra_index;
4171 extra_index += 8; // src_hash(4) + line(1) + name(1) + value(1) + doc_comment(1)
4172 extra_index += @as(u1, @truncate(flags >> 2)); // Align
4173 extra_index += @as(u2, @as(u1, @truncate(flags >> 3))) * 2; // Link section or address space, consists of 2 Refs
4174
4175 try scanDecl(&scan_decl_iter, decl_sub_index, flags);
4092 for (decls) |decl_inst| {
4093 try scanDecl(&scan_decl_iter, decl_inst);
41764094 }
4177 return extra_index;
41784095}
41794096
41804097const ScanDeclIter = struct {
4181 module: *Module,
4098 zcu: *Zcu,
41824099 namespace_index: Namespace.Index,
41834100 parent_decl: *Decl,
41844101 usingnamespace_index: usize = 0,
......@@ -4186,119 +4103,112 @@ const ScanDeclIter = struct {
41864103 unnamed_test_index: usize = 0,
41874104};
41884105
4189fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Error!void {
4106fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void {
41904107 const tracy = trace(@src());
41914108 defer tracy.end();
41924109
4193 const mod = iter.module;
4110 const zcu = iter.zcu;
41944111 const namespace_index = iter.namespace_index;
4195 const namespace = mod.namespacePtr(namespace_index);
4196 const gpa = mod.gpa;
4112 const namespace = zcu.namespacePtr(namespace_index);
4113 const gpa = zcu.gpa;
41974114 const zir = namespace.file_scope.zir;
4198 const ip = &mod.intern_pool;
4115 const ip = &zcu.intern_pool;
4116
4117 const pl_node = zir.instructions.items(.data)[@intFromEnum(decl_inst)].pl_node;
4118 const extra = zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
4119 const declaration = extra.data;
41994120
4200 // zig fmt: off
4201 const is_pub = (flags & 0b0001) != 0;
4202 const export_bit = (flags & 0b0010) != 0;
4203 const has_align = (flags & 0b0100) != 0;
4204 const has_linksection_or_addrspace = (flags & 0b1000) != 0;
4205 // zig fmt: on
4206
4207 const line_off = zir.extra[decl_sub_index + 4];
4208 const line = iter.parent_decl.relativeToLine(line_off);
4209 const decl_name_index: Zir.NullTerminatedString = @enumFromInt(zir.extra[decl_sub_index + 5]);
4210 const decl_doccomment_index = zir.extra[decl_sub_index + 7];
4211 const decl_zir_index = zir.extra[decl_sub_index + 6];
4212 const decl_block_inst_data = zir.instructions.items(.data)[decl_zir_index].pl_node;
4213 const decl_node = iter.parent_decl.relativeToNodeIndex(decl_block_inst_data.src_node);
4121 const line = iter.parent_decl.src_line + declaration.line_offset;
4122 const decl_node = iter.parent_decl.relativeToNodeIndex(pl_node.src_node);
42144123
42154124 // Every Decl needs a name.
4216 var is_named_test = false;
4217 var kind: Decl.Kind = .named;
4218 const decl_name: InternPool.NullTerminatedString = switch (decl_name_index) {
4219 .empty => name: {
4220 if (export_bit) {
4221 const i = iter.usingnamespace_index;
4222 iter.usingnamespace_index += 1;
4223 kind = .@"usingnamespace";
4224 break :name try ip.getOrPutStringFmt(gpa, "usingnamespace_{d}", .{i});
4225 } else {
4226 const i = iter.comptime_index;
4227 iter.comptime_index += 1;
4228 kind = .@"comptime";
4229 break :name try ip.getOrPutStringFmt(gpa, "comptime_{d}", .{i});
4230 }
4125 const decl_name: InternPool.NullTerminatedString, const kind: Decl.Kind, const is_named_test: bool = switch (declaration.name) {
4126 .@"comptime" => info: {
4127 const i = iter.comptime_index;
4128 iter.comptime_index += 1;
4129 break :info .{
4130 try ip.getOrPutStringFmt(gpa, "comptime_{d}", .{i}),
4131 .@"comptime",
4132 false,
4133 };
42314134 },
4232 .unnamed_test_decl => name: {
4135 .@"usingnamespace" => info: {
4136 const i = iter.usingnamespace_index;
4137 iter.usingnamespace_index += 1;
4138 break :info .{
4139 try ip.getOrPutStringFmt(gpa, "usingnamespace_{d}", .{i}),
4140 .@"usingnamespace",
4141 false,
4142 };
4143 },
4144 .unnamed_test => info: {
42334145 const i = iter.unnamed_test_index;
42344146 iter.unnamed_test_index += 1;
4235 kind = .@"test";
4236 break :name try ip.getOrPutStringFmt(gpa, "test_{d}", .{i});
4147 break :info .{
4148 try ip.getOrPutStringFmt(gpa, "test_{d}", .{i}),
4149 .@"test",
4150 false,
4151 };
42374152 },
4238 .decltest => name: {
4239 is_named_test = true;
4240 const test_name = zir.nullTerminatedString(@enumFromInt(decl_doccomment_index));
4241 kind = .@"test";
4242 break :name try ip.getOrPutStringFmt(gpa, "decltest.{s}", .{test_name});
4153 .decltest => info: {
4154 assert(declaration.flags.has_doc_comment);
4155 const name = zir.nullTerminatedString(@enumFromInt(zir.extra[extra.end]));
4156 break :info .{
4157 try ip.getOrPutStringFmt(gpa, "decltest.{s}", .{name}),
4158 .@"test",
4159 true,
4160 };
42434161 },
4244 _ => name: {
4245 const raw_name = zir.nullTerminatedString(decl_name_index);
4246 if (raw_name.len == 0) {
4247 is_named_test = true;
4248 const test_name = zir.nullTerminatedString(@enumFromInt(@intFromEnum(decl_name_index) + 1));
4249 kind = .@"test";
4250 break :name try ip.getOrPutStringFmt(gpa, "test.{s}", .{test_name});
4251 } else {
4252 break :name try ip.getOrPutString(gpa, raw_name);
4253 }
4162 _ => if (declaration.name.isNamedTest(zir)) .{
4163 try ip.getOrPutStringFmt(gpa, "test.{s}", .{zir.nullTerminatedString(declaration.name.toString(zir).?)}),
4164 .@"test",
4165 true,
4166 } else .{
4167 try ip.getOrPutString(gpa, zir.nullTerminatedString(declaration.name.toString(zir).?)),
4168 .named,
4169 false,
42544170 },
42554171 };
42564172
4257 const is_exported = export_bit and decl_name_index != .empty;
42584173 if (kind == .@"usingnamespace") try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1);
42594174
42604175 // We create a Decl for it regardless of analysis status.
42614176 const gop = try namespace.decls.getOrPutContextAdapted(
42624177 gpa,
42634178 decl_name,
4264 DeclAdapter{ .mod = mod },
4265 Namespace.DeclContext{ .module = mod },
4179 DeclAdapter{ .mod = zcu },
4180 Namespace.DeclContext{ .module = zcu },
42664181 );
4267 const comp = mod.comp;
4182 const comp = zcu.comp;
42684183 if (!gop.found_existing) {
4269 const new_decl_index = try mod.allocateNewDecl(namespace_index, decl_node, iter.parent_decl.src_scope);
4270 const new_decl = mod.declPtr(new_decl_index);
4184 const new_decl_index = try zcu.allocateNewDecl(namespace_index, decl_node, iter.parent_decl.src_scope);
4185 const new_decl = zcu.declPtr(new_decl_index);
42714186 new_decl.kind = kind;
42724187 new_decl.name = decl_name;
42734188 if (kind == .@"usingnamespace") {
4274 namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, is_pub);
4189 namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, declaration.flags.is_pub);
42754190 }
42764191 new_decl.src_line = line;
42774192 gop.key_ptr.* = new_decl_index;
42784193 // Exported decls, comptime decls, usingnamespace decls, and
42794194 // test decls if in test mode, get analyzed.
42804195 const decl_mod = namespace.file_scope.mod;
4281 const want_analysis = is_exported or switch (decl_name_index) {
4282 .empty => true, // comptime or usingnamespace decl
4283 .unnamed_test_decl => blk: {
4284 // test decl with no name. Skip the part where we check against
4285 // the test name filter.
4286 if (!comp.config.is_test) break :blk false;
4287 if (decl_mod != mod.main_mod) break :blk false;
4288 try mod.test_functions.put(gpa, new_decl_index, {});
4289 break :blk true;
4290 },
4291 else => blk: {
4292 if (!is_named_test) break :blk false;
4293 if (!comp.config.is_test) break :blk false;
4294 if (decl_mod != mod.main_mod) break :blk false;
4295 if (comp.test_filter) |test_filter| {
4296 if (mem.indexOf(u8, ip.stringToSlice(decl_name), test_filter) == null) {
4297 break :blk false;
4196 const want_analysis = declaration.flags.is_export or switch (kind) {
4197 .anon => unreachable,
4198 .@"comptime", .@"usingnamespace" => true,
4199 .named => false,
4200 .@"test" => a: {
4201 if (!comp.config.is_test) break :a false;
4202 if (decl_mod != zcu.main_mod) break :a false;
4203 if (is_named_test) {
4204 if (comp.test_filter) |test_filter| {
4205 if (mem.indexOf(u8, ip.stringToSlice(decl_name), test_filter) == null) {
4206 break :a false;
4207 }
42984208 }
42994209 }
4300 try mod.test_functions.put(gpa, new_decl_index, {});
4301 break :blk true;
4210 try zcu.test_functions.put(gpa, new_decl_index, {});
4211 break :a true;
43024212 },
43034213 };
43044214 if (want_analysis) {
......@@ -4307,46 +4217,42 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err
43074217 });
43084218 comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl_index });
43094219 }
4310 new_decl.is_pub = is_pub;
4311 new_decl.is_exported = is_exported;
4312 new_decl.has_align = has_align;
4313 new_decl.has_linksection_or_addrspace = has_linksection_or_addrspace;
4314 new_decl.zir_decl_index = @enumFromInt(decl_sub_index);
4220 new_decl.is_pub = declaration.flags.is_pub;
4221 new_decl.is_exported = declaration.flags.is_export;
4222 new_decl.zir_decl_index = decl_inst.toOptional();
43154223 new_decl.alive = true; // This Decl corresponds to an AST node and therefore always alive.
43164224 return;
43174225 }
43184226 const decl_index = gop.key_ptr.*;
4319 const decl = mod.declPtr(decl_index);
4227 const decl = zcu.declPtr(decl_index);
43204228 if (kind == .@"test") {
43214229 const src_loc = SrcLoc{
4322 .file_scope = decl.getFileScope(mod),
4230 .file_scope = decl.getFileScope(zcu),
43234231 .parent_decl_node = decl.src_node,
43244232 .lazy = .{ .token_offset = 1 },
43254233 };
43264234 const msg = try ErrorMsg.create(gpa, src_loc, "duplicate test name: {}", .{
4327 decl_name.fmt(&mod.intern_pool),
4235 decl_name.fmt(ip),
43284236 });
43294237 errdefer msg.destroy(gpa);
4330 try mod.failed_decls.putNoClobber(gpa, decl_index, msg);
4238 try zcu.failed_decls.putNoClobber(gpa, decl_index, msg);
43314239 const other_src_loc = SrcLoc{
43324240 .file_scope = namespace.file_scope,
43334241 .parent_decl_node = decl_node,
43344242 .lazy = .{ .token_offset = 1 },
43354243 };
4336 try mod.errNoteNonLazy(other_src_loc, msg, "other test here", .{});
4244 try zcu.errNoteNonLazy(other_src_loc, msg, "other test here", .{});
43374245 }
43384246 // Update the AST node of the decl; even if its contents are unchanged, it may
43394247 // have been re-ordered.
43404248 decl.src_node = decl_node;
43414249 decl.src_line = line;
43424250
4343 decl.is_pub = is_pub;
4344 decl.is_exported = is_exported;
4251 decl.is_pub = declaration.flags.is_pub;
4252 decl.is_exported = declaration.flags.is_export;
43454253 decl.kind = kind;
4346 decl.has_align = has_align;
4347 decl.has_linksection_or_addrspace = has_linksection_or_addrspace;
4348 decl.zir_decl_index = @enumFromInt(decl_sub_index);
4349 if (decl.getOwnedFunction(mod) != null) {
4254 decl.zir_decl_index = decl_inst.toOptional();
4255 if (decl.getOwnedFunction(zcu) != null) {
43504256 // TODO Look into detecting when this would be unnecessary by storing enough state
43514257 // in `Decl` to notice that the line number did not change.
43524258 comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
......@@ -4514,7 +4420,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
45144420 };
45154421 defer inner_block.instructions.deinit(gpa);
45164422
4517 const fn_info = sema.code.getFnInfo(func.zirBodyInst(ip).*);
4423 const fn_info = sema.code.getFnInfo(func.zirBodyInst(ip).resolve(ip));
45184424
45194425 // Here we are performing "runtime semantic analysis" for a function body, which means
45204426 // we must map the parameter ZIR instructions to `arg` AIR instructions.
......@@ -4730,8 +4636,6 @@ pub fn allocateNewDecl(
47304636 .generation = 0,
47314637 .is_pub = false,
47324638 .is_exported = false,
4733 .has_linksection_or_addrspace = false,
4734 .has_align = false,
47354639 .alive = false,
47364640 .kind = .anon,
47374641 });
......@@ -6169,7 +6073,7 @@ pub fn getParamName(mod: *Module, func_index: InternPool.Index, index: u32) [:0]
61696073 const tags = file.zir.instructions.items(.tag);
61706074 const data = file.zir.instructions.items(.data);
61716075
6172 const param_body = file.zir.getParamBody(func.zir_body_inst);
6076 const param_body = file.zir.getParamBody(func.zir_body_inst.resolve(&mod.intern_pool));
61736077 const param = param_body[index];
61746078
61756079 return switch (tags[@intFromEnum(param)]) {
src/Sema.zig+41-29
......@@ -1224,6 +1224,10 @@ fn analyzeBodyInner(
12241224 .trap => break sema.zirTrap(block, inst),
12251225 // zig fmt: on
12261226
1227 // This instruction never exists in an analyzed body. It exists only in the declaration
1228 // list for a container type.
1229 .declaration => unreachable,
1230
12271231 .extended => ext: {
12281232 const extended = datas[@intFromEnum(inst)].extended;
12291233 break :ext switch (extended.opcode) {
......@@ -2704,11 +2708,12 @@ pub fn getStructType(
27042708 sema: *Sema,
27052709 decl: InternPool.DeclIndex,
27062710 namespace: InternPool.NamespaceIndex,
2707 zir_index: Zir.Inst.Index,
2711 tracked_inst: InternPool.TrackedInst.Index,
27082712) !InternPool.Index {
27092713 const mod = sema.mod;
27102714 const gpa = sema.gpa;
27112715 const ip = &mod.intern_pool;
2716 const zir_index = tracked_inst.resolve(ip);
27122717 const extended = sema.code.instructions.items(.data)[@intFromEnum(zir_index)].extended;
27132718 assert(extended.opcode == .struct_decl);
27142719 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
......@@ -2736,12 +2741,14 @@ pub fn getStructType(
27362741 }
27372742 }
27382743
2739 extra_index = try mod.scanNamespace(namespace, extra_index, decls_len, mod.declPtr(decl));
2744 const decls = sema.code.bodySlice(extra_index, decls_len);
2745 try mod.scanNamespace(namespace, decls, mod.declPtr(decl));
2746 extra_index += decls_len;
27402747
27412748 const ty = try ip.getStructType(gpa, .{
27422749 .decl = decl,
27432750 .namespace = namespace.toOptional(),
2744 .zir_index = zir_index,
2751 .zir_index = tracked_inst,
27452752 .layout = small.layout,
27462753 .known_non_opv = small.known_non_opv,
27472754 .is_tuple = small.is_tuple,
......@@ -2791,7 +2798,8 @@ fn zirStructDecl(
27912798 errdefer mod.destroyNamespace(new_namespace_index);
27922799
27932800 const struct_ty = ty: {
2794 const ty = try sema.getStructType(new_decl_index, new_namespace_index, inst);
2801 const tracked_inst = try ip.trackZir(mod.gpa, block.getFileScope(mod), inst);
2802 const ty = try sema.getStructType(new_decl_index, new_namespace_index, tracked_inst);
27952803 if (sema.builtin_type_target_index != .none) {
27962804 ip.resolveBuiltinType(sema.builtin_type_target_index, ty);
27972805 break :ty sema.builtin_type_target_index;
......@@ -2850,7 +2858,7 @@ fn createAnonymousDeclTypeNamed(
28502858 return new_decl_index;
28512859 },
28522860 .func => {
2853 const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index));
2861 const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip));
28542862 const zir_tags = sema.code.instructions.items(.tag);
28552863
28562864 var buf = std.ArrayList(u8).init(gpa);
......@@ -2973,7 +2981,9 @@ fn zirEnumDecl(
29732981 const new_namespace = mod.namespacePtr(new_namespace_index);
29742982 errdefer if (!done) mod.destroyNamespace(new_namespace_index);
29752983
2976 extra_index = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl);
2984 const decls = sema.code.bodySlice(extra_index, decls_len);
2985 try mod.scanNamespace(new_namespace_index, decls, new_decl);
2986 extra_index += decls_len;
29772987
29782988 const body = sema.code.bodySlice(extra_index, body_len);
29792989 extra_index += body.len;
......@@ -3244,7 +3254,7 @@ fn zirUnionDecl(
32443254 },
32453255 .decl = new_decl_index,
32463256 .namespace = new_namespace_index,
3247 .zir_index = inst,
3257 .zir_index = try mod.intern_pool.trackZir(gpa, block.getFileScope(mod), inst),
32483258 .fields_len = fields_len,
32493259 .enum_tag_ty = .none,
32503260 .field_types = &.{},
......@@ -3263,7 +3273,8 @@ fn zirUnionDecl(
32633273 new_decl.val = Value.fromInterned(union_ty);
32643274 new_namespace.ty = Type.fromInterned(union_ty);
32653275
3266 _ = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl);
3276 const decls = sema.code.bodySlice(extra_index, decls_len);
3277 try mod.scanNamespace(new_namespace_index, decls, new_decl);
32673278
32683279 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
32693280 try mod.finalizeAnonDecl(new_decl_index);
......@@ -3326,7 +3337,8 @@ fn zirOpaqueDecl(
33263337 new_decl.val = Value.fromInterned(opaque_ty);
33273338 new_namespace.ty = Type.fromInterned(opaque_ty);
33283339
3329 extra_index = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl);
3340 const decls = sema.code.bodySlice(extra_index, decls_len);
3341 try mod.scanNamespace(new_namespace_index, decls, new_decl);
33303342
33313343 const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
33323344 try mod.finalizeAnonDecl(new_decl_index);
......@@ -7436,7 +7448,7 @@ fn analyzeCall(
74367448 // the AIR instructions of the callsite. The callee could be a generic function
74377449 // which means its parameter type expressions must be resolved in order and used
74387450 // to successively coerce the arguments.
7439 const fn_info = ics.callee().code.getFnInfo(module_fn.zir_body_inst);
7451 const fn_info = ics.callee().code.getFnInfo(module_fn.zir_body_inst.resolve(ip));
74407452 try ics.callee().inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body);
74417453
74427454 var arg_i: u32 = 0;
......@@ -7484,7 +7496,7 @@ fn analyzeCall(
74847496 // each of the parameters, resolving the return type and providing it to the child
74857497 // `Sema` so that it can be used for the `ret_ptr` instruction.
74867498 const ret_ty_inst = if (fn_info.ret_ty_body.len != 0)
7487 try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst)
7499 try sema.resolveBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst.resolve(ip))
74887500 else
74897501 try sema.resolveInst(fn_info.ret_ty_ref);
74907502 const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
......@@ -7875,7 +7887,7 @@ fn instantiateGenericCall(
78757887 const namespace_index = fn_owner_decl.src_namespace;
78767888 const namespace = mod.namespacePtr(namespace_index);
78777889 const fn_zir = namespace.file_scope.zir;
7878 const fn_info = fn_zir.getFnInfo(generic_owner_func.zir_body_inst);
7890 const fn_info = fn_zir.getFnInfo(generic_owner_func.zir_body_inst.resolve(ip));
78797891
78807892 const comptime_args = try sema.arena.alloc(InternPool.Index, args_info.count());
78817893 @memset(comptime_args, .none);
......@@ -9457,7 +9469,7 @@ fn funcCommon(
94579469 .is_generic = final_is_generic,
94589470 .is_noinline = is_noinline,
94599471
9460 .zir_body_inst = func_inst,
9472 .zir_body_inst = try ip.trackZir(gpa, block.getFileScope(mod), func_inst),
94619473 .lbrace_line = src_locs.lbrace_line,
94629474 .rbrace_line = src_locs.rbrace_line,
94639475 .lbrace_column = @as(u16, @truncate(src_locs.columns)),
......@@ -9535,7 +9547,7 @@ fn funcCommon(
95359547 .ty = func_ty,
95369548 .cc = cc,
95379549 .is_noinline = is_noinline,
9538 .zir_body_inst = func_inst,
9550 .zir_body_inst = try ip.trackZir(gpa, block.getFileScope(mod), func_inst),
95399551 .lbrace_line = src_locs.lbrace_line,
95409552 .rbrace_line = src_locs.rbrace_line,
95419553 .lbrace_column = @as(u16, @truncate(src_locs.columns)),
......@@ -21552,7 +21564,7 @@ fn zirReify(
2155221564 .namespace = new_namespace_index,
2155321565 .enum_tag_ty = enum_tag_ty,
2155421566 .fields_len = fields_len,
21555 .zir_index = inst,
21567 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst), // TODO: should reified types be handled differently?
2155621568 .flags = .{
2155721569 .layout = layout,
2155821570 .status = .have_field_types,
......@@ -21720,7 +21732,7 @@ fn reifyStruct(
2172021732 const ty = try ip.getStructType(gpa, .{
2172121733 .decl = new_decl_index,
2172221734 .namespace = .none,
21723 .zir_index = inst,
21735 .zir_index = try mod.intern_pool.trackZir(gpa, block.getFileScope(mod), inst), // TODO: should reified types be handled differently?
2172421736 .layout = layout,
2172521737 .known_non_opv = false,
2172621738 .fields_len = fields_len,
......@@ -35592,7 +35604,8 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp
3559235604 break :blk accumulator;
3559335605 };
3559435606
35595 const extended = zir.instructions.items(.data)[@intFromEnum(struct_type.zir_index)].extended;
35607 const zir_index = struct_type.zir_index.resolve(ip);
35608 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
3559635609 assert(extended.opcode == .struct_decl);
3559735610 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
3559835611
......@@ -35612,7 +35625,7 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp
3561235625 break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref);
3561335626 } else {
3561435627 const body = zir.bodySlice(extra_index, backing_int_body_len);
35615 const ty_ref = try sema.resolveBody(&block, body, struct_type.zir_index);
35628 const ty_ref = try sema.resolveBody(&block, body, zir_index);
3561635629 break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref);
3561735630 }
3561835631 };
......@@ -36340,9 +36353,7 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
3634036353 }
3634136354
3634236355 // Skip over decls.
36343 var decls_it = zir.declIteratorInner(extra_index, decls_len);
36344 while (decls_it.next()) |_| {}
36345 extra_index = decls_it.extra_index;
36356 extra_index += decls_len;
3634636357
3634736358 return .{ fields_len, small, extra_index };
3634836359}
......@@ -36358,7 +36369,7 @@ fn semaStructFields(
3635836369 const decl = mod.declPtr(decl_index);
3635936370 const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace;
3636036371 const zir = mod.namespacePtr(namespace_index).file_scope.zir;
36361 const zir_index = struct_type.zir_index;
36372 const zir_index = struct_type.zir_index.resolve(ip);
3636236373
3636336374 const fields_len, const small, var extra_index = structZirInfo(zir, zir_index);
3636436375
......@@ -36629,7 +36640,7 @@ fn semaStructFieldInits(
3662936640 const decl = mod.declPtr(decl_index);
3663036641 const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace;
3663136642 const zir = mod.namespacePtr(namespace_index).file_scope.zir;
36632 const zir_index = struct_type.zir_index;
36643 const zir_index = struct_type.zir_index.resolve(ip);
3663336644 const fields_len, const small, var extra_index = structZirInfo(zir, zir_index);
3663436645
3663536646 var comptime_mutable_decls = std.ArrayList(InternPool.DeclIndex).init(gpa);
......@@ -36778,7 +36789,8 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
3677836789 const ip = &mod.intern_pool;
3677936790 const decl_index = union_type.decl;
3678036791 const zir = mod.namespacePtr(union_type.namespace).file_scope.zir;
36781 const extended = zir.instructions.items(.data)[@intFromEnum(union_type.zir_index)].extended;
36792 const zir_index = union_type.zir_index.resolve(ip);
36793 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
3678236794 assert(extended.opcode == .union_decl);
3678336795 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
3678436796 var extra_index: usize = extended.operand;
......@@ -36811,9 +36823,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
3681136823 } else 0;
3681236824
3681336825 // Skip over decls.
36814 var decls_it = zir.declIteratorInner(extra_index, decls_len);
36815 while (decls_it.next()) |_| {}
36816 extra_index = decls_it.extra_index;
36826 extra_index += decls_len;
3681736827
3681836828 const body = zir.bodySlice(extra_index, body_len);
3681936829 extra_index += body.len;
......@@ -37810,10 +37820,12 @@ pub fn analyzeAddressSpace(
3781037820 ctx: AddressSpaceContext,
3781137821) !std.builtin.AddressSpace {
3781237822 const mod = sema.mod;
37813 const addrspace_tv = try sema.resolveInstConst(block, src, zir_ref, .{
37823 const air_ref = try sema.resolveInst(zir_ref);
37824 const coerced = try sema.coerce(block, Type.fromInterned(.address_space_type), air_ref, src);
37825 const addrspace_val = try sema.resolveConstDefinedValue(block, src, coerced, .{
3781437826 .needed_comptime_reason = "address space must be comptime-known",
3781537827 });
37816 const address_space = mod.toEnum(std.builtin.AddressSpace, addrspace_tv.val);
37828 const address_space = mod.toEnum(std.builtin.AddressSpace, addrspace_val);
3781737829 const target = sema.mod.getTarget();
3781837830 const arch = target.cpu.arch;
3781937831
src/Zir.zig+213-187
......@@ -30,7 +30,7 @@ instructions: std.MultiArrayList(Inst).Slice,
3030/// is referencing the data here whether they want to store both index and length,
3131/// thus allowing null bytes, or store only index, and use null-termination. The
3232/// `string_bytes` array is agnostic to either usage.
33/// Indexes 0 and 1 are reserved for special cases.
33/// Index 0 is reserved for special cases.
3434string_bytes: []u8,
3535/// The meaning of this data is determined by `Inst.Tag` value.
3636/// The first few indexes are reserved. See `ExtraIndex` for the values.
......@@ -60,21 +60,6 @@ pub const ExtraIndex = enum(u32) {
6060 imports,
6161
6262 _,
63
64 pub fn toOptional(i: ExtraIndex) OptionalExtraIndex {
65 return @enumFromInt(@intFromEnum(i));
66 }
67};
68
69pub const OptionalExtraIndex = enum(u32) {
70 compile_errors,
71 imports,
72 none = std.math.maxInt(u32),
73 _,
74
75 pub fn unwrap(oi: OptionalExtraIndex) ?ExtraIndex {
76 return if (oi == .none) null else @enumFromInt(@intFromEnum(oi));
77 }
7863};
7964
8065fn ExtraData(comptime T: type) type {
......@@ -93,6 +78,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) {
9378
9479 Inst.Ref,
9580 Inst.Index,
81 Inst.Declaration.Name,
9682 NullTerminatedString,
9783 => @enumFromInt(code.extra[i]),
9884
......@@ -102,6 +88,7 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) {
10288 Inst.SwitchBlock.Bits,
10389 Inst.SwitchBlockErrUnion.Bits,
10490 Inst.FuncFancy.Bits,
91 Inst.Declaration.Flags,
10592 => @bitCast(code.extra[i]),
10693
10794 else => @compileError("bad field type"),
......@@ -116,8 +103,6 @@ pub fn extraData(code: Zir, comptime T: type, index: usize) ExtraData(T) {
116103
117104pub const NullTerminatedString = enum(u32) {
118105 empty = 0,
119 unnamed_test_decl = 1,
120 decltest = 2,
121106 _,
122107};
123108
......@@ -304,6 +289,12 @@ pub const Inst = struct {
304289 /// a noreturn instruction.
305290 /// Uses the `pl_node` union field. Payload is `Block`.
306291 block_inline,
292 /// This instruction may only ever appear in the list of declarations for a
293 /// namespace type, e.g. within a `struct_decl` instruction. It represents a
294 /// single source declaration (`const`/`var`/`fn`), containing the name,
295 /// attributes, type, and value of the declaration.
296 /// Uses the `pl_node` union field. Payload is `Declaration`.
297 declaration,
307298 /// Implements `suspend {...}`.
308299 /// Uses the `pl_node` union field. Payload is `Block`.
309300 suspend_block,
......@@ -1092,6 +1083,7 @@ pub const Inst = struct {
10921083 .block,
10931084 .block_comptime,
10941085 .block_inline,
1086 .declaration,
10951087 .suspend_block,
10961088 .loop,
10971089 .bool_br_and,
......@@ -1405,6 +1397,7 @@ pub const Inst = struct {
14051397 .block,
14061398 .block_comptime,
14071399 .block_inline,
1400 .declaration,
14081401 .suspend_block,
14091402 .loop,
14101403 .bool_br_and,
......@@ -1639,6 +1632,7 @@ pub const Inst = struct {
16391632 .block = .pl_node,
16401633 .block_comptime = .pl_node,
16411634 .block_inline = .pl_node,
1635 .declaration = .pl_node,
16421636 .suspend_block = .pl_node,
16431637 .bool_not = .un_node,
16441638 .bool_br_and = .bool_br,
......@@ -2508,6 +2502,7 @@ pub const Inst = struct {
25082502 /// If this is 1 it means return_type is a simple Ref
25092503 ret_body_len: u32,
25102504 /// Points to the block that contains the param instructions for this function.
2505 /// If this is a `declaration`, it refers to the declaration's value body.
25112506 param_block: Index,
25122507 body_len: u32,
25132508
......@@ -2565,6 +2560,7 @@ pub const Inst = struct {
25652560 /// 18. src_locs: Func.SrcLocs // if body_len != 0
25662561 pub const FuncFancy = struct {
25672562 /// Points to the block that contains the param instructions for this function.
2563 /// If this is a `declaration`, it refers to the declaration's value body.
25682564 param_block: Index,
25692565 body_len: u32,
25702566 bits: Bits,
......@@ -2632,6 +2628,116 @@ pub const Inst = struct {
26322628 body_len: u32,
26332629 };
26342630
2631 /// Trailing:
2632 /// 0. doc_comment: u32 // if `has_doc_comment`; null-terminated string index
2633 /// 1. align_body_len: u32 // if `has_align_linksection_addrspace`; 0 means no `align`
2634 /// 2. linksection_body_len: u32 // if `has_align_linksection_addrspace`; 0 means no `linksection`
2635 /// 3. addrspace_body_len: u32 // if `has_align_linksection_addrspace`; 0 means no `addrspace`
2636 /// 4. value_body_inst: Zir.Inst.Index
2637 /// - for each `value_body_len`
2638 /// - body to be exited via `break_inline` to this `declaration` instruction
2639 /// 5. align_body_inst: Zir.Inst.Index
2640 /// - for each `align_body_len`
2641 /// - body to be exited via `break_inline` to this `declaration` instruction
2642 /// 6. linksection_body_inst: Zir.Inst.Index
2643 /// - for each `linksection_body_len`
2644 /// - body to be exited via `break_inline` to this `declaration` instruction
2645 /// 7. addrspace_body_inst: Zir.Inst.Index
2646 /// - for each `addrspace_body_len`
2647 /// - body to be exited via `break_inline` to this `declaration` instruction
2648 pub const Declaration = struct {
2649 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
2650 src_hash_0: u32,
2651 src_hash_1: u32,
2652 src_hash_2: u32,
2653 src_hash_3: u32,
2654 /// The name of this `Decl`. Also indicates whether it is a test, comptime block, etc.
2655 name: Name,
2656 /// This Decl's line number relative to that of its parent.
2657 /// TODO: column must be encoded similarly to respect non-formatted code!
2658 line_offset: u32,
2659 flags: Flags,
2660
2661 pub const Flags = packed struct(u32) {
2662 value_body_len: u28,
2663 is_pub: bool,
2664 is_export: bool,
2665 has_doc_comment: bool,
2666 has_align_linksection_addrspace: bool,
2667 };
2668
2669 pub const Name = enum(u32) {
2670 @"comptime" = std.math.maxInt(u32),
2671 @"usingnamespace" = std.math.maxInt(u32) - 1,
2672 unnamed_test = std.math.maxInt(u32) - 2,
2673 /// In this case, `has_doc_comment` will be true, and the doc
2674 /// comment body is the identifier name.
2675 decltest = std.math.maxInt(u32) - 3,
2676 /// Other values are `NullTerminatedString` values, i.e. index into
2677 /// `string_bytes`. If the byte referenced is 0, the decl is a named
2678 /// test, and the actual name begins at the following byte.
2679 _,
2680
2681 pub fn isNamedTest(name: Name, zir: Zir) bool {
2682 return switch (name) {
2683 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => false,
2684 _ => zir.string_bytes[@intFromEnum(name)] == 0,
2685 };
2686 }
2687 pub fn toString(name: Name, zir: Zir) ?NullTerminatedString {
2688 switch (name) {
2689 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => return null,
2690 _ => {},
2691 }
2692 const idx: u32 = @intFromEnum(name);
2693 if (zir.string_bytes[idx] == 0) {
2694 // Named test
2695 return @enumFromInt(idx + 1);
2696 }
2697 return @enumFromInt(idx);
2698 }
2699 };
2700
2701 pub const Bodies = struct {
2702 value_body: []const Index,
2703 align_body: ?[]const Index,
2704 linksection_body: ?[]const Index,
2705 addrspace_body: ?[]const Index,
2706 };
2707
2708 pub fn getBodies(declaration: Declaration, extra_end: u32, zir: Zir) Bodies {
2709 var extra_index: u32 = extra_end;
2710 extra_index += @intFromBool(declaration.flags.has_doc_comment);
2711 const value_body_len = declaration.flags.value_body_len;
2712 const align_body_len, const linksection_body_len, const addrspace_body_len = lens: {
2713 if (!declaration.flags.has_align_linksection_addrspace) {
2714 break :lens .{ 0, 0, 0 };
2715 }
2716 const lens = zir.extra[extra_index..][0..3].*;
2717 extra_index += 3;
2718 break :lens lens;
2719 };
2720 return .{
2721 .value_body = b: {
2722 defer extra_index += value_body_len;
2723 break :b zir.bodySlice(extra_index, value_body_len);
2724 },
2725 .align_body = if (align_body_len == 0) null else b: {
2726 defer extra_index += align_body_len;
2727 break :b zir.bodySlice(extra_index, align_body_len);
2728 },
2729 .linksection_body = if (linksection_body_len == 0) null else b: {
2730 defer extra_index += linksection_body_len;
2731 break :b zir.bodySlice(extra_index, linksection_body_len);
2732 },
2733 .addrspace_body = if (addrspace_body_len == 0) null else b: {
2734 defer extra_index += addrspace_body_len;
2735 break :b zir.bodySlice(extra_index, addrspace_body_len);
2736 },
2737 };
2738 }
2739 };
2740
26352741 /// Stored inside extra, with trailing arguments according to `args_len`.
26362742 /// Implicit 0. arg_0_start: u32, // always same as `args_len`
26372743 /// 1. arg_end: u32, // for each `args_len`
......@@ -2913,37 +3019,14 @@ pub const Inst = struct {
29133019 /// 3. backing_int_body_len: u32, // if has_backing_int
29143020 /// 4. backing_int_ref: Ref, // if has_backing_int and backing_int_body_len is 0
29153021 /// 5. backing_int_body_inst: Inst, // if has_backing_int and backing_int_body_len is > 0
2916 /// 6. decl_bits: u32 // for every 8 decls
2917 /// - sets of 4 bits:
2918 /// 0b000X: whether corresponding decl is pub
2919 /// 0b00X0: whether corresponding decl is exported
2920 /// 0b0X00: whether corresponding decl has an align expression
2921 /// 0bX000: whether corresponding decl has a linksection or an address space expression
2922 /// 7. decl: { // for every decls_len
2923 /// src_hash: [4]u32, // hash of source bytes
2924 /// line: u32, // line number of decl, relative to parent
2925 /// name: NullTerminatedString, // null terminated string index
2926 /// - 0 means comptime or usingnamespace decl.
2927 /// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace
2928 /// - 1 means test decl with no name.
2929 /// - 2 means that the test is a decltest, doc_comment gives the name of the identifier
2930 /// - if there is a 0 byte at the position `name` indexes, it indicates
2931 /// this is a test decl, and the name starts at `name+1`.
2932 /// value: Index,
2933 /// doc_comment: u32, .empty if no doc comment, if this is a decltest, doc_comment references the decl name in the string table
2934 /// align: Ref, // if corresponding bit is set
2935 /// link_section_or_address_space: { // if corresponding bit is set.
2936 /// link_section: Ref,
2937 /// address_space: Ref,
2938 /// }
2939 /// }
2940 /// 8. flags: u32 // for every 8 fields
3022 /// 6. decl: Index, // for every decls_len; points to a `declaration` instruction
3023 /// 7. flags: u32 // for every 8 fields
29413024 /// - sets of 4 bits:
29423025 /// 0b000X: whether corresponding field has an align expression
29433026 /// 0b00X0: whether corresponding field has a default expression
29443027 /// 0b0X00: whether corresponding field is comptime
29453028 /// 0bX000: whether corresponding field has a type expression
2946 /// 9. fields: { // for every fields_len
3029 /// 8. fields: { // for every fields_len
29473030 /// field_name: u32, // if !is_tuple
29483031 /// doc_comment: NullTerminatedString, // .empty if no doc comment
29493032 /// field_type: Ref, // if corresponding bit is not set. none means anytype.
......@@ -3009,33 +3092,11 @@ pub const Inst = struct {
30093092 /// 2. body_len: u32, // if has_body_len
30103093 /// 3. fields_len: u32, // if has_fields_len
30113094 /// 4. decls_len: u32, // if has_decls_len
3012 /// 5. decl_bits: u32 // for every 8 decls
3013 /// - sets of 4 bits:
3014 /// 0b000X: whether corresponding decl is pub
3015 /// 0b00X0: whether corresponding decl is exported
3016 /// 0b0X00: whether corresponding decl has an align expression
3017 /// 0bX000: whether corresponding decl has a linksection or an address space expression
3018 /// 6. decl: { // for every decls_len
3019 /// src_hash: [4]u32, // hash of source bytes
3020 /// line: u32, // line number of decl, relative to parent
3021 /// name: NullTerminatedString, // null terminated string index
3022 /// - 0 means comptime or usingnamespace decl.
3023 /// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace
3024 /// - 1 means test decl with no name.
3025 /// - if there is a 0 byte at the position `name` indexes, it indicates
3026 /// this is a test decl, and the name starts at `name+1`.
3027 /// value: Index,
3028 /// doc_comment: u32, // .empty if no doc_comment
3029 /// align: Ref, // if corresponding bit is set
3030 /// link_section_or_address_space: { // if corresponding bit is set.
3031 /// link_section: Ref,
3032 /// address_space: Ref,
3033 /// }
3034 /// }
3035 /// 7. inst: Index // for every body_len
3036 /// 8. has_bits: u32 // for every 32 fields
3095 /// 5. decl: Index, // for every decls_len; points to a `declaration` instruction
3096 /// 6. inst: Index // for every body_len
3097 /// 7. has_bits: u32 // for every 32 fields
30373098 /// - the bit is whether corresponding field has an value expression
3038 /// 9. fields: { // for every fields_len
3099 /// 8. fields: { // for every fields_len
30393100 /// field_name: u32,
30403101 /// doc_comment: u32, // .empty if no doc_comment
30413102 /// value: Ref, // if corresponding bit is set
......@@ -3059,37 +3120,15 @@ pub const Inst = struct {
30593120 /// 2. body_len: u32, // if has_body_len
30603121 /// 3. fields_len: u32, // if has_fields_len
30613122 /// 4. decls_len: u32, // if has_decls_len
3062 /// 5. decl_bits: u32 // for every 8 decls
3063 /// - sets of 4 bits:
3064 /// 0b000X: whether corresponding decl is pub
3065 /// 0b00X0: whether corresponding decl is exported
3066 /// 0b0X00: whether corresponding decl has an align expression
3067 /// 0bX000: whether corresponding decl has a linksection or an address space expression
3068 /// 6. decl: { // for every decls_len
3069 /// src_hash: [4]u32, // hash of source bytes
3070 /// line: u32, // line number of decl, relative to parent
3071 /// name: NullTerminatedString, // null terminated string index
3072 /// - 0 means comptime or usingnamespace decl.
3073 /// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace
3074 /// - 1 means test decl with no name.
3075 /// - if there is a 0 byte at the position `name` indexes, it indicates
3076 /// this is a test decl, and the name starts at `name+1`.
3077 /// value: Index,
3078 /// doc_comment: NullTerminatedString, // .empty if no doc comment
3079 /// align: Ref, // if corresponding bit is set
3080 /// link_section_or_address_space: { // if corresponding bit is set.
3081 /// link_section: Ref,
3082 /// address_space: Ref,
3083 /// }
3084 /// }
3085 /// 7. inst: Index // for every body_len
3086 /// 8. has_bits: u32 // for every 8 fields
3123 /// 5. decl: Index, // for every decls_len; points to a `declaration` instruction
3124 /// 6. inst: Index // for every body_len
3125 /// 7. has_bits: u32 // for every 8 fields
30873126 /// - sets of 4 bits:
30883127 /// 0b000X: whether corresponding field has a type expression
30893128 /// 0b00X0: whether corresponding field has a align expression
30903129 /// 0b0X00: whether corresponding field has a tag value expression
30913130 /// 0bX000: unused
3092 /// 9. fields: { // for every fields_len
3131 /// 8. fields: { // for every fields_len
30933132 /// field_name: NullTerminatedString, // null terminated string index
30943133 /// doc_comment: NullTerminatedString, // .empty if no doc comment
30953134 /// field_type: Ref, // if corresponding bit is set
......@@ -3121,29 +3160,7 @@ pub const Inst = struct {
31213160 /// Trailing:
31223161 /// 0. src_node: i32, // if has_src_node
31233162 /// 1. decls_len: u32, // if has_decls_len
3124 /// 2. decl_bits: u32 // for every 8 decls
3125 /// - sets of 4 bits:
3126 /// 0b000X: whether corresponding decl is pub
3127 /// 0b00X0: whether corresponding decl is exported
3128 /// 0b0X00: whether corresponding decl has an align expression
3129 /// 0bX000: whether corresponding decl has a linksection or an address space expression
3130 /// 3. decl: { // for every decls_len
3131 /// src_hash: [4]u32, // hash of source bytes
3132 /// line: u32, // line number of decl, relative to parent
3133 /// name: NullTerminatedString, // null terminated string index
3134 /// - 0 means comptime or usingnamespace decl.
3135 /// - if name == 0 `is_exported` determines which one: 0=comptime,1=usingnamespace
3136 /// - 1 means test decl with no name.
3137 /// - if there is a 0 byte at the position `name` indexes, it indicates
3138 /// this is a test decl, and the name starts at `name+1`.
3139 /// value: Index,
3140 /// doc_comment: NullTerminatedString, // .empty if no doc comment,
3141 /// align: Ref, // if corresponding bit is set
3142 /// link_section_or_address_space: { // if corresponding bit is set.
3143 /// link_section: Ref,
3144 /// address_space: Ref,
3145 /// }
3146 /// }
3163 /// 2. decl: Index, // for every decls_len; points to a `declaration` instruction
31473164 pub const OpaqueDecl = struct {
31483165 pub const Small = packed struct {
31493166 has_src_node: bool,
......@@ -3407,44 +3424,17 @@ pub const Inst = struct {
34073424pub const SpecialProng = enum { none, @"else", under };
34083425
34093426pub const DeclIterator = struct {
3410 extra_index: usize,
3411 bit_bag_index: usize,
3412 cur_bit_bag: u32,
3413 decl_i: u32,
3414 decls_len: u32,
3427 extra_index: u32,
3428 decls_remaining: u32,
34153429 zir: Zir,
34163430
3417 pub const Item = struct {
3418 name: [:0]const u8,
3419 sub_index: ExtraIndex,
3420 flags: u4,
3421 };
3422
3423 pub fn next(it: *DeclIterator) ?Item {
3424 if (it.decl_i >= it.decls_len) return null;
3425
3426 if (it.decl_i % 8 == 0) {
3427 it.cur_bit_bag = it.zir.extra[it.bit_bag_index];
3428 it.bit_bag_index += 1;
3429 }
3430 it.decl_i += 1;
3431
3432 const flags: u4 = @truncate(it.cur_bit_bag);
3433 it.cur_bit_bag >>= 4;
3434
3435 const sub_index: ExtraIndex = @enumFromInt(it.extra_index);
3436 it.extra_index += 5; // src_hash(4) + line(1)
3437 const name = it.zir.nullTerminatedString(@enumFromInt(it.zir.extra[it.extra_index]));
3438 it.extra_index += 3; // name(1) + value(1) + doc_comment(1)
3439 it.extra_index += @as(u1, @truncate(flags >> 2)); // align
3440 it.extra_index += @as(u1, @truncate(flags >> 3)); // link_section
3441 it.extra_index += @as(u1, @truncate(flags >> 3)); // address_space
3442
3443 return Item{
3444 .sub_index = sub_index,
3445 .name = name,
3446 .flags = flags,
3447 };
3431 pub fn next(it: *DeclIterator) ?Inst.Index {
3432 if (it.decls_remaining == 0) return null;
3433 const decl_inst: Zir.Inst.Index = @enumFromInt(it.zir.extra[it.extra_index]);
3434 it.extra_index += 1;
3435 it.decls_remaining -= 1;
3436 assert(it.zir.instructions.items(.tag)[@intFromEnum(decl_inst)] == .declaration);
3437 return decl_inst;
34483438 }
34493439};
34503440
......@@ -3454,14 +3444,18 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
34543444 switch (tags[@intFromEnum(decl_inst)]) {
34553445 // Functions are allowed and yield no iterations.
34563446 // There is one case matching this in the extended instruction set below.
3457 .func, .func_inferred, .func_fancy => return declIteratorInner(zir, 0, 0),
3447 .func, .func_inferred, .func_fancy => return .{
3448 .extra_index = undefined,
3449 .decls_remaining = 0,
3450 .zir = zir,
3451 },
34583452
34593453 .extended => {
34603454 const extended = datas[@intFromEnum(decl_inst)].extended;
34613455 switch (extended.opcode) {
34623456 .struct_decl => {
34633457 const small: Inst.StructDecl.Small = @bitCast(extended.small);
3464 var extra_index: usize = extended.operand;
3458 var extra_index: u32 = extended.operand;
34653459 extra_index += @intFromBool(small.has_src_node);
34663460 extra_index += @intFromBool(small.has_fields_len);
34673461 const decls_len = if (small.has_decls_len) decls_len: {
......@@ -3480,11 +3474,15 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
34803474 }
34813475 }
34823476
3483 return declIteratorInner(zir, extra_index, decls_len);
3477 return .{
3478 .extra_index = extra_index,
3479 .decls_remaining = decls_len,
3480 .zir = zir,
3481 };
34843482 },
34853483 .enum_decl => {
34863484 const small: Inst.EnumDecl.Small = @bitCast(extended.small);
3487 var extra_index: usize = extended.operand;
3485 var extra_index: u32 = extended.operand;
34883486 extra_index += @intFromBool(small.has_src_node);
34893487 extra_index += @intFromBool(small.has_tag_type);
34903488 extra_index += @intFromBool(small.has_body_len);
......@@ -3495,11 +3493,15 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
34953493 break :decls_len decls_len;
34963494 } else 0;
34973495
3498 return declIteratorInner(zir, extra_index, decls_len);
3496 return .{
3497 .extra_index = extra_index,
3498 .decls_remaining = decls_len,
3499 .zir = zir,
3500 };
34993501 },
35003502 .union_decl => {
35013503 const small: Inst.UnionDecl.Small = @bitCast(extended.small);
3502 var extra_index: usize = extended.operand;
3504 var extra_index: u32 = extended.operand;
35033505 extra_index += @intFromBool(small.has_src_node);
35043506 extra_index += @intFromBool(small.has_tag_type);
35053507 extra_index += @intFromBool(small.has_body_len);
......@@ -3510,11 +3512,15 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
35103512 break :decls_len decls_len;
35113513 } else 0;
35123514
3513 return declIteratorInner(zir, extra_index, decls_len);
3515 return .{
3516 .extra_index = extra_index,
3517 .decls_remaining = decls_len,
3518 .zir = zir,
3519 };
35143520 },
35153521 .opaque_decl => {
35163522 const small: Inst.OpaqueDecl.Small = @bitCast(extended.small);
3517 var extra_index: usize = extended.operand;
3523 var extra_index: u32 = extended.operand;
35183524 extra_index += @intFromBool(small.has_src_node);
35193525 const decls_len = if (small.has_decls_len) decls_len: {
35203526 const decls_len = zir.extra[extra_index];
......@@ -3522,7 +3528,11 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
35223528 break :decls_len decls_len;
35233529 } else 0;
35243530
3525 return declIteratorInner(zir, extra_index, decls_len);
3531 return .{
3532 .extra_index = extra_index,
3533 .decls_remaining = decls_len,
3534 .zir = zir,
3535 };
35263536 },
35273537 else => unreachable,
35283538 }
......@@ -3531,25 +3541,17 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
35313541 }
35323542}
35333543
3534pub fn declIteratorInner(zir: Zir, extra_index: usize, decls_len: u32) DeclIterator {
3535 const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable;
3536 return .{
3537 .zir = zir,
3538 .extra_index = extra_index + bit_bags_count,
3539 .bit_bag_index = extra_index,
3540 .cur_bit_bag = undefined,
3541 .decl_i = 0,
3542 .decls_len = decls_len,
3543 };
3544}
3545
35463544/// The iterator would have to allocate memory anyway to iterate. So here we populate
35473545/// an ArrayList as the result.
3548pub fn findDecls(zir: Zir, list: *std.ArrayList(Inst.Index), decl_sub_index: ExtraIndex) !void {
3549 const block_inst: Zir.Inst.Index = @enumFromInt(zir.extra[@intFromEnum(decl_sub_index) + 6]);
3546pub fn findDecls(zir: Zir, list: *std.ArrayList(Inst.Index), decl_inst: Zir.Inst.Index) !void {
35503547 list.clearRetainingCapacity();
3548 const declaration, const extra_end = zir.getDeclaration(decl_inst);
3549 const bodies = declaration.getBodies(extra_end, zir);
35513550
3552 return zir.findDeclsInner(list, block_inst);
3551 try zir.findDeclsBody(list, bodies.value_body);
3552 if (bodies.align_body) |b| try zir.findDeclsBody(list, b);
3553 if (bodies.linksection_body) |b| try zir.findDeclsBody(list, b);
3554 if (bodies.addrspace_body) |b| try zir.findDeclsBody(list, b);
35533555}
35543556
35553557fn findDeclsInner(
......@@ -3791,8 +3793,17 @@ pub fn getParamBody(zir: Zir, fn_inst: Inst.Index) []const Zir.Inst.Index {
37913793 else => unreachable,
37923794 };
37933795
3794 const param_block = zir.extraData(Inst.Block, datas[@intFromEnum(param_block_index)].pl_node.payload_index);
3795 return zir.bodySlice(param_block.end, param_block.data.body_len);
3796 switch (tags[@intFromEnum(param_block_index)]) {
3797 .block, .block_comptime, .block_inline => {
3798 const param_block = zir.extraData(Inst.Block, datas[@intFromEnum(param_block_index)].pl_node.payload_index);
3799 return zir.bodySlice(param_block.end, param_block.data.body_len);
3800 },
3801 .declaration => {
3802 const decl, const extra_end = zir.getDeclaration(param_block_index);
3803 return decl.getBodies(extra_end, zir).value_body;
3804 },
3805 else => unreachable,
3806 }
37963807}
37973808
37983809pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
......@@ -3888,12 +3899,17 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
38883899 },
38893900 else => unreachable,
38903901 };
3891 switch (tags[@intFromEnum(info.param_block)]) {
3892 .block, .block_comptime, .block_inline => {}, // OK
3893 else => unreachable, // assertion failure
3894 }
3895 const param_block = zir.extraData(Inst.Block, datas[@intFromEnum(info.param_block)].pl_node.payload_index);
3896 const param_body = zir.bodySlice(param_block.end, param_block.data.body_len);
3902 const param_body = switch (tags[@intFromEnum(info.param_block)]) {
3903 .block, .block_comptime, .block_inline => param_body: {
3904 const param_block = zir.extraData(Inst.Block, datas[@intFromEnum(info.param_block)].pl_node.payload_index);
3905 break :param_body zir.bodySlice(param_block.end, param_block.data.body_len);
3906 },
3907 .declaration => param_body: {
3908 const decl, const extra_end = zir.getDeclaration(info.param_block);
3909 break :param_body decl.getBodies(extra_end, zir).value_body;
3910 },
3911 else => unreachable,
3912 };
38973913 var total_params_len: u32 = 0;
38983914 for (param_body) |inst| {
38993915 switch (tags[@intFromEnum(inst)]) {
......@@ -3912,3 +3928,13 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
39123928 .total_params_len = total_params_len,
39133929 };
39143930}
3931
3932pub fn getDeclaration(zir: Zir, inst: Zir.Inst.Index) struct { Inst.Declaration, u32 } {
3933 assert(zir.instructions.items(.tag)[@intFromEnum(inst)] == .declaration);
3934 const pl_node = zir.instructions.items(.data)[@intFromEnum(inst)].pl_node;
3935 const extra = zir.extraData(Inst.Declaration, pl_node.payload_index);
3936 return .{
3937 extra.data,
3938 @intCast(extra.end),
3939 };
3940}
src/main.zig+3-14
......@@ -6855,10 +6855,7 @@ pub fn cmdChangelist(
68556855 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};
68566856 defer inst_map.deinit(gpa);
68576857
6858 var extra_map: std.AutoHashMapUnmanaged(Zir.ExtraIndex, Zir.ExtraIndex) = .{};
6859 defer extra_map.deinit(gpa);
6860
6861 try Module.mapOldZirToNew(gpa, old_zir, file.zir, &inst_map, &extra_map);
6858 try Module.mapOldZirToNew(gpa, old_zir, file.zir, &inst_map);
68626859
68636860 var bw = io.bufferedWriter(io.getStdOut().writer());
68646861 const stdout = bw.writer();
......@@ -6867,16 +6864,8 @@ pub fn cmdChangelist(
68676864 var it = inst_map.iterator();
68686865 while (it.next()) |entry| {
68696866 try stdout.print(" %{d} => %{d}\n", .{
6870 entry.key_ptr.*, entry.value_ptr.*,
6871 });
6872 }
6873 }
6874 {
6875 try stdout.print("Extra mappings:\n", .{});
6876 var it = extra_map.iterator();
6877 while (it.next()) |entry| {
6878 try stdout.print(" {d} => {d}\n", .{
6879 entry.key_ptr.*, entry.value_ptr.*,
6867 @intFromEnum(entry.key_ptr.*),
6868 @intFromEnum(entry.value_ptr.*),
68806869 });
68816870 }
68826871 }
src/print_zir.zig+67-122
......@@ -521,6 +521,8 @@ const Writer = struct {
521521 .@"defer" => try self.writeDefer(stream, inst),
522522 .defer_err_code => try self.writeDeferErrCode(stream, inst),
523523
524 .declaration => try self.writeDeclaration(stream, inst),
525
524526 .extended => try self.writeExtended(stream, inst),
525527 }
526528 }
......@@ -1454,8 +1456,9 @@ const Writer = struct {
14541456
14551457 try stream.writeAll("{\n");
14561458 self.indent += 2;
1457 extra_index = try self.writeDecls(stream, decls_len, extra_index);
1459 try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
14581460 self.indent -= 2;
1461 extra_index += decls_len;
14591462 try stream.writeByteNTimes(' ', self.indent);
14601463 try stream.writeAll("}, ");
14611464 }
......@@ -1634,8 +1637,9 @@ const Writer = struct {
16341637
16351638 try stream.writeAll("{\n");
16361639 self.indent += 2;
1637 extra_index = try self.writeDecls(stream, decls_len, extra_index);
1640 try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
16381641 self.indent -= 2;
1642 extra_index += decls_len;
16391643 try stream.writeByteNTimes(' ', self.indent);
16401644 try stream.writeAll("}");
16411645 }
......@@ -1727,124 +1731,6 @@ const Writer = struct {
17271731 try self.writeSrcNode(stream, src_node);
17281732 }
17291733
1730 fn writeDecls(self: *Writer, stream: anytype, decls_len: u32, extra_start: usize) !usize {
1731 const parent_decl_node = self.parent_decl_node;
1732 const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable;
1733 var extra_index = extra_start + bit_bags_count;
1734 var bit_bag_index: usize = extra_start;
1735 var cur_bit_bag: u32 = undefined;
1736 var decl_i: u32 = 0;
1737 while (decl_i < decls_len) : (decl_i += 1) {
1738 if (decl_i % 8 == 0) {
1739 cur_bit_bag = self.code.extra[bit_bag_index];
1740 bit_bag_index += 1;
1741 }
1742 const is_pub = @as(u1, @truncate(cur_bit_bag)) != 0;
1743 cur_bit_bag >>= 1;
1744 const is_exported = @as(u1, @truncate(cur_bit_bag)) != 0;
1745 cur_bit_bag >>= 1;
1746 const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
1747 cur_bit_bag >>= 1;
1748 const has_section_or_addrspace = @as(u1, @truncate(cur_bit_bag)) != 0;
1749 cur_bit_bag >>= 1;
1750
1751 const sub_index = extra_index;
1752
1753 const hash_u32s = self.code.extra[extra_index..][0..4];
1754 extra_index += 4;
1755 const line = self.code.extra[extra_index];
1756 extra_index += 1;
1757 const decl_name_index = self.code.extra[extra_index];
1758 extra_index += 1;
1759 const decl_index: Zir.Inst.Index = @enumFromInt(self.code.extra[extra_index]);
1760 extra_index += 1;
1761 const doc_comment_index: Zir.NullTerminatedString = @enumFromInt(self.code.extra[extra_index]);
1762 extra_index += 1;
1763
1764 const align_inst: Zir.Inst.Ref = if (!has_align) .none else inst: {
1765 const inst = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
1766 extra_index += 1;
1767 break :inst inst;
1768 };
1769 const section_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
1770 const inst = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
1771 extra_index += 1;
1772 break :inst inst;
1773 };
1774 const addrspace_inst: Zir.Inst.Ref = if (!has_section_or_addrspace) .none else inst: {
1775 const inst = @as(Zir.Inst.Ref, @enumFromInt(self.code.extra[extra_index]));
1776 extra_index += 1;
1777 break :inst inst;
1778 };
1779
1780 const pub_str = if (is_pub) "pub " else "";
1781 const hash_bytes: [16]u8 = @bitCast(hash_u32s.*);
1782 if (decl_name_index == 0) {
1783 try stream.writeByteNTimes(' ', self.indent);
1784 const name = if (is_exported) "usingnamespace" else "comptime";
1785 try stream.writeAll(pub_str);
1786 try stream.writeAll(name);
1787 } else if (decl_name_index == 1) {
1788 try stream.writeByteNTimes(' ', self.indent);
1789 try stream.writeAll("test");
1790 } else if (decl_name_index == 2) {
1791 try stream.writeByteNTimes(' ', self.indent);
1792 try stream.print("[{d}] decltest {s}", .{ sub_index, self.code.nullTerminatedString(doc_comment_index) });
1793 } else {
1794 const raw_decl_name = self.code.nullTerminatedString(@enumFromInt(decl_name_index));
1795 const decl_name = if (raw_decl_name.len == 0)
1796 self.code.nullTerminatedString(@enumFromInt(decl_name_index + 1))
1797 else
1798 raw_decl_name;
1799 const test_str = if (raw_decl_name.len == 0) "test \"" else "";
1800 const export_str = if (is_exported) "export " else "";
1801
1802 try self.writeDocComment(stream, doc_comment_index);
1803
1804 try stream.writeByteNTimes(' ', self.indent);
1805 const endquote_if_test: []const u8 = if (raw_decl_name.len == 0) "\"" else "";
1806 try stream.print("[{d}] {s}{s}{s}{}{s}", .{
1807 sub_index, pub_str, test_str, export_str, std.zig.fmtId(decl_name), endquote_if_test,
1808 });
1809 if (align_inst != .none) {
1810 try stream.writeAll(" align(");
1811 try self.writeInstRef(stream, align_inst);
1812 try stream.writeAll(")");
1813 }
1814 if (addrspace_inst != .none) {
1815 try stream.writeAll(" addrspace(");
1816 try self.writeInstRef(stream, addrspace_inst);
1817 try stream.writeAll(")");
1818 }
1819 if (section_inst != .none) {
1820 try stream.writeAll(" linksection(");
1821 try self.writeInstRef(stream, section_inst);
1822 try stream.writeAll(")");
1823 }
1824 }
1825
1826 if (self.recurse_decls) {
1827 const tag = self.code.instructions.items(.tag)[@intFromEnum(decl_index)];
1828 try stream.print(" line({d}) hash({}): %{d} = {s}(", .{
1829 line, std.fmt.fmtSliceHexLower(&hash_bytes), @intFromEnum(decl_index), @tagName(tag),
1830 });
1831
1832 const decl_block_inst_data = self.code.instructions.items(.data)[@intFromEnum(decl_index)].pl_node;
1833 const sub_decl_node_off = decl_block_inst_data.src_node;
1834 self.parent_decl_node = self.relativeToNodeIndex(sub_decl_node_off);
1835 try self.writePlNodeBlockWithoutSrc(stream, decl_index);
1836 self.parent_decl_node = parent_decl_node;
1837 try self.writeSrc(stream, decl_block_inst_data.src());
1838 try stream.writeAll("\n");
1839 } else {
1840 try stream.print(" line({d}) hash({}): %{d} = ...\n", .{
1841 line, std.fmt.fmtSliceHexLower(&hash_bytes), @intFromEnum(decl_index),
1842 });
1843 }
1844 }
1845 return extra_index;
1846 }
1847
18481734 fn writeEnumDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
18491735 const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small));
18501736 var extra_index: usize = extended.operand;
......@@ -1891,8 +1777,9 @@ const Writer = struct {
18911777
18921778 try stream.writeAll("{\n");
18931779 self.indent += 2;
1894 extra_index = try self.writeDecls(stream, decls_len, extra_index);
1780 try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
18951781 self.indent -= 2;
1782 extra_index += decls_len;
18961783 try stream.writeByteNTimes(' ', self.indent);
18971784 try stream.writeAll("}, ");
18981785 }
......@@ -1988,7 +1875,7 @@ const Writer = struct {
19881875
19891876 try stream.writeAll("{\n");
19901877 self.indent += 2;
1991 _ = try self.writeDecls(stream, decls_len, extra_index);
1878 try self.writeBody(stream, self.code.bodySlice(extra_index, decls_len));
19921879 self.indent -= 2;
19931880 try stream.writeByteNTimes(' ', self.indent);
19941881 try stream.writeAll("})");
......@@ -2762,6 +2649,64 @@ const Writer = struct {
27622649 try stream.writeByte(')');
27632650 }
27642651
2652 fn writeDeclaration(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2653 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
2654 const extra = self.code.extraData(Zir.Inst.Declaration, inst_data.payload_index);
2655 const doc_comment: ?Zir.NullTerminatedString = if (extra.data.flags.has_doc_comment) dc: {
2656 break :dc @enumFromInt(self.code.extra[extra.end]);
2657 } else null;
2658 if (extra.data.flags.is_pub) try stream.writeAll("pub ");
2659 if (extra.data.flags.is_export) try stream.writeAll("export ");
2660 switch (extra.data.name) {
2661 .@"comptime" => try stream.writeAll("comptime"),
2662 .@"usingnamespace" => try stream.writeAll("usingnamespace"),
2663 .unnamed_test => try stream.writeAll("test"),
2664 .decltest => try stream.print("decltest '{s}'", .{self.code.nullTerminatedString(doc_comment.?)}),
2665 _ => {
2666 const name = extra.data.name.toString(self.code).?;
2667 const prefix = if (extra.data.name.isNamedTest(self.code)) "test " else "";
2668 try stream.print("{s}'{s}'", .{ prefix, self.code.nullTerminatedString(name) });
2669 },
2670 }
2671 const src_hash_arr: [4]u32 = .{
2672 extra.data.src_hash_0,
2673 extra.data.src_hash_1,
2674 extra.data.src_hash_2,
2675 extra.data.src_hash_3,
2676 };
2677 const src_hash_bytes: [16]u8 = @bitCast(src_hash_arr);
2678 try stream.print(" line(+{d}) hash({})", .{ extra.data.line_offset, std.fmt.fmtSliceHexLower(&src_hash_bytes) });
2679
2680 {
2681 const prev_parent_decl_node = self.parent_decl_node;
2682 defer self.parent_decl_node = prev_parent_decl_node;
2683 self.parent_decl_node = self.relativeToNodeIndex(inst_data.src_node);
2684
2685 const bodies = extra.data.getBodies(@intCast(extra.end), self.code);
2686
2687 try stream.writeAll(" value=");
2688 try self.writeBracedDecl(stream, bodies.value_body);
2689
2690 if (bodies.align_body) |b| {
2691 try stream.writeAll(" align=");
2692 try self.writeBracedDecl(stream, b);
2693 }
2694
2695 if (bodies.linksection_body) |b| {
2696 try stream.writeAll(" linksection=");
2697 try self.writeBracedDecl(stream, b);
2698 }
2699
2700 if (bodies.addrspace_body) |b| {
2701 try stream.writeAll(" addrspace=");
2702 try self.writeBracedDecl(stream, b);
2703 }
2704 }
2705
2706 try stream.writeAll(") ");
2707 try self.writeSrc(stream, inst_data.src());
2708 }
2709
27652710 fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void {
27662711 if (ref == .none) {
27672712 return stream.writeAll(".none");