authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-02-06 11:33:07+00:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-02-06 11:33:07+00:00
log0c8072506883db21d5f8e3e7e7cb45b36d496f28
tree2bdfd1254c7931322ea75ffb2c5823000c5083d0
parent648b492ef1d962cabd7d2f017ef47aef73c0c3aa
parent0784d389844a127248bb724352ce7101bc49784c
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #18814 from mlugg/incremental-dependencies

Begin re-implementing incremental compilation

11 files changed, 1308 insertions(+), 300 deletions(-)

lib/std/zig.zig+3-2
...@@ -27,11 +27,12 @@ pub const parseNumberLiteral = number_literal.parseNumberLiteral;...@@ -27,11 +27,12 @@ pub const parseNumberLiteral = number_literal.parseNumberLiteral;
27pub const c_builtins = @import("zig/c_builtins.zig");27pub const c_builtins = @import("zig/c_builtins.zig");
28pub const c_translation = @import("zig/c_translation.zig");28pub const c_translation = @import("zig/c_translation.zig");
2929
30pub const SrcHasher = std.crypto.hash.Blake3;
30pub const SrcHash = [16]u8;31pub const SrcHash = [16]u8;
3132
32pub fn hashSrc(src: []const u8) SrcHash {33pub fn hashSrc(src: []const u8) SrcHash {
33 var out: SrcHash = undefined;34 var out: SrcHash = undefined;
34 std.crypto.hash.Blake3.hash(src, &out, .{});35 SrcHasher.hash(src, &out, .{});
35 return out;36 return out;
36}37}
3738
...@@ -41,7 +42,7 @@ pub fn srcHashEql(a: SrcHash, b: SrcHash) bool {...@@ -41,7 +42,7 @@ pub fn srcHashEql(a: SrcHash, b: SrcHash) bool {
4142
42pub fn hashName(parent_hash: SrcHash, sep: []const u8, name: []const u8) SrcHash {43pub fn hashName(parent_hash: SrcHash, sep: []const u8, name: []const u8) SrcHash {
43 var out: SrcHash = undefined;44 var out: SrcHash = undefined;
44 var hasher = std.crypto.hash.Blake3.init(.{});45 var hasher = SrcHasher.init(.{});
45 hasher.update(&parent_hash);46 hasher.update(&parent_hash);
46 hasher.update(sep);47 hasher.update(sep);
47 hasher.update(name);48 hasher.update(name);
src/AstGen.zig+93-16
...@@ -4815,6 +4815,7 @@ fn structDeclInner(...@@ -4815,6 +4815,7 @@ fn structDeclInner(
4815 .any_comptime_fields = false,4815 .any_comptime_fields = false,
4816 .any_default_inits = false,4816 .any_default_inits = false,
4817 .any_aligned_fields = false,4817 .any_aligned_fields = false,
4818 .fields_hash = std.zig.hashSrc(@tagName(layout)),
4818 });4819 });
4819 return decl_inst.toRef();4820 return decl_inst.toRef();
4820 }4821 }
...@@ -4936,6 +4937,12 @@ fn structDeclInner(...@@ -4936,6 +4937,12 @@ fn structDeclInner(
4936 }4937 }
4937 };4938 };
49384939
4940 var fields_hasher = std.zig.SrcHasher.init(.{});
4941 fields_hasher.update(@tagName(layout));
4942 if (backing_int_node != 0) {
4943 fields_hasher.update(tree.getNodeSource(backing_int_node));
4944 }
4945
4939 var sfba = std.heap.stackFallback(256, astgen.arena);4946 var sfba = std.heap.stackFallback(256, astgen.arena);
4940 const sfba_allocator = sfba.get();4947 const sfba_allocator = sfba.get();
49414948
...@@ -4956,6 +4963,8 @@ fn structDeclInner(...@@ -4956,6 +4963,8 @@ fn structDeclInner(
4956 .field => |field| field,4963 .field => |field| field,
4957 };4964 };
49584965
4966 fields_hasher.update(tree.getNodeSource(member_node));
4967
4959 if (!is_tuple) {4968 if (!is_tuple) {
4960 const field_name = try astgen.identAsString(member.ast.main_token);4969 const field_name = try astgen.identAsString(member.ast.main_token);
49614970
...@@ -5083,6 +5092,9 @@ fn structDeclInner(...@@ -5083,6 +5092,9 @@ fn structDeclInner(
5083 return error.AnalysisFail;5092 return error.AnalysisFail;
5084 }5093 }
50855094
5095 var fields_hash: std.zig.SrcHash = undefined;
5096 fields_hasher.final(&fields_hash);
5097
5086 try gz.setStruct(decl_inst, .{5098 try gz.setStruct(decl_inst, .{
5087 .src_node = node,5099 .src_node = node,
5088 .layout = layout,5100 .layout = layout,
...@@ -5096,6 +5108,7 @@ fn structDeclInner(...@@ -5096,6 +5108,7 @@ fn structDeclInner(
5096 .any_comptime_fields = any_comptime_fields,5108 .any_comptime_fields = any_comptime_fields,
5097 .any_default_inits = any_default_inits,5109 .any_default_inits = any_default_inits,
5098 .any_aligned_fields = any_aligned_fields,5110 .any_aligned_fields = any_aligned_fields,
5111 .fields_hash = fields_hash,
5099 });5112 });
51005113
5101 wip_members.finishBits(bits_per_field);5114 wip_members.finishBits(bits_per_field);
...@@ -5174,6 +5187,13 @@ fn unionDeclInner(...@@ -5174,6 +5187,13 @@ fn unionDeclInner(
5174 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);5187 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);
5175 defer wip_members.deinit();5188 defer wip_members.deinit();
51765189
5190 var fields_hasher = std.zig.SrcHasher.init(.{});
5191 fields_hasher.update(@tagName(layout));
5192 fields_hasher.update(&.{@intFromBool(auto_enum_tok != null)});
5193 if (arg_node != 0) {
5194 fields_hasher.update(astgen.tree.getNodeSource(arg_node));
5195 }
5196
5177 var sfba = std.heap.stackFallback(256, astgen.arena);5197 var sfba = std.heap.stackFallback(256, astgen.arena);
5178 const sfba_allocator = sfba.get();5198 const sfba_allocator = sfba.get();
51795199
...@@ -5188,6 +5208,7 @@ fn unionDeclInner(...@@ -5188,6 +5208,7 @@ fn unionDeclInner(
5188 .decl => continue,5208 .decl => continue,
5189 .field => |field| field,5209 .field => |field| field,
5190 };5210 };
5211 fields_hasher.update(astgen.tree.getNodeSource(member_node));
5191 member.convertToNonTupleLike(astgen.tree.nodes);5212 member.convertToNonTupleLike(astgen.tree.nodes);
5192 if (member.ast.tuple_like) {5213 if (member.ast.tuple_like) {
5193 return astgen.failTok(member.ast.main_token, "union field missing name", .{});5214 return astgen.failTok(member.ast.main_token, "union field missing name", .{});
...@@ -5289,6 +5310,9 @@ fn unionDeclInner(...@@ -5289,6 +5310,9 @@ fn unionDeclInner(
5289 return error.AnalysisFail;5310 return error.AnalysisFail;
5290 }5311 }
52915312
5313 var fields_hash: std.zig.SrcHash = undefined;
5314 fields_hasher.final(&fields_hash);
5315
5292 if (!block_scope.isEmpty()) {5316 if (!block_scope.isEmpty()) {
5293 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);5317 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
5294 }5318 }
...@@ -5305,6 +5329,7 @@ fn unionDeclInner(...@@ -5305,6 +5329,7 @@ fn unionDeclInner(
5305 .decls_len = decl_count,5329 .decls_len = decl_count,
5306 .auto_enum_tag = auto_enum_tok != null,5330 .auto_enum_tag = auto_enum_tok != null,
5307 .any_aligned_fields = any_aligned_fields,5331 .any_aligned_fields = any_aligned_fields,
5332 .fields_hash = fields_hash,
5308 });5333 });
53095334
5310 wip_members.finishBits(bits_per_field);5335 wip_members.finishBits(bits_per_field);
...@@ -5498,6 +5523,12 @@ fn containerDecl(...@@ -5498,6 +5523,12 @@ fn containerDecl(
5498 var wip_members = try WipMembers.init(gpa, &astgen.scratch, @intCast(counts.decls), @intCast(counts.total_fields), bits_per_field, max_field_size);5523 var wip_members = try WipMembers.init(gpa, &astgen.scratch, @intCast(counts.decls), @intCast(counts.total_fields), bits_per_field, max_field_size);
5499 defer wip_members.deinit();5524 defer wip_members.deinit();
55005525
5526 var fields_hasher = std.zig.SrcHasher.init(.{});
5527 if (container_decl.ast.arg != 0) {
5528 fields_hasher.update(tree.getNodeSource(container_decl.ast.arg));
5529 }
5530 fields_hasher.update(&.{@intFromBool(nonexhaustive)});
5531
5501 var sfba = std.heap.stackFallback(256, astgen.arena);5532 var sfba = std.heap.stackFallback(256, astgen.arena);
5502 const sfba_allocator = sfba.get();5533 const sfba_allocator = sfba.get();
55035534
...@@ -5510,6 +5541,7 @@ fn containerDecl(...@@ -5510,6 +5541,7 @@ fn containerDecl(
5510 for (container_decl.ast.members) |member_node| {5541 for (container_decl.ast.members) |member_node| {
5511 if (member_node == counts.nonexhaustive_node)5542 if (member_node == counts.nonexhaustive_node)
5512 continue;5543 continue;
5544 fields_hasher.update(tree.getNodeSource(member_node));
5513 namespace.base.tag = .namespace;5545 namespace.base.tag = .namespace;
5514 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {5546 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {
5515 .decl => continue,5547 .decl => continue,
...@@ -5590,6 +5622,9 @@ fn containerDecl(...@@ -5590,6 +5622,9 @@ fn containerDecl(
5590 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);5622 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
5591 }5623 }
55925624
5625 var fields_hash: std.zig.SrcHash = undefined;
5626 fields_hasher.final(&fields_hash);
5627
5593 const body = block_scope.instructionsSlice();5628 const body = block_scope.instructionsSlice();
5594 const body_len = astgen.countBodyLenAfterFixups(body);5629 const body_len = astgen.countBodyLenAfterFixups(body);
55955630
...@@ -5600,6 +5635,7 @@ fn containerDecl(...@@ -5600,6 +5635,7 @@ fn containerDecl(
5600 .body_len = body_len,5635 .body_len = body_len,
5601 .fields_len = @intCast(counts.total_fields),5636 .fields_len = @intCast(counts.total_fields),
5602 .decls_len = @intCast(counts.decls),5637 .decls_len = @intCast(counts.decls),
5638 .fields_hash = fields_hash,
5603 });5639 });
56045640
5605 wip_members.finishBits(bits_per_field);5641 wip_members.finishBits(bits_per_field);
...@@ -11900,8 +11936,8 @@ const GenZir = struct {...@@ -11900,8 +11936,8 @@ const GenZir = struct {
1190011936
11901 var body: []Zir.Inst.Index = &[0]Zir.Inst.Index{};11937 var body: []Zir.Inst.Index = &[0]Zir.Inst.Index{};
11902 var ret_body: []Zir.Inst.Index = &[0]Zir.Inst.Index{};11938 var ret_body: []Zir.Inst.Index = &[0]Zir.Inst.Index{};
11903 var src_locs_buffer: [3]u32 = undefined;11939 var src_locs_and_hash_buffer: [7]u32 = undefined;
11904 var src_locs: []u32 = src_locs_buffer[0..0];11940 var src_locs_and_hash: []u32 = src_locs_and_hash_buffer[0..0];
11905 if (args.body_gz) |body_gz| {11941 if (args.body_gz) |body_gz| {
11906 const tree = astgen.tree;11942 const tree = astgen.tree;
11907 const node_tags = tree.nodes.items(.tag);11943 const node_tags = tree.nodes.items(.tag);
...@@ -11916,10 +11952,27 @@ const GenZir = struct {...@@ -11916,10 +11952,27 @@ const GenZir = struct {
11916 const rbrace_column: u32 = @intCast(astgen.source_column);11952 const rbrace_column: u32 = @intCast(astgen.source_column);
1191711953
11918 const columns = args.lbrace_column | (rbrace_column << 16);11954 const columns = args.lbrace_column | (rbrace_column << 16);
11919 src_locs_buffer[0] = args.lbrace_line;11955
11920 src_locs_buffer[1] = rbrace_line;11956 const proto_hash: std.zig.SrcHash = switch (node_tags[fn_decl]) {
11921 src_locs_buffer[2] = columns;11957 .fn_decl => sig_hash: {
11922 src_locs = &src_locs_buffer;11958 const proto_node = node_datas[fn_decl].lhs;
11959 break :sig_hash std.zig.hashSrc(tree.getNodeSource(proto_node));
11960 },
11961 .test_decl => std.zig.hashSrc(""), // tests don't have a prototype
11962 else => unreachable,
11963 };
11964 const proto_hash_arr: [4]u32 = @bitCast(proto_hash);
11965
11966 src_locs_and_hash_buffer = .{
11967 args.lbrace_line,
11968 rbrace_line,
11969 columns,
11970 proto_hash_arr[0],
11971 proto_hash_arr[1],
11972 proto_hash_arr[2],
11973 proto_hash_arr[3],
11974 };
11975 src_locs_and_hash = &src_locs_and_hash_buffer;
1192311976
11924 body = body_gz.instructionsSlice();11977 body = body_gz.instructionsSlice();
11925 if (args.ret_gz) |ret_gz|11978 if (args.ret_gz) |ret_gz|
...@@ -11953,7 +12006,7 @@ const GenZir = struct {...@@ -11953,7 +12006,7 @@ const GenZir = struct {
11953 fancyFnExprExtraLen(astgen, section_body, args.section_ref) +12006 fancyFnExprExtraLen(astgen, section_body, args.section_ref) +
11954 fancyFnExprExtraLen(astgen, cc_body, args.cc_ref) +12007 fancyFnExprExtraLen(astgen, cc_body, args.cc_ref) +
11955 fancyFnExprExtraLen(astgen, ret_body, ret_ref) +12008 fancyFnExprExtraLen(astgen, ret_body, ret_ref) +
11956 body_len + src_locs.len +12009 body_len + src_locs_and_hash.len +
11957 @intFromBool(args.lib_name != .empty) +12010 @intFromBool(args.lib_name != .empty) +
11958 @intFromBool(args.noalias_bits != 0),12011 @intFromBool(args.noalias_bits != 0),
11959 );12012 );
...@@ -12040,7 +12093,7 @@ const GenZir = struct {...@@ -12040,7 +12093,7 @@ const GenZir = struct {
12040 }12093 }
1204112094
12042 astgen.appendBodyWithFixups(body);12095 astgen.appendBodyWithFixups(body);
12043 astgen.extra.appendSliceAssumeCapacity(src_locs);12096 astgen.extra.appendSliceAssumeCapacity(src_locs_and_hash);
1204412097
12045 // Order is important when unstacking.12098 // Order is important when unstacking.
12046 if (args.body_gz) |body_gz| body_gz.unstack();12099 if (args.body_gz) |body_gz| body_gz.unstack();
...@@ -12068,7 +12121,7 @@ const GenZir = struct {...@@ -12068,7 +12121,7 @@ const GenZir = struct {
12068 gpa,12121 gpa,
12069 @typeInfo(Zir.Inst.Func).Struct.fields.len + 1 +12122 @typeInfo(Zir.Inst.Func).Struct.fields.len + 1 +
12070 fancyFnExprExtraLen(astgen, ret_body, ret_ref) +12123 fancyFnExprExtraLen(astgen, ret_body, ret_ref) +
12071 body_len + src_locs.len,12124 body_len + src_locs_and_hash.len,
12072 );12125 );
1207312126
12074 const ret_body_len = if (ret_body.len != 0)12127 const ret_body_len = if (ret_body.len != 0)
...@@ -12092,7 +12145,7 @@ const GenZir = struct {...@@ -12092,7 +12145,7 @@ const GenZir = struct {
12092 astgen.extra.appendAssumeCapacity(@intFromEnum(ret_ref));12145 astgen.extra.appendAssumeCapacity(@intFromEnum(ret_ref));
12093 }12146 }
12094 astgen.appendBodyWithFixups(body);12147 astgen.appendBodyWithFixups(body);
12095 astgen.extra.appendSliceAssumeCapacity(src_locs);12148 astgen.extra.appendSliceAssumeCapacity(src_locs_and_hash);
1209612149
12097 // Order is important when unstacking.12150 // Order is important when unstacking.
12098 if (args.body_gz) |body_gz| body_gz.unstack();12151 if (args.body_gz) |body_gz| body_gz.unstack();
...@@ -12853,12 +12906,20 @@ const GenZir = struct {...@@ -12853,12 +12906,20 @@ const GenZir = struct {
12853 any_comptime_fields: bool,12906 any_comptime_fields: bool,
12854 any_default_inits: bool,12907 any_default_inits: bool,
12855 any_aligned_fields: bool,12908 any_aligned_fields: bool,
12909 fields_hash: std.zig.SrcHash,
12856 }) !void {12910 }) !void {
12857 const astgen = gz.astgen;12911 const astgen = gz.astgen;
12858 const gpa = astgen.gpa;12912 const gpa = astgen.gpa;
1285912913
12860 try astgen.extra.ensureUnusedCapacity(gpa, 6);12914 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
12861 const payload_index: u32 = @intCast(astgen.extra.items.len);12915
12916 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.StructDecl).Struct.fields.len + 6);
12917 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.StructDecl{
12918 .fields_hash_0 = fields_hash_arr[0],
12919 .fields_hash_1 = fields_hash_arr[1],
12920 .fields_hash_2 = fields_hash_arr[2],
12921 .fields_hash_3 = fields_hash_arr[3],
12922 });
1286212923
12863 if (args.src_node != 0) {12924 if (args.src_node != 0) {
12864 const node_offset = gz.nodeIndexToRelative(args.src_node);12925 const node_offset = gz.nodeIndexToRelative(args.src_node);
...@@ -12908,12 +12969,20 @@ const GenZir = struct {...@@ -12908,12 +12969,20 @@ const GenZir = struct {
12908 layout: std.builtin.Type.ContainerLayout,12969 layout: std.builtin.Type.ContainerLayout,
12909 auto_enum_tag: bool,12970 auto_enum_tag: bool,
12910 any_aligned_fields: bool,12971 any_aligned_fields: bool,
12972 fields_hash: std.zig.SrcHash,
12911 }) !void {12973 }) !void {
12912 const astgen = gz.astgen;12974 const astgen = gz.astgen;
12913 const gpa = astgen.gpa;12975 const gpa = astgen.gpa;
1291412976
12915 try astgen.extra.ensureUnusedCapacity(gpa, 5);12977 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
12916 const payload_index: u32 = @intCast(astgen.extra.items.len);12978
12979 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.UnionDecl).Struct.fields.len + 5);
12980 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.UnionDecl{
12981 .fields_hash_0 = fields_hash_arr[0],
12982 .fields_hash_1 = fields_hash_arr[1],
12983 .fields_hash_2 = fields_hash_arr[2],
12984 .fields_hash_3 = fields_hash_arr[3],
12985 });
1291712986
12918 if (args.src_node != 0) {12987 if (args.src_node != 0) {
12919 const node_offset = gz.nodeIndexToRelative(args.src_node);12988 const node_offset = gz.nodeIndexToRelative(args.src_node);
...@@ -12958,12 +13027,20 @@ const GenZir = struct {...@@ -12958,12 +13027,20 @@ const GenZir = struct {
12958 fields_len: u32,13027 fields_len: u32,
12959 decls_len: u32,13028 decls_len: u32,
12960 nonexhaustive: bool,13029 nonexhaustive: bool,
13030 fields_hash: std.zig.SrcHash,
12961 }) !void {13031 }) !void {
12962 const astgen = gz.astgen;13032 const astgen = gz.astgen;
12963 const gpa = astgen.gpa;13033 const gpa = astgen.gpa;
1296413034
12965 try astgen.extra.ensureUnusedCapacity(gpa, 5);13035 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
12966 const payload_index: u32 = @intCast(astgen.extra.items.len);13036
13037 try astgen.extra.ensureUnusedCapacity(gpa, @typeInfo(Zir.Inst.EnumDecl).Struct.fields.len + 5);
13038 const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.EnumDecl{
13039 .fields_hash_0 = fields_hash_arr[0],
13040 .fields_hash_1 = fields_hash_arr[1],
13041 .fields_hash_2 = fields_hash_arr[2],
13042 .fields_hash_3 = fields_hash_arr[3],
13043 });
1296713044
12968 if (args.src_node != 0) {13045 if (args.src_node != 0) {
12969 const node_offset = gz.nodeIndexToRelative(args.src_node);13046 const node_offset = gz.nodeIndexToRelative(args.src_node);
src/Autodoc.zig+3-3
...@@ -3497,7 +3497,7 @@ fn walkInstruction(...@@ -3497,7 +3497,7 @@ fn walkInstruction(
3497 };3497 };
34983498
3499 const small = @as(Zir.Inst.UnionDecl.Small, @bitCast(extended.small));3499 const small = @as(Zir.Inst.UnionDecl.Small, @bitCast(extended.small));
3500 var extra_index: usize = extended.operand;3500 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.UnionDecl).Struct.fields.len;
35013501
3502 const src_node: ?i32 = if (small.has_src_node) blk: {3502 const src_node: ?i32 = if (small.has_src_node) blk: {
3503 const src_node = @as(i32, @bitCast(file.zir.extra[extra_index]));3503 const src_node = @as(i32, @bitCast(file.zir.extra[extra_index]));
...@@ -3627,7 +3627,7 @@ fn walkInstruction(...@@ -3627,7 +3627,7 @@ fn walkInstruction(
3627 };3627 };
36283628
3629 const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small));3629 const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small));
3630 var extra_index: usize = extended.operand;3630 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.EnumDecl).Struct.fields.len;
36313631
3632 const src_node: ?i32 = if (small.has_src_node) blk: {3632 const src_node: ?i32 = if (small.has_src_node) blk: {
3633 const src_node = @as(i32, @bitCast(file.zir.extra[extra_index]));3633 const src_node = @as(i32, @bitCast(file.zir.extra[extra_index]));
...@@ -3778,7 +3778,7 @@ fn walkInstruction(...@@ -3778,7 +3778,7 @@ fn walkInstruction(
3778 };3778 };
37793779
3780 const small = @as(Zir.Inst.StructDecl.Small, @bitCast(extended.small));3780 const small = @as(Zir.Inst.StructDecl.Small, @bitCast(extended.small));
3781 var extra_index: usize = extended.operand;3781 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
37823782
3783 const src_node: ?i32 = if (small.has_src_node) blk: {3783 const src_node: ?i32 = if (small.has_src_node) blk: {
3784 const src_node = @as(i32, @bitCast(file.zir.extra[extra_index]));3784 const src_node = @as(i32, @bitCast(file.zir.extra[extra_index]));
src/Compilation.zig+48-13
...@@ -156,6 +156,7 @@ time_report: bool,...@@ -156,6 +156,7 @@ time_report: bool,
156stack_report: bool,156stack_report: bool,
157debug_compiler_runtime_libs: bool,157debug_compiler_runtime_libs: bool,
158debug_compile_errors: bool,158debug_compile_errors: bool,
159debug_incremental: bool,
159job_queued_compiler_rt_lib: bool = false,160job_queued_compiler_rt_lib: bool = false,
160job_queued_compiler_rt_obj: bool = false,161job_queued_compiler_rt_obj: bool = false,
161job_queued_update_builtin_zig: bool,162job_queued_update_builtin_zig: bool,
...@@ -1079,6 +1080,7 @@ pub const CreateOptions = struct {...@@ -1079,6 +1080,7 @@ pub const CreateOptions = struct {
1079 verbose_llvm_cpu_features: bool = false,1080 verbose_llvm_cpu_features: bool = false,
1080 debug_compiler_runtime_libs: bool = false,1081 debug_compiler_runtime_libs: bool = false,
1081 debug_compile_errors: bool = false,1082 debug_compile_errors: bool = false,
1083 debug_incremental: bool = false,
1082 /// Normally when you create a `Compilation`, Zig will automatically build1084 /// Normally when you create a `Compilation`, Zig will automatically build
1083 /// and link in required dependencies, such as compiler-rt and libc. When1085 /// and link in required dependencies, such as compiler-rt and libc. When
1084 /// building such dependencies themselves, this flag must be set to avoid1086 /// building such dependencies themselves, this flag must be set to avoid
...@@ -1508,6 +1510,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil...@@ -1508,6 +1510,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
1508 .test_name_prefix = options.test_name_prefix,1510 .test_name_prefix = options.test_name_prefix,
1509 .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,1511 .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,
1510 .debug_compile_errors = options.debug_compile_errors,1512 .debug_compile_errors = options.debug_compile_errors,
1513 .debug_incremental = options.debug_incremental,
1511 .libcxx_abi_version = options.libcxx_abi_version,1514 .libcxx_abi_version = options.libcxx_abi_version,
1512 .root_name = root_name,1515 .root_name = root_name,
1513 .sysroot = sysroot,1516 .sysroot = sysroot,
...@@ -2141,7 +2144,6 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void...@@ -2141,7 +2144,6 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void
21412144
2142 if (comp.module) |module| {2145 if (comp.module) |module| {
2143 module.compile_log_text.shrinkAndFree(gpa, 0);2146 module.compile_log_text.shrinkAndFree(gpa, 0);
2144 module.generation += 1;
21452147
2146 // Make sure std.zig is inside the import_table. We unconditionally need2148 // Make sure std.zig is inside the import_table. We unconditionally need
2147 // it for start.zig.2149 // it for start.zig.
...@@ -2807,6 +2809,13 @@ const Header = extern struct {...@@ -2807,6 +2809,13 @@ const Header = extern struct {
2807 limbs_len: u32,2809 limbs_len: u32,
2808 string_bytes_len: u32,2810 string_bytes_len: u32,
2809 tracked_insts_len: u32,2811 tracked_insts_len: u32,
2812 src_hash_deps_len: u32,
2813 decl_val_deps_len: u32,
2814 namespace_deps_len: u32,
2815 namespace_name_deps_len: u32,
2816 first_dependency_len: u32,
2817 dep_entries_len: u32,
2818 free_dep_entries_len: u32,
2810 },2819 },
2811};2820};
28122821
...@@ -2814,7 +2823,7 @@ const Header = extern struct {...@@ -2814,7 +2823,7 @@ const Header = extern struct {
2814/// saved, such as the target and most CLI flags. A cache hit will only occur2823/// saved, such as the target and most CLI flags. A cache hit will only occur
2815/// when subsequent compiler invocations use the same set of flags.2824/// when subsequent compiler invocations use the same set of flags.
2816pub fn saveState(comp: *Compilation) !void {2825pub fn saveState(comp: *Compilation) !void {
2817 var bufs_list: [7]std.os.iovec_const = undefined;2826 var bufs_list: [19]std.os.iovec_const = undefined;
2818 var bufs_len: usize = 0;2827 var bufs_len: usize = 0;
28192828
2820 const lf = comp.bin_file orelse return;2829 const lf = comp.bin_file orelse return;
...@@ -2828,6 +2837,13 @@ pub fn saveState(comp: *Compilation) !void {...@@ -2828,6 +2837,13 @@ pub fn saveState(comp: *Compilation) !void {
2828 .limbs_len = @intCast(ip.limbs.items.len),2837 .limbs_len = @intCast(ip.limbs.items.len),
2829 .string_bytes_len = @intCast(ip.string_bytes.items.len),2838 .string_bytes_len = @intCast(ip.string_bytes.items.len),
2830 .tracked_insts_len = @intCast(ip.tracked_insts.count()),2839 .tracked_insts_len = @intCast(ip.tracked_insts.count()),
2840 .src_hash_deps_len = @intCast(ip.src_hash_deps.count()),
2841 .decl_val_deps_len = @intCast(ip.decl_val_deps.count()),
2842 .namespace_deps_len = @intCast(ip.namespace_deps.count()),
2843 .namespace_name_deps_len = @intCast(ip.namespace_name_deps.count()),
2844 .first_dependency_len = @intCast(ip.first_dependency.count()),
2845 .dep_entries_len = @intCast(ip.dep_entries.items.len),
2846 .free_dep_entries_len = @intCast(ip.free_dep_entries.items.len),
2831 },2847 },
2832 };2848 };
2833 addBuf(&bufs_list, &bufs_len, mem.asBytes(&header));2849 addBuf(&bufs_list, &bufs_len, mem.asBytes(&header));
...@@ -2838,6 +2854,20 @@ pub fn saveState(comp: *Compilation) !void {...@@ -2838,6 +2854,20 @@ pub fn saveState(comp: *Compilation) !void {
2838 addBuf(&bufs_list, &bufs_len, ip.string_bytes.items);2854 addBuf(&bufs_list, &bufs_len, ip.string_bytes.items);
2839 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.tracked_insts.keys()));2855 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.tracked_insts.keys()));
28402856
2857 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.src_hash_deps.keys()));
2858 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.src_hash_deps.values()));
2859 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.decl_val_deps.keys()));
2860 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.decl_val_deps.values()));
2861 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.namespace_deps.keys()));
2862 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.namespace_deps.values()));
2863 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.namespace_name_deps.keys()));
2864 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.namespace_name_deps.values()));
2865
2866 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.first_dependency.keys()));
2867 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.first_dependency.values()));
2868 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.dep_entries.items));
2869 addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.free_dep_entries.items));
2870
2841 // TODO: compilation errors2871 // TODO: compilation errors
2842 // TODO: files2872 // TODO: files
2843 // TODO: namespaces2873 // TODO: namespaces
...@@ -3463,9 +3493,7 @@ pub fn performAllTheWork(...@@ -3463,9 +3493,7 @@ pub fn performAllTheWork(
34633493
3464 if (comp.module) |mod| {3494 if (comp.module) |mod| {
3465 try reportMultiModuleErrors(mod);3495 try reportMultiModuleErrors(mod);
3466 }3496 try mod.flushRetryableFailures();
3467
3468 if (comp.module) |mod| {
3469 mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);3497 mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
3470 mod.sema_prog_node.activate();3498 mod.sema_prog_node.activate();
3471 }3499 }
...@@ -3486,6 +3514,17 @@ pub fn performAllTheWork(...@@ -3486,6 +3514,17 @@ pub fn performAllTheWork(
3486 try processOneJob(comp, work_item, main_progress_node);3514 try processOneJob(comp, work_item, main_progress_node);
3487 continue;3515 continue;
3488 }3516 }
3517 if (comp.module) |zcu| {
3518 // If there's no work queued, check if there's anything outdated
3519 // which we need to work on, and queue it if so.
3520 if (try zcu.findOutdatedToAnalyze()) |outdated| {
3521 switch (outdated.unwrap()) {
3522 .decl => |decl| try comp.work_queue.writeItem(.{ .analyze_decl = decl }),
3523 .func => |func| try comp.work_queue.writeItem(.{ .codegen_func = func }),
3524 }
3525 continue;
3526 }
3527 }
3489 break;3528 break;
3490 }3529 }
34913530
...@@ -3509,17 +3548,14 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v...@@ -3509,17 +3548,14 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
3509 switch (decl.analysis) {3548 switch (decl.analysis) {
3510 .unreferenced => unreachable,3549 .unreferenced => unreachable,
3511 .in_progress => unreachable,3550 .in_progress => unreachable,
3512 .outdated => unreachable,
35133551
3514 .file_failure,3552 .file_failure,
3515 .sema_failure,3553 .sema_failure,
3516 .liveness_failure,
3517 .codegen_failure,3554 .codegen_failure,
3518 .dependency_failure,3555 .dependency_failure,
3519 .sema_failure_retryable,
3520 => return,3556 => return,
35213557
3522 .complete, .codegen_failure_retryable => {3558 .complete => {
3523 const named_frame = tracy.namedFrame("codegen_decl");3559 const named_frame = tracy.namedFrame("codegen_decl");
3524 defer named_frame.end();3560 defer named_frame.end();
35253561
...@@ -3554,17 +3590,15 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v...@@ -3554,17 +3590,15 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
3554 switch (decl.analysis) {3590 switch (decl.analysis) {
3555 .unreferenced => unreachable,3591 .unreferenced => unreachable,
3556 .in_progress => unreachable,3592 .in_progress => unreachable,
3557 .outdated => unreachable,
35583593
3559 .file_failure,3594 .file_failure,
3560 .sema_failure,3595 .sema_failure,
3561 .dependency_failure,3596 .dependency_failure,
3562 .sema_failure_retryable,
3563 => return,3597 => return,
35643598
3565 // emit-h only requires semantic analysis of the Decl to be complete,3599 // emit-h only requires semantic analysis of the Decl to be complete,
3566 // it does not depend on machine code generation to succeed.3600 // it does not depend on machine code generation to succeed.
3567 .liveness_failure, .codegen_failure, .codegen_failure_retryable, .complete => {3601 .codegen_failure, .complete => {
3568 const named_frame = tracy.namedFrame("emit_h_decl");3602 const named_frame = tracy.namedFrame("emit_h_decl");
3569 defer named_frame.end();3603 defer named_frame.end();
35703604
...@@ -3636,7 +3670,8 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v...@@ -3636,7 +3670,8 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
3636 "unable to update line number: {s}",3670 "unable to update line number: {s}",
3637 .{@errorName(err)},3671 .{@errorName(err)},
3638 ));3672 ));
3639 decl.analysis = .codegen_failure_retryable;3673 decl.analysis = .codegen_failure;
3674 try module.retryable_failures.append(gpa, InternPool.Depender.wrap(.{ .decl = decl_index }));
3640 };3675 };
3641 },3676 },
3642 .analyze_mod => |pkg| {3677 .analyze_mod => |pkg| {
src/InternPool.zig+283-16
...@@ -58,6 +58,38 @@ string_table: std.HashMapUnmanaged(...@@ -58,6 +58,38 @@ string_table: std.HashMapUnmanaged(
58/// persists across incremental updates.58/// persists across incremental updates.
59tracked_insts: std.AutoArrayHashMapUnmanaged(TrackedInst, void) = .{},59tracked_insts: std.AutoArrayHashMapUnmanaged(TrackedInst, void) = .{},
6060
61/// Dependencies on the source code hash associated with a ZIR instruction.
62/// * For a `declaration`, this is the entire declaration body.
63/// * For a `struct_decl`, `union_decl`, etc, this is the source of the fields (but not declarations).
64/// * For a `func`, this is the source of the full function signature.
65/// These are also invalidated if tracking fails for this instruction.
66/// Value is index into `dep_entries` of the first dependency on this hash.
67src_hash_deps: std.AutoArrayHashMapUnmanaged(TrackedInst.Index, DepEntry.Index) = .{},
68/// Dependencies on the value of a Decl.
69/// Value is index into `dep_entries` of the first dependency on this Decl value.
70decl_val_deps: std.AutoArrayHashMapUnmanaged(DeclIndex, DepEntry.Index) = .{},
71/// Dependencies on the full set of names in a ZIR namespace.
72/// Key refers to a `struct_decl`, `union_decl`, etc.
73/// Value is index into `dep_entries` of the first dependency on this namespace.
74namespace_deps: std.AutoArrayHashMapUnmanaged(TrackedInst.Index, DepEntry.Index) = .{},
75/// Dependencies on the (non-)existence of some name in a namespace.
76/// Value is index into `dep_entries` of the first dependency on this name.
77namespace_name_deps: std.AutoArrayHashMapUnmanaged(NamespaceNameKey, DepEntry.Index) = .{},
78
79/// Given a `Depender`, points to an entry in `dep_entries` whose `depender`
80/// matches. The `next_dependee` field can be used to iterate all such entries
81/// and remove them from the corresponding lists.
82first_dependency: std.AutoArrayHashMapUnmanaged(Depender, DepEntry.Index) = .{},
83
84/// Stores dependency information. The hashmaps declared above are used to look
85/// up entries in this list as required. This is not stored in `extra` so that
86/// we can use `free_dep_entries` to track free indices, since dependencies are
87/// removed frequently.
88dep_entries: std.ArrayListUnmanaged(DepEntry) = .{},
89/// Stores unused indices in `dep_entries` which can be reused without a full
90/// garbage collection pass.
91free_dep_entries: std.ArrayListUnmanaged(DepEntry.Index) = .{},
92
61pub const TrackedInst = extern struct {93pub const TrackedInst = extern struct {
62 path_digest: Cache.BinDigest,94 path_digest: Cache.BinDigest,
63 inst: Zir.Inst.Index,95 inst: Zir.Inst.Index,
...@@ -70,6 +102,19 @@ pub const TrackedInst = extern struct {...@@ -70,6 +102,19 @@ pub const TrackedInst = extern struct {
70 pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) Zir.Inst.Index {102 pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) Zir.Inst.Index {
71 return ip.tracked_insts.keys()[@intFromEnum(i)].inst;103 return ip.tracked_insts.keys()[@intFromEnum(i)].inst;
72 }104 }
105 pub fn toOptional(i: TrackedInst.Index) Optional {
106 return @enumFromInt(@intFromEnum(i));
107 }
108 pub const Optional = enum(u32) {
109 none = std.math.maxInt(u32),
110 _,
111 pub fn unwrap(opt: Optional) ?TrackedInst.Index {
112 return switch (opt) {
113 .none => null,
114 _ => @enumFromInt(@intFromEnum(opt)),
115 };
116 }
117 };
73 };118 };
74};119};
75120
...@@ -82,6 +127,202 @@ pub fn trackZir(ip: *InternPool, gpa: Allocator, file: *Module.File, inst: Zir.I...@@ -82,6 +127,202 @@ pub fn trackZir(ip: *InternPool, gpa: Allocator, file: *Module.File, inst: Zir.I
82 return @enumFromInt(gop.index);127 return @enumFromInt(gop.index);
83}128}
84129
130/// Reperesents the "source" of a dependency edge, i.e. either a Decl or a
131/// runtime function (represented as an InternPool index).
132/// MSB is 0 for a Decl, 1 for a function.
133pub const Depender = enum(u32) {
134 _,
135 pub const Unwrapped = union(enum) {
136 decl: DeclIndex,
137 func: InternPool.Index,
138 };
139 pub fn unwrap(dep: Depender) Unwrapped {
140 const tag: u1 = @truncate(@intFromEnum(dep) >> 31);
141 const val: u31 = @truncate(@intFromEnum(dep));
142 return switch (tag) {
143 0 => .{ .decl = @enumFromInt(val) },
144 1 => .{ .func = @enumFromInt(val) },
145 };
146 }
147 pub fn wrap(raw: Unwrapped) Depender {
148 return @enumFromInt(switch (raw) {
149 .decl => |decl| @intFromEnum(decl),
150 .func => |func| (1 << 31) | @intFromEnum(func),
151 });
152 }
153 pub fn toOptional(dep: Depender) Optional {
154 return @enumFromInt(@intFromEnum(dep));
155 }
156 pub const Optional = enum(u32) {
157 none = std.math.maxInt(u32),
158 _,
159 pub fn unwrap(opt: Optional) ?Depender {
160 return switch (opt) {
161 .none => null,
162 _ => @enumFromInt(@intFromEnum(opt)),
163 };
164 }
165 };
166};
167
168pub const Dependee = union(enum) {
169 src_hash: TrackedInst.Index,
170 decl_val: DeclIndex,
171 namespace: TrackedInst.Index,
172 namespace_name: NamespaceNameKey,
173};
174
175pub fn removeDependenciesForDepender(ip: *InternPool, gpa: Allocator, depender: Depender) void {
176 var opt_idx = (ip.first_dependency.fetchSwapRemove(depender) orelse return).value.toOptional();
177
178 while (opt_idx.unwrap()) |idx| {
179 const dep = ip.dep_entries.items[@intFromEnum(idx)];
180 opt_idx = dep.next_dependee;
181
182 const prev_idx = dep.prev.unwrap() orelse {
183 // This entry is the start of a list in some `*_deps`.
184 // We cannot easily remove this mapping, so this must remain as a dummy entry.
185 ip.dep_entries.items[@intFromEnum(idx)].depender = .none;
186 continue;
187 };
188
189 ip.dep_entries.items[@intFromEnum(prev_idx)].next = dep.next;
190 if (dep.next.unwrap()) |next_idx| {
191 ip.dep_entries.items[@intFromEnum(next_idx)].prev = dep.prev;
192 }
193
194 ip.free_dep_entries.append(gpa, idx) catch {
195 // This memory will be reclaimed on the next garbage collection.
196 // Thus, we do not need to propagate this error.
197 };
198 }
199}
200
201pub const DependencyIterator = struct {
202 ip: *const InternPool,
203 next_entry: DepEntry.Index.Optional,
204 pub fn next(it: *DependencyIterator) ?Depender {
205 const idx = it.next_entry.unwrap() orelse return null;
206 const entry = it.ip.dep_entries.items[@intFromEnum(idx)];
207 it.next_entry = entry.next;
208 return entry.depender.unwrap().?;
209 }
210};
211
212pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyIterator {
213 const first_entry = switch (dependee) {
214 .src_hash => |x| ip.src_hash_deps.get(x),
215 .decl_val => |x| ip.decl_val_deps.get(x),
216 .namespace => |x| ip.namespace_deps.get(x),
217 .namespace_name => |x| ip.namespace_name_deps.get(x),
218 } orelse return .{
219 .ip = ip,
220 .next_entry = .none,
221 };
222 if (ip.dep_entries.items[@intFromEnum(first_entry)].depender == .none) return .{
223 .ip = ip,
224 .next_entry = .none,
225 };
226 return .{
227 .ip = ip,
228 .next_entry = first_entry.toOptional(),
229 };
230}
231
232pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: Depender, dependee: Dependee) Allocator.Error!void {
233 const first_depender_dep: DepEntry.Index.Optional = if (ip.first_dependency.get(depender)) |idx| dep: {
234 // The entry already exists, so there is capacity to overwrite it later.
235 break :dep idx.toOptional();
236 } else none: {
237 // Ensure there is capacity available to add this dependency later.
238 try ip.first_dependency.ensureUnusedCapacity(gpa, 1);
239 break :none .none;
240 };
241
242 // We're very likely to need space for a new entry - reserve it now to avoid
243 // the need for error cleanup logic.
244 if (ip.free_dep_entries.items.len == 0) {
245 try ip.dep_entries.ensureUnusedCapacity(gpa, 1);
246 }
247
248 // This block should allocate an entry and prepend it to the relevant `*_deps` list.
249 // The `next` field should be correctly initialized; all other fields may be undefined.
250 const new_index: DepEntry.Index = switch (dependee) {
251 inline else => |dependee_payload, tag| new_index: {
252 const gop = try switch (tag) {
253 .src_hash => ip.src_hash_deps,
254 .decl_val => ip.decl_val_deps,
255 .namespace => ip.namespace_deps,
256 .namespace_name => ip.namespace_name_deps,
257 }.getOrPut(gpa, dependee_payload);
258
259 if (gop.found_existing and ip.dep_entries.items[@intFromEnum(gop.value_ptr.*)].depender == .none) {
260 // Dummy entry, so we can reuse it rather than allocating a new one!
261 ip.dep_entries.items[@intFromEnum(gop.value_ptr.*)].next = .none;
262 break :new_index gop.value_ptr.*;
263 }
264
265 // Prepend a new dependency.
266 const new_index: DepEntry.Index, const ptr = if (ip.free_dep_entries.popOrNull()) |new_index| new: {
267 break :new .{ new_index, &ip.dep_entries.items[@intFromEnum(new_index)] };
268 } else .{ @enumFromInt(ip.dep_entries.items.len), ip.dep_entries.addOneAssumeCapacity() };
269 ptr.next = if (gop.found_existing) gop.value_ptr.*.toOptional() else .none;
270 gop.value_ptr.* = new_index;
271 break :new_index new_index;
272 },
273 };
274
275 ip.dep_entries.items[@intFromEnum(new_index)].depender = depender.toOptional();
276 ip.dep_entries.items[@intFromEnum(new_index)].prev = .none;
277 ip.dep_entries.items[@intFromEnum(new_index)].next_dependee = first_depender_dep;
278 ip.first_dependency.putAssumeCapacity(depender, new_index);
279}
280
281/// String is the name whose existence the dependency is on.
282/// DepEntry.Index refers to the first such dependency.
283pub const NamespaceNameKey = struct {
284 /// The instruction (`struct_decl` etc) which owns the namespace in question.
285 namespace: TrackedInst.Index,
286 /// The name whose existence the dependency is on.
287 name: NullTerminatedString,
288};
289
290pub const DepEntry = extern struct {
291 /// If null, this is a dummy entry - all other fields are `undefined`. It is
292 /// the first and only entry in one of `intern_pool.*_deps`, and does not
293 /// appear in any list by `first_dependency`, but is not in
294 /// `free_dep_entries` since `*_deps` stores a reference to it.
295 depender: Depender.Optional,
296 /// Index into `dep_entries` forming a doubly linked list of all dependencies on this dependee.
297 /// Used to iterate all dependers for a given dependee during an update.
298 /// null if this is the end of the list.
299 next: DepEntry.Index.Optional,
300 /// The other link for `next`.
301 /// null if this is the start of the list.
302 prev: DepEntry.Index.Optional,
303 /// Index into `dep_entries` forming a singly linked list of dependencies *of* `depender`.
304 /// Used to efficiently remove all `DepEntry`s for a single `depender` when it is re-analyzed.
305 /// null if this is the end of the list.
306 next_dependee: DepEntry.Index.Optional,
307
308 pub const Index = enum(u32) {
309 _,
310 pub fn toOptional(dep: DepEntry.Index) Optional {
311 return @enumFromInt(@intFromEnum(dep));
312 }
313 pub const Optional = enum(u32) {
314 none = std.math.maxInt(u32),
315 _,
316 pub fn unwrap(opt: Optional) ?DepEntry.Index {
317 return switch (opt) {
318 .none => null,
319 _ => @enumFromInt(@intFromEnum(opt)),
320 };
321 }
322 };
323 };
324};
325
85const FieldMap = std.ArrayHashMapUnmanaged(void, void, std.array_hash_map.AutoContext(void), false);326const FieldMap = std.ArrayHashMapUnmanaged(void, void, std.array_hash_map.AutoContext(void), false);
86327
87const builtin = @import("builtin");328const builtin = @import("builtin");
...@@ -428,6 +669,7 @@ pub const Key = union(enum) {...@@ -428,6 +669,7 @@ pub const Key = union(enum) {
428 decl: DeclIndex,669 decl: DeclIndex,
429 /// Represents the declarations inside this opaque.670 /// Represents the declarations inside this opaque.
430 namespace: NamespaceIndex,671 namespace: NamespaceIndex,
672 zir_index: TrackedInst.Index.Optional,
431 };673 };
432674
433 /// Although packed structs and non-packed structs are encoded differently,675 /// Although packed structs and non-packed structs are encoded differently,
...@@ -440,7 +682,7 @@ pub const Key = union(enum) {...@@ -440,7 +682,7 @@ pub const Key = union(enum) {
440 /// `none` when the struct has no declarations.682 /// `none` when the struct has no declarations.
441 namespace: OptionalNamespaceIndex,683 namespace: OptionalNamespaceIndex,
442 /// Index of the struct_decl ZIR instruction.684 /// Index of the struct_decl ZIR instruction.
443 zir_index: TrackedInst.Index,685 zir_index: TrackedInst.Index.Optional,
444 layout: std.builtin.Type.ContainerLayout,686 layout: std.builtin.Type.ContainerLayout,
445 field_names: NullTerminatedString.Slice,687 field_names: NullTerminatedString.Slice,
446 field_types: Index.Slice,688 field_types: Index.Slice,
...@@ -684,7 +926,7 @@ pub const Key = union(enum) {...@@ -684,7 +926,7 @@ pub const Key = union(enum) {
684 }926 }
685927
686 /// Asserts the struct is not packed.928 /// Asserts the struct is not packed.
687 pub fn setZirIndex(s: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index) void {929 pub fn setZirIndex(s: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void {
688 assert(s.layout != .Packed);930 assert(s.layout != .Packed);
689 const field_index = std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?;931 const field_index = std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?;
690 ip.extra.items[s.extra_index + field_index] = @intFromEnum(new_zir_index);932 ip.extra.items[s.extra_index + field_index] = @intFromEnum(new_zir_index);
...@@ -800,7 +1042,7 @@ pub const Key = union(enum) {...@@ -800,7 +1042,7 @@ pub const Key = union(enum) {
800 flags: Tag.TypeUnion.Flags,1042 flags: Tag.TypeUnion.Flags,
801 /// The enum that provides the list of field names and values.1043 /// The enum that provides the list of field names and values.
802 enum_tag_ty: Index,1044 enum_tag_ty: Index,
803 zir_index: TrackedInst.Index,1045 zir_index: TrackedInst.Index.Optional,
8041046
805 /// The returned pointer expires with any addition to the `InternPool`.1047 /// The returned pointer expires with any addition to the `InternPool`.
806 pub fn flagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeUnion.Flags {1048 pub fn flagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeUnion.Flags {
...@@ -889,6 +1131,7 @@ pub const Key = union(enum) {...@@ -889,6 +1131,7 @@ pub const Key = union(enum) {
889 /// This is ignored by `get` but will be provided by `indexToKey` when1131 /// This is ignored by `get` but will be provided by `indexToKey` when
890 /// a value map exists.1132 /// a value map exists.
891 values_map: OptionalMapIndex = .none,1133 values_map: OptionalMapIndex = .none,
1134 zir_index: TrackedInst.Index.Optional,
8921135
893 pub const TagMode = enum {1136 pub const TagMode = enum {
894 /// The integer tag type was auto-numbered by zig.1137 /// The integer tag type was auto-numbered by zig.
...@@ -953,6 +1196,7 @@ pub const Key = union(enum) {...@@ -953,6 +1196,7 @@ pub const Key = union(enum) {
953 tag_mode: EnumType.TagMode,1196 tag_mode: EnumType.TagMode,
954 /// This may be updated via `setTagType` later.1197 /// This may be updated via `setTagType` later.
955 tag_ty: Index = .none,1198 tag_ty: Index = .none,
1199 zir_index: TrackedInst.Index.Optional,
9561200
957 pub fn toEnumType(self: @This()) EnumType {1201 pub fn toEnumType(self: @This()) EnumType {
958 return .{1202 return .{
...@@ -962,6 +1206,7 @@ pub const Key = union(enum) {...@@ -962,6 +1206,7 @@ pub const Key = union(enum) {
962 .tag_mode = self.tag_mode,1206 .tag_mode = self.tag_mode,
963 .names = .{ .start = 0, .len = 0 },1207 .names = .{ .start = 0, .len = 0 },
964 .values = .{ .start = 0, .len = 0 },1208 .values = .{ .start = 0, .len = 0 },
1209 .zir_index = self.zir_index,
965 };1210 };
966 }1211 }
9671212
...@@ -1909,7 +2154,7 @@ pub const UnionType = struct {...@@ -1909,7 +2154,7 @@ pub const UnionType = struct {
1909 /// If this slice has length 0 it means all elements are `none`.2154 /// If this slice has length 0 it means all elements are `none`.
1910 field_aligns: Alignment.Slice,2155 field_aligns: Alignment.Slice,
1911 /// Index of the union_decl ZIR instruction.2156 /// Index of the union_decl ZIR instruction.
1912 zir_index: TrackedInst.Index,2157 zir_index: TrackedInst.Index.Optional,
1913 /// Index into extra array of the `flags` field.2158 /// Index into extra array of the `flags` field.
1914 flags_index: u32,2159 flags_index: u32,
1915 /// Copied from `enum_tag_ty`.2160 /// Copied from `enum_tag_ty`.
...@@ -2003,10 +2248,10 @@ pub const UnionType = struct {...@@ -2003,10 +2248,10 @@ pub const UnionType = struct {
2003 }2248 }
20042249
2005 /// This does not mutate the field of UnionType.2250 /// This does not mutate the field of UnionType.
2006 pub fn setZirIndex(self: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index) void {2251 pub fn setZirIndex(self: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void {
2007 const flags_field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;2252 const flags_field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;
2008 const zir_index_field_index = std.meta.fieldIndex(Tag.TypeUnion, "zir_index").?;2253 const zir_index_field_index = std.meta.fieldIndex(Tag.TypeUnion, "zir_index").?;
2009 const ptr: *TrackedInst.Index =2254 const ptr: *TrackedInst.Index.Optional =
2010 @ptrCast(&ip.extra.items[self.flags_index - flags_field_index + zir_index_field_index]);2255 @ptrCast(&ip.extra.items[self.flags_index - flags_field_index + zir_index_field_index]);
2011 ptr.* = new_zir_index;2256 ptr.* = new_zir_index;
2012 }2257 }
...@@ -3099,7 +3344,7 @@ pub const Tag = enum(u8) {...@@ -3099,7 +3344,7 @@ pub const Tag = enum(u8) {
3099 namespace: NamespaceIndex,3344 namespace: NamespaceIndex,
3100 /// The enum that provides the list of field names and values.3345 /// The enum that provides the list of field names and values.
3101 tag_ty: Index,3346 tag_ty: Index,
3102 zir_index: TrackedInst.Index,3347 zir_index: TrackedInst.Index.Optional,
31033348
3104 pub const Flags = packed struct(u32) {3349 pub const Flags = packed struct(u32) {
3105 runtime_tag: UnionType.RuntimeTag,3350 runtime_tag: UnionType.RuntimeTag,
...@@ -3121,7 +3366,7 @@ pub const Tag = enum(u8) {...@@ -3121,7 +3366,7 @@ pub const Tag = enum(u8) {
3121 /// 2. init: Index for each fields_len // if tag is type_struct_packed_inits3366 /// 2. init: Index for each fields_len // if tag is type_struct_packed_inits
3122 pub const TypeStructPacked = struct {3367 pub const TypeStructPacked = struct {
3123 decl: DeclIndex,3368 decl: DeclIndex,
3124 zir_index: TrackedInst.Index,3369 zir_index: TrackedInst.Index.Optional,
3125 fields_len: u32,3370 fields_len: u32,
3126 namespace: OptionalNamespaceIndex,3371 namespace: OptionalNamespaceIndex,
3127 backing_int_ty: Index,3372 backing_int_ty: Index,
...@@ -3168,7 +3413,7 @@ pub const Tag = enum(u8) {...@@ -3168,7 +3413,7 @@ pub const Tag = enum(u8) {
3168 /// 7. field_offset: u32 // for each field in declared order, undef until layout_resolved3413 /// 7. field_offset: u32 // for each field in declared order, undef until layout_resolved
3169 pub const TypeStruct = struct {3414 pub const TypeStruct = struct {
3170 decl: DeclIndex,3415 decl: DeclIndex,
3171 zir_index: TrackedInst.Index,3416 zir_index: TrackedInst.Index.Optional,
3172 fields_len: u32,3417 fields_len: u32,
3173 flags: Flags,3418 flags: Flags,
3174 size: u32,3419 size: u32,
...@@ -3238,6 +3483,11 @@ pub const FuncAnalysis = packed struct(u32) {...@@ -3238,6 +3483,11 @@ pub const FuncAnalysis = packed struct(u32) {
3238 /// This function might be OK but it depends on another Decl which did not3483 /// This function might be OK but it depends on another Decl which did not
3239 /// successfully complete semantic analysis.3484 /// successfully complete semantic analysis.
3240 dependency_failure,3485 dependency_failure,
3486 /// There will be a corresponding ErrorMsg in Module.failed_decls.
3487 /// Indicates that semantic analysis succeeded, but code generation for
3488 /// this function failed.
3489 codegen_failure,
3490 /// Semantic analysis and code generation of this function succeeded.
3241 success,3491 success,
3242 };3492 };
3243};3493};
...@@ -3523,6 +3773,7 @@ pub const EnumExplicit = struct {...@@ -3523,6 +3773,7 @@ pub const EnumExplicit = struct {
3523 /// If this is `none`, it means the trailing tag values are absent because3773 /// If this is `none`, it means the trailing tag values are absent because
3524 /// they are auto-numbered.3774 /// they are auto-numbered.
3525 values_map: OptionalMapIndex,3775 values_map: OptionalMapIndex,
3776 zir_index: TrackedInst.Index.Optional,
3526};3777};
35273778
3528/// Trailing:3779/// Trailing:
...@@ -3538,6 +3789,7 @@ pub const EnumAuto = struct {...@@ -3538,6 +3789,7 @@ pub const EnumAuto = struct {
3538 fields_len: u32,3789 fields_len: u32,
3539 /// Maps field names to declaration index.3790 /// Maps field names to declaration index.
3540 names_map: MapIndex,3791 names_map: MapIndex,
3792 zir_index: TrackedInst.Index.Optional,
3541};3793};
35423794
3543pub const PackedU64 = packed struct(u64) {3795pub const PackedU64 = packed struct(u64) {
...@@ -3759,6 +4011,16 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {...@@ -3759,6 +4011,16 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
37594011
3760 ip.tracked_insts.deinit(gpa);4012 ip.tracked_insts.deinit(gpa);
37614013
4014 ip.src_hash_deps.deinit(gpa);
4015 ip.decl_val_deps.deinit(gpa);
4016 ip.namespace_deps.deinit(gpa);
4017 ip.namespace_name_deps.deinit(gpa);
4018
4019 ip.first_dependency.deinit(gpa);
4020
4021 ip.dep_entries.deinit(gpa);
4022 ip.free_dep_entries.deinit(gpa);
4023
3762 ip.* = undefined;4024 ip.* = undefined;
3763}4025}
37644026
...@@ -3885,6 +4147,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -3885,6 +4147,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
3885 .tag_mode = .auto,4147 .tag_mode = .auto,
3886 .names_map = enum_auto.data.names_map.toOptional(),4148 .names_map = enum_auto.data.names_map.toOptional(),
3887 .values_map = .none,4149 .values_map = .none,
4150 .zir_index = enum_auto.data.zir_index,
3888 } };4151 } };
3889 },4152 },
3890 .type_enum_explicit => ip.indexToKeyEnum(data, .explicit),4153 .type_enum_explicit => ip.indexToKeyEnum(data, .explicit),
...@@ -4493,6 +4756,7 @@ fn indexToKeyEnum(ip: *const InternPool, data: u32, tag_mode: Key.EnumType.TagMo...@@ -4493,6 +4756,7 @@ fn indexToKeyEnum(ip: *const InternPool, data: u32, tag_mode: Key.EnumType.TagMo
4493 .tag_mode = tag_mode,4756 .tag_mode = tag_mode,
4494 .names_map = enum_explicit.data.names_map.toOptional(),4757 .names_map = enum_explicit.data.names_map.toOptional(),
4495 .values_map = enum_explicit.data.values_map,4758 .values_map = enum_explicit.data.values_map,
4759 .zir_index = enum_explicit.data.zir_index,
4496 } };4760 } };
4497}4761}
44984762
...@@ -5329,7 +5593,7 @@ pub const UnionTypeInit = struct {...@@ -5329,7 +5593,7 @@ pub const UnionTypeInit = struct {
5329 flags: Tag.TypeUnion.Flags,5593 flags: Tag.TypeUnion.Flags,
5330 decl: DeclIndex,5594 decl: DeclIndex,
5331 namespace: NamespaceIndex,5595 namespace: NamespaceIndex,
5332 zir_index: TrackedInst.Index,5596 zir_index: TrackedInst.Index.Optional,
5333 fields_len: u32,5597 fields_len: u32,
5334 enum_tag_ty: Index,5598 enum_tag_ty: Index,
5335 /// May have length 0 which leaves the values unset until later.5599 /// May have length 0 which leaves the values unset until later.
...@@ -5401,7 +5665,7 @@ pub const StructTypeInit = struct {...@@ -5401,7 +5665,7 @@ pub const StructTypeInit = struct {
5401 decl: DeclIndex,5665 decl: DeclIndex,
5402 namespace: OptionalNamespaceIndex,5666 namespace: OptionalNamespaceIndex,
5403 layout: std.builtin.Type.ContainerLayout,5667 layout: std.builtin.Type.ContainerLayout,
5404 zir_index: TrackedInst.Index,5668 zir_index: TrackedInst.Index.Optional,
5405 fields_len: u32,5669 fields_len: u32,
5406 known_non_opv: bool,5670 known_non_opv: bool,
5407 requires_comptime: RequiresComptime,5671 requires_comptime: RequiresComptime,
...@@ -5923,7 +6187,6 @@ pub const GetFuncInstanceKey = struct {...@@ -5923,7 +6187,6 @@ pub const GetFuncInstanceKey = struct {
5923 is_noinline: bool,6187 is_noinline: bool,
5924 generic_owner: Index,6188 generic_owner: Index,
5925 inferred_error_set: bool,6189 inferred_error_set: bool,
5926 generation: u32,
5927};6190};
59286191
5929pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey) Allocator.Error!Index {6192pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey) Allocator.Error!Index {
...@@ -5990,7 +6253,6 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)...@@ -5990,7 +6253,6 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)
5990 generic_owner,6253 generic_owner,
5991 func_index,6254 func_index,
5992 func_extra_index,6255 func_extra_index,
5993 arg.generation,
5994 func_ty,6256 func_ty,
5995 arg.section,6257 arg.section,
5996 );6258 );
...@@ -6122,7 +6384,6 @@ pub fn getFuncInstanceIes(...@@ -6122,7 +6384,6 @@ pub fn getFuncInstanceIes(
6122 generic_owner,6384 generic_owner,
6123 func_index,6385 func_index,
6124 func_extra_index,6386 func_extra_index,
6125 arg.generation,
6126 func_ty,6387 func_ty,
6127 arg.section,6388 arg.section,
6128 );6389 );
...@@ -6134,7 +6395,6 @@ fn finishFuncInstance(...@@ -6134,7 +6395,6 @@ fn finishFuncInstance(
6134 generic_owner: Index,6395 generic_owner: Index,
6135 func_index: Index,6396 func_index: Index,
6136 func_extra_index: u32,6397 func_extra_index: u32,
6137 generation: u32,
6138 func_ty: Index,6398 func_ty: Index,
6139 section: OptionalNullTerminatedString,6399 section: OptionalNullTerminatedString,
6140) Allocator.Error!Index {6400) Allocator.Error!Index {
...@@ -6154,7 +6414,6 @@ fn finishFuncInstance(...@@ -6154,7 +6414,6 @@ fn finishFuncInstance(
6154 .analysis = .complete,6414 .analysis = .complete,
6155 .zir_decl_index = fn_owner_decl.zir_decl_index,6415 .zir_decl_index = fn_owner_decl.zir_decl_index,
6156 .src_scope = fn_owner_decl.src_scope,6416 .src_scope = fn_owner_decl.src_scope,
6157 .generation = generation,
6158 .is_pub = fn_owner_decl.is_pub,6417 .is_pub = fn_owner_decl.is_pub,
6159 .is_exported = fn_owner_decl.is_exported,6418 .is_exported = fn_owner_decl.is_exported,
6160 .alive = true,6419 .alive = true,
...@@ -6264,6 +6523,7 @@ fn getIncompleteEnumAuto(...@@ -6264,6 +6523,7 @@ fn getIncompleteEnumAuto(
6264 .int_tag_type = int_tag_type,6523 .int_tag_type = int_tag_type,
6265 .names_map = names_map,6524 .names_map = names_map,
6266 .fields_len = enum_type.fields_len,6525 .fields_len = enum_type.fields_len,
6526 .zir_index = enum_type.zir_index,
6267 });6527 });
62686528
6269 ip.items.appendAssumeCapacity(.{6529 ip.items.appendAssumeCapacity(.{
...@@ -6314,6 +6574,7 @@ fn getIncompleteEnumExplicit(...@@ -6314,6 +6574,7 @@ fn getIncompleteEnumExplicit(
6314 .fields_len = enum_type.fields_len,6574 .fields_len = enum_type.fields_len,
6315 .names_map = names_map,6575 .names_map = names_map,
6316 .values_map = values_map,6576 .values_map = values_map,
6577 .zir_index = enum_type.zir_index,
6317 });6578 });
63186579
6319 ip.items.appendAssumeCapacity(.{6580 ip.items.appendAssumeCapacity(.{
...@@ -6339,6 +6600,7 @@ pub const GetEnumInit = struct {...@@ -6339,6 +6600,7 @@ pub const GetEnumInit = struct {
6339 names: []const NullTerminatedString,6600 names: []const NullTerminatedString,
6340 values: []const Index,6601 values: []const Index,
6341 tag_mode: Key.EnumType.TagMode,6602 tag_mode: Key.EnumType.TagMode,
6603 zir_index: TrackedInst.Index.Optional,
6342};6604};
63436605
6344pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Error!Index {6606pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Error!Index {
...@@ -6355,6 +6617,7 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro...@@ -6355,6 +6617,7 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro
6355 .tag_mode = undefined,6617 .tag_mode = undefined,
6356 .names_map = undefined,6618 .names_map = undefined,
6357 .values_map = undefined,6619 .values_map = undefined,
6620 .zir_index = undefined,
6358 },6621 },
6359 }, adapter);6622 }, adapter);
6360 if (gop.found_existing) return @enumFromInt(gop.index);6623 if (gop.found_existing) return @enumFromInt(gop.index);
...@@ -6380,6 +6643,7 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro...@@ -6380,6 +6643,7 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro
6380 .int_tag_type = ini.tag_ty,6643 .int_tag_type = ini.tag_ty,
6381 .names_map = names_map,6644 .names_map = names_map,
6382 .fields_len = fields_len,6645 .fields_len = fields_len,
6646 .zir_index = ini.zir_index,
6383 }),6647 }),
6384 });6648 });
6385 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));6649 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));
...@@ -6416,6 +6680,7 @@ pub fn finishGetEnum(...@@ -6416,6 +6680,7 @@ pub fn finishGetEnum(
6416 .fields_len = fields_len,6680 .fields_len = fields_len,
6417 .names_map = names_map,6681 .names_map = names_map,
6418 .values_map = values_map,6682 .values_map = values_map,
6683 .zir_index = ini.zir_index,
6419 }),6684 }),
6420 });6685 });
6421 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));6686 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));
...@@ -6507,6 +6772,7 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {...@@ -6507,6 +6772,7 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
6507 OptionalNullTerminatedString,6772 OptionalNullTerminatedString,
6508 Tag.TypePointer.VectorIndex,6773 Tag.TypePointer.VectorIndex,
6509 TrackedInst.Index,6774 TrackedInst.Index,
6775 TrackedInst.Index.Optional,
6510 => @intFromEnum(@field(extra, field.name)),6776 => @intFromEnum(@field(extra, field.name)),
65116777
6512 u32,6778 u32,
...@@ -6583,6 +6849,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct...@@ -6583,6 +6849,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct
6583 OptionalNullTerminatedString,6849 OptionalNullTerminatedString,
6584 Tag.TypePointer.VectorIndex,6850 Tag.TypePointer.VectorIndex,
6585 TrackedInst.Index,6851 TrackedInst.Index,
6852 TrackedInst.Index.Optional,
6586 => @enumFromInt(int32),6853 => @enumFromInt(int32),
65876854
6588 u32,6855 u32,
src/Module.zig+606-222
...@@ -144,10 +144,26 @@ global_error_set: GlobalErrorSet = .{},...@@ -144,10 +144,26 @@ global_error_set: GlobalErrorSet = .{},
144/// Maximum amount of distinct error values, set by --error-limit144/// Maximum amount of distinct error values, set by --error-limit
145error_limit: ErrorInt,145error_limit: ErrorInt,
146146
147/// Incrementing integer used to compare against the corresponding Decl147/// Value is the number of PO or outdated Decls which this Depender depends on.
148/// field to determine whether a Decl's status applies to an ongoing update, or a148potentially_outdated: std.AutoArrayHashMapUnmanaged(InternPool.Depender, u32) = .{},
149/// previous analysis.149/// Value is the number of PO or outdated Decls which this Depender depends on.
150generation: u32 = 0,150/// Once this value drops to 0, the Depender is a candidate for re-analysis.
151outdated: std.AutoArrayHashMapUnmanaged(InternPool.Depender, u32) = .{},
152/// This contains all `Depender`s in `outdated` whose PO dependency count is 0.
153/// Such `Depender`s are ready for immediate re-analysis.
154/// See `findOutdatedToAnalyze` for details.
155outdated_ready: std.AutoArrayHashMapUnmanaged(InternPool.Depender, void) = .{},
156/// This contains a set of Decls which may not be in `outdated`, but are the
157/// root Decls of files which have updated source and thus must be re-analyzed.
158/// If such a Decl is only in this set, the struct type index may be preserved
159/// (only the namespace might change). If such a Decl is also `outdated`, the
160/// struct type index must be recreated.
161outdated_file_root: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
162/// This contains a list of Dependers whose analysis or codegen failed, but the
163/// failure was something like running out of disk space, and trying again may
164/// succeed. On the next update, we will flush this list, marking all members of
165/// it as outdated.
166retryable_failures: std.ArrayListUnmanaged(InternPool.Depender) = .{},
151167
152stage1_flags: packed struct {168stage1_flags: packed struct {
153 have_winmain: bool = false,169 have_winmain: bool = false,
...@@ -364,21 +380,14 @@ pub const Decl = struct {...@@ -364,21 +380,14 @@ pub const Decl = struct {
364 alignment: Alignment,380 alignment: Alignment,
365 /// Populated when `has_tv`.381 /// Populated when `has_tv`.
366 @"addrspace": std.builtin.AddressSpace,382 @"addrspace": std.builtin.AddressSpace,
367 /// The direct parent namespace of the Decl.383 /// The direct parent namespace of the Decl. In the case of the Decl
368 /// Reference to externally owned memory.384 /// corresponding to a file, this is the namespace of the struct, since
369 /// In the case of the Decl corresponding to a file, this is385 /// there is no parent.
370 /// the namespace of the struct, since there is no parent.
371 src_namespace: Namespace.Index,386 src_namespace: Namespace.Index,
372387
373 /// The scope which lexically contains this decl. A decl must depend388 /// The scope which lexically contains this decl.
374 /// on its lexical parent, in order to ensure that this pointer is valid.
375 /// This scope is allocated out of the arena of the parent decl.
376 src_scope: CaptureScope.Index,389 src_scope: CaptureScope.Index,
377390
378 /// An integer that can be checked against the corresponding incrementing
379 /// generation field of Module. This is used to determine whether `complete` status
380 /// represents pre- or post- re-analysis.
381 generation: u32,
382 /// The AST node index of this declaration.391 /// The AST node index of this declaration.
383 /// Must be recomputed when the corresponding source file is modified.392 /// Must be recomputed when the corresponding source file is modified.
384 src_node: Ast.Node.Index,393 src_node: Ast.Node.Index,
...@@ -404,31 +413,20 @@ pub const Decl = struct {...@@ -404,31 +413,20 @@ pub const Decl = struct {
404 /// The file corresponding to this Decl had a parse error or ZIR error.413 /// The file corresponding to this Decl had a parse error or ZIR error.
405 /// There will be a corresponding ErrorMsg in Module.failed_files.414 /// There will be a corresponding ErrorMsg in Module.failed_files.
406 file_failure,415 file_failure,
407 /// This Decl might be OK but it depends on another one which did not successfully complete416 /// This Decl might be OK but it depends on another one which did not
408 /// semantic analysis.417 /// successfully complete semantic analysis.
409 dependency_failure,418 dependency_failure,
410 /// Semantic analysis failure.419 /// Semantic analysis failure.
411 /// There will be a corresponding ErrorMsg in Module.failed_decls.420 /// There will be a corresponding ErrorMsg in Module.failed_decls.
412 sema_failure,421 sema_failure,
413 /// There will be a corresponding ErrorMsg in Module.failed_decls.422 /// There will be a corresponding ErrorMsg in Module.failed_decls.
414 /// This indicates the failure was something like running out of disk space,
415 /// and attempting semantic analysis again may succeed.
416 sema_failure_retryable,
417 /// There will be a corresponding ErrorMsg in Module.failed_decls.
418 liveness_failure,
419 /// There will be a corresponding ErrorMsg in Module.failed_decls.
420 codegen_failure,423 codegen_failure,
421 /// There will be a corresponding ErrorMsg in Module.failed_decls.424 /// Sematic analysis and constant value codegen of this Decl has
422 /// This indicates the failure was something like running out of disk space,425 /// succeeded. However, the Decl may be outdated due to an in-progress
423 /// and attempting codegen again may succeed.426 /// update. Note that for a function, this does not mean codegen of the
424 codegen_failure_retryable,427 /// function body succeded: that state is indicated by the function's
425 /// Everything is done. During an update, this Decl may be out of date, depending428 /// `analysis` field.
426 /// on its dependencies. The `generation` field can be used to determine if this
427 /// completion status occurred before or after a given update.
428 complete,429 complete,
429 /// A Module update is in progress, and this Decl has been flagged as being known
430 /// to require re-analysis.
431 outdated,
432 },430 },
433 /// Whether `typed_value`, `align`, `linksection` and `addrspace` are populated.431 /// Whether `typed_value`, `align`, `linksection` and `addrspace` are populated.
434 has_tv: bool,432 has_tv: bool,
...@@ -680,14 +678,6 @@ pub const Decl = struct {...@@ -680,14 +678,6 @@ pub const Decl = struct {
680 return mod.namespacePtr(decl.src_namespace).file_scope;678 return mod.namespacePtr(decl.src_namespace).file_scope;
681 }679 }
682680
683 pub fn removeDependant(decl: *Decl, other: Decl.Index) void {
684 assert(decl.dependants.swapRemove(other));
685 }
686
687 pub fn removeDependency(decl: *Decl, other: Decl.Index) void {
688 assert(decl.dependencies.swapRemove(other));
689 }
690
691 pub fn getExternDecl(decl: Decl, mod: *Module) OptionalIndex {681 pub fn getExternDecl(decl: Decl, mod: *Module) OptionalIndex {
692 assert(decl.has_tv);682 assert(decl.has_tv);
693 return switch (mod.intern_pool.indexToKey(decl.val.toIntern())) {683 return switch (mod.intern_pool.indexToKey(decl.val.toIntern())) {
...@@ -734,8 +724,7 @@ pub const Namespace = struct {...@@ -734,8 +724,7 @@ pub const Namespace = struct {
734 file_scope: *File,724 file_scope: *File,
735 /// Will be a struct, enum, union, or opaque.725 /// Will be a struct, enum, union, or opaque.
736 ty: Type,726 ty: Type,
737 /// Direct children of the namespace. Used during an update to detect727 /// Direct children of the namespace.
738 /// which decls have been added/removed from source.
739 /// Declaration order is preserved via entry order.728 /// Declaration order is preserved via entry order.
740 /// These are only declarations named directly by the AST; anonymous729 /// These are only declarations named directly by the AST; anonymous
741 /// declarations are not stored here.730 /// declarations are not stored here.
...@@ -838,14 +827,6 @@ pub const File = struct {...@@ -838,14 +827,6 @@ pub const File = struct {
838 /// undefined until `zir_loaded == true`.827 /// undefined until `zir_loaded == true`.
839 path_digest: Cache.BinDigest = undefined,828 path_digest: Cache.BinDigest = undefined,
840829
841 /// Used by change detection algorithm, after astgen, contains the
842 /// set of decls that existed in the previous ZIR but not in the new one.
843 deleted_decls: ArrayListUnmanaged(Decl.Index) = .{},
844 /// Used by change detection algorithm, after astgen, contains the
845 /// set of decls that existed both in the previous ZIR and in the new one,
846 /// but their source code has been modified.
847 outdated_decls: ArrayListUnmanaged(Decl.Index) = .{},
848
849 /// The most recent successful ZIR for this file, with no errors.830 /// The most recent successful ZIR for this file, with no errors.
850 /// This is only populated when a previously successful ZIR831 /// This is only populated when a previously successful ZIR
851 /// newly introduces compile errors during an update. When ZIR is832 /// newly introduces compile errors during an update. When ZIR is
...@@ -898,8 +879,6 @@ pub const File = struct {...@@ -898,8 +879,6 @@ pub const File = struct {
898 gpa.free(file.sub_file_path);879 gpa.free(file.sub_file_path);
899 file.unload(gpa);880 file.unload(gpa);
900 }881 }
901 file.deleted_decls.deinit(gpa);
902 file.outdated_decls.deinit(gpa);
903 file.references.deinit(gpa);882 file.references.deinit(gpa);
904 if (file.root_decl.unwrap()) |root_decl| {883 if (file.root_decl.unwrap()) |root_decl| {
905 mod.destroyDecl(root_decl);884 mod.destroyDecl(root_decl);
...@@ -2498,6 +2477,12 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2498,6 +2477,12 @@ pub fn deinit(zcu: *Zcu) void {
24982477
2499 zcu.global_error_set.deinit(gpa);2478 zcu.global_error_set.deinit(gpa);
25002479
2480 zcu.potentially_outdated.deinit(gpa);
2481 zcu.outdated.deinit(gpa);
2482 zcu.outdated_ready.deinit(gpa);
2483 zcu.outdated_file_root.deinit(gpa);
2484 zcu.retryable_failures.deinit(gpa);
2485
2501 zcu.test_functions.deinit(gpa);2486 zcu.test_functions.deinit(gpa);
25022487
2503 for (zcu.global_assembly.values()) |s| {2488 for (zcu.global_assembly.values()) |s| {
...@@ -2856,27 +2841,20 @@ pub fn astGenFile(mod: *Module, file: *File) !void {...@@ -2856,27 +2841,20 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
2856 }2841 }
28572842
2858 if (file.prev_zir) |prev_zir| {2843 if (file.prev_zir) |prev_zir| {
2859 // Iterate over all Namespace objects contained within this File, looking at the
2860 // previous and new ZIR together and update the references to point
2861 // to the new one. For example, Decl name, Decl zir_decl_index, and Namespace
2862 // decl_table keys need to get updated to point to the new memory, even if the
2863 // underlying source code is unchanged.
2864 // We do not need to hold any locks at this time because all the Decl and Namespace
2865 // objects being touched are specific to this File, and the only other concurrent
2866 // tasks are touching other File objects.
2867 try updateZirRefs(mod, file, prev_zir.*);2844 try updateZirRefs(mod, file, prev_zir.*);
2868 // At this point, `file.outdated_decls` and `file.deleted_decls` are populated,
2869 // and semantic analysis will deal with them properly.
2870 // No need to keep previous ZIR.2845 // No need to keep previous ZIR.
2871 prev_zir.deinit(gpa);2846 prev_zir.deinit(gpa);
2872 gpa.destroy(prev_zir);2847 gpa.destroy(prev_zir);
2873 file.prev_zir = null;2848 file.prev_zir = null;
2874 } else if (file.root_decl.unwrap()) |root_decl| {2849 }
2875 // This is an update, but it is the first time the File has succeeded2850
2876 // ZIR. We must mark it outdated since we have already tried to2851 if (file.root_decl.unwrap()) |root_decl| {
2877 // semantically analyze it.2852 // The root of this file must be re-analyzed, since the file has changed.
2878 try file.outdated_decls.resize(gpa, 1);2853 comp.mutex.lock();
2879 file.outdated_decls.items[0] = root_decl;2854 defer comp.mutex.unlock();
2855
2856 log.debug("outdated root Decl: {}", .{root_decl});
2857 try mod.outdated_file_root.put(gpa, root_decl, {});
2880 }2858 }
2881}2859}
28822860
...@@ -2950,25 +2928,347 @@ fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.File)...@@ -2950,25 +2928,347 @@ fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.File)
2950 return zir;2928 return zir;
2951}2929}
29522930
2931/// This is called from the AstGen thread pool, so must acquire
2932/// the Compilation mutex when acting on shared state.
2953fn updateZirRefs(zcu: *Module, file: *File, old_zir: Zir) !void {2933fn updateZirRefs(zcu: *Module, file: *File, old_zir: Zir) !void {
2954 const gpa = zcu.gpa;2934 const gpa = zcu.gpa;
2935 const new_zir = file.zir;
29552936
2956 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};2937 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};
2957 defer inst_map.deinit(gpa);2938 defer inst_map.deinit(gpa);
29582939
2959 try mapOldZirToNew(gpa, old_zir, file.zir, &inst_map);2940 try mapOldZirToNew(gpa, old_zir, new_zir, &inst_map);
2941
2942 const old_tag = old_zir.instructions.items(.tag);
2943 const old_data = old_zir.instructions.items(.data);
29602944
2961 // TODO: this should be done after all AstGen workers complete, to avoid2945 // TODO: this should be done after all AstGen workers complete, to avoid
2962 // iterating over this full set for every updated file.2946 // iterating over this full set for every updated file.
2963 for (zcu.intern_pool.tracked_insts.keys()) |*ti| {2947 for (zcu.intern_pool.tracked_insts.keys(), 0..) |*ti, idx_raw| {
2948 const ti_idx: InternPool.TrackedInst.Index = @enumFromInt(idx_raw);
2964 if (!std.mem.eql(u8, &ti.path_digest, &file.path_digest)) continue;2949 if (!std.mem.eql(u8, &ti.path_digest, &file.path_digest)) continue;
2950 const old_inst = ti.inst;
2965 ti.inst = inst_map.get(ti.inst) orelse {2951 ti.inst = inst_map.get(ti.inst) orelse {
2966 // TODO: invalidate this `TrackedInst` via the dependency mechanism2952 // Tracking failed for this instruction. Invalidate associated `src_hash` deps.
2953 zcu.comp.mutex.lock();
2954 defer zcu.comp.mutex.unlock();
2955 log.debug("tracking failed for %{d}", .{old_inst});
2956 try zcu.markDependeeOutdated(.{ .src_hash = ti_idx });
2967 continue;2957 continue;
2968 };2958 };
2959
2960 if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: {
2961 if (new_zir.getAssociatedSrcHash(ti.inst)) |new_hash| {
2962 if (std.zig.srcHashEql(old_hash, new_hash)) {
2963 break :hash_changed;
2964 }
2965 log.debug("hash for (%{d} -> %{d}) changed: {} -> {}", .{
2966 old_inst,
2967 ti.inst,
2968 std.fmt.fmtSliceHexLower(&old_hash),
2969 std.fmt.fmtSliceHexLower(&new_hash),
2970 });
2971 }
2972 // The source hash associated with this instruction changed - invalidate relevant dependencies.
2973 zcu.comp.mutex.lock();
2974 defer zcu.comp.mutex.unlock();
2975 try zcu.markDependeeOutdated(.{ .src_hash = ti_idx });
2976 }
2977
2978 // If this is a `struct_decl` etc, we must invalidate any outdated namespace dependencies.
2979 const has_namespace = switch (old_tag[@intFromEnum(old_inst)]) {
2980 .extended => switch (old_data[@intFromEnum(old_inst)].extended.opcode) {
2981 .struct_decl, .union_decl, .opaque_decl, .enum_decl => true,
2982 else => false,
2983 },
2984 else => false,
2985 };
2986 if (!has_namespace) continue;
2987
2988 var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
2989 defer old_names.deinit(zcu.gpa);
2990 {
2991 var it = old_zir.declIterator(old_inst);
2992 while (it.next()) |decl_inst| {
2993 const decl_name = old_zir.getDeclaration(decl_inst)[0].name;
2994 switch (decl_name) {
2995 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
2996 _ => if (decl_name.isNamedTest(old_zir)) continue,
2997 }
2998 const name_zir = decl_name.toString(old_zir).?;
2999 const name_ip = try zcu.intern_pool.getOrPutString(
3000 zcu.gpa,
3001 old_zir.nullTerminatedString(name_zir),
3002 );
3003 try old_names.put(zcu.gpa, name_ip, {});
3004 }
3005 }
3006 var any_change = false;
3007 {
3008 var it = new_zir.declIterator(ti.inst);
3009 while (it.next()) |decl_inst| {
3010 const decl_name = old_zir.getDeclaration(decl_inst)[0].name;
3011 switch (decl_name) {
3012 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
3013 _ => if (decl_name.isNamedTest(old_zir)) continue,
3014 }
3015 const name_zir = decl_name.toString(old_zir).?;
3016 const name_ip = try zcu.intern_pool.getOrPutString(
3017 zcu.gpa,
3018 old_zir.nullTerminatedString(name_zir),
3019 );
3020 if (!old_names.swapRemove(name_ip)) continue;
3021 // Name added
3022 any_change = true;
3023 zcu.comp.mutex.lock();
3024 defer zcu.comp.mutex.unlock();
3025 try zcu.markDependeeOutdated(.{ .namespace_name = .{
3026 .namespace = ti_idx,
3027 .name = name_ip,
3028 } });
3029 }
3030 }
3031 // The only elements remaining in `old_names` now are any names which were removed.
3032 for (old_names.keys()) |name_ip| {
3033 any_change = true;
3034 zcu.comp.mutex.lock();
3035 defer zcu.comp.mutex.unlock();
3036 try zcu.markDependeeOutdated(.{ .namespace_name = .{
3037 .namespace = ti_idx,
3038 .name = name_ip,
3039 } });
3040 }
3041
3042 if (any_change) {
3043 zcu.comp.mutex.lock();
3044 defer zcu.comp.mutex.unlock();
3045 try zcu.markDependeeOutdated(.{ .namespace = ti_idx });
3046 }
2969 }3047 }
2970}3048}
29713049
3050pub fn markDependeeOutdated(zcu: *Zcu, dependee: InternPool.Dependee) !void {
3051 log.debug("outdated dependee: {}", .{dependee});
3052 var it = zcu.intern_pool.dependencyIterator(dependee);
3053 while (it.next()) |depender| {
3054 if (zcu.outdated.contains(depender)) {
3055 // We do not need to increment the PO dep count, as if the outdated
3056 // dependee is a Decl, we had already marked this as PO.
3057 continue;
3058 }
3059 const opt_po_entry = zcu.potentially_outdated.fetchSwapRemove(depender);
3060 try zcu.outdated.putNoClobber(
3061 zcu.gpa,
3062 depender,
3063 // We do not need to increment this count for the same reason as above.
3064 if (opt_po_entry) |e| e.value else 0,
3065 );
3066 log.debug("outdated: {}", .{depender});
3067 if (opt_po_entry != null) {
3068 // This is a new entry with no PO dependencies.
3069 try zcu.outdated_ready.put(zcu.gpa, depender, {});
3070 }
3071 // If this is a Decl and was not previously PO, we must recursively
3072 // mark dependencies on its tyval as PO.
3073 if (opt_po_entry == null) switch (depender.unwrap()) {
3074 .decl => |decl_index| try zcu.markDeclDependenciesPotentiallyOutdated(decl_index),
3075 .func => {},
3076 };
3077 }
3078}
3079
3080fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
3081 var it = zcu.intern_pool.dependencyIterator(dependee);
3082 while (it.next()) |depender| {
3083 if (zcu.outdated.getPtr(depender)) |po_dep_count| {
3084 // This depender is already outdated, but it now has one
3085 // less PO dependency!
3086 po_dep_count.* -= 1;
3087 if (po_dep_count.* == 0) {
3088 try zcu.outdated_ready.put(zcu.gpa, depender, {});
3089 }
3090 continue;
3091 }
3092 // This depender is definitely at least PO, because this Decl was just analyzed
3093 // due to being outdated.
3094 const ptr = zcu.potentially_outdated.getPtr(depender).?;
3095 if (ptr.* > 1) {
3096 ptr.* -= 1;
3097 continue;
3098 }
3099
3100 // This dependency is no longer PO, i.e. is known to be up-to-date.
3101 assert(zcu.potentially_outdated.swapRemove(depender));
3102 // If this is a Decl, we must recursively mark dependencies on its tyval
3103 // as no longer PO.
3104 switch (depender.unwrap()) {
3105 .decl => |decl_index| try zcu.markPoDependeeUpToDate(.{ .decl_val = decl_index }),
3106 .func => {},
3107 }
3108 }
3109}
3110
3111/// Given a Decl which is newly outdated or PO, mark all dependers which depend
3112/// on its tyval as PO.
3113fn markDeclDependenciesPotentiallyOutdated(zcu: *Zcu, decl_index: Decl.Index) !void {
3114 var it = zcu.intern_pool.dependencyIterator(.{ .decl_val = decl_index });
3115 while (it.next()) |po| {
3116 if (zcu.outdated.getPtr(po)) |po_dep_count| {
3117 // This dependency is already outdated, but it now has one more PO
3118 // dependency.
3119 if (po_dep_count.* == 0) {
3120 _ = zcu.outdated_ready.swapRemove(po);
3121 }
3122 po_dep_count.* += 1;
3123 continue;
3124 }
3125 if (zcu.potentially_outdated.getPtr(po)) |n| {
3126 // There is now one more PO dependency.
3127 n.* += 1;
3128 continue;
3129 }
3130 try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1);
3131 // If this ia a Decl, we must recursively mark dependencies
3132 // on its tyval as PO.
3133 switch (po.unwrap()) {
3134 .decl => |po_decl| try zcu.markDeclDependenciesPotentiallyOutdated(po_decl),
3135 .func => {},
3136 }
3137 }
3138 // TODO: repeat the above for `decl_ty` dependencies when they are introduced
3139}
3140
3141pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.Depender {
3142 if (!zcu.comp.debug_incremental) return null;
3143
3144 if (zcu.outdated.count() == 0 and zcu.potentially_outdated.count() == 0) {
3145 log.debug("findOutdatedToAnalyze: no outdated depender", .{});
3146 return null;
3147 }
3148
3149 // Our goal is to find an outdated Depender which itself has no outdated or
3150 // PO dependencies. Most of the time, such a Depender will exist - we track
3151 // them in the `outdated_ready` set for efficiency. However, this is not
3152 // necessarily the case, since the Decl dependency graph may contain loops
3153 // via mutually recursive definitions:
3154 // pub const A = struct { b: *B };
3155 // pub const B = struct { b: *A };
3156 // In this case, we must defer to more complex logic below.
3157
3158 if (zcu.outdated_ready.count() > 0) {
3159 log.debug("findOutdatedToAnalyze: trivial '{s} {d}'", .{
3160 @tagName(zcu.outdated_ready.keys()[0].unwrap()),
3161 switch (zcu.outdated_ready.keys()[0].unwrap()) {
3162 inline else => |x| @intFromEnum(x),
3163 },
3164 });
3165 return zcu.outdated_ready.keys()[0];
3166 }
3167
3168 // Next, we will see if there is any outdated file root which was not in
3169 // `outdated`. This set will be small (number of files changed in this
3170 // update), so it's alright for us to just iterate here.
3171 for (zcu.outdated_file_root.keys()) |file_decl| {
3172 const decl_depender = InternPool.Depender.wrap(.{ .decl = file_decl });
3173 if (zcu.outdated.contains(decl_depender)) {
3174 // Since we didn't hit this in the first loop, this Decl must have
3175 // pending dependencies, so is ineligible.
3176 continue;
3177 }
3178 if (zcu.potentially_outdated.contains(decl_depender)) {
3179 // This Decl's struct may or may not need to be recreated depending
3180 // on whether it is outdated. If we analyzed it now, we would have
3181 // to assume it was outdated and recreate it!
3182 continue;
3183 }
3184 log.debug("findOutdatedToAnalyze: outdated file root decl '{d}'", .{file_decl});
3185 return decl_depender;
3186 }
3187
3188 // There is no single Depender which is ready for re-analysis. Instead, we
3189 // must assume that some Decl with PO dependencies is outdated - e.g. in the
3190 // above example we arbitrarily pick one of A or B. We should select a Decl,
3191 // since a Decl is definitely responsible for the loop in the dependency
3192 // graph (since you can't depend on a runtime function analysis!).
3193
3194 // The choice of this Decl could have a big impact on how much total
3195 // analysis we perform, since if analysis concludes its tyval is unchanged,
3196 // then other PO Dependers may be resolved as up-to-date. To hopefully avoid
3197 // doing too much work, let's find a Decl which the most things depend on -
3198 // the idea is that this will resolve a lot of loops (but this is only a
3199 // heuristic).
3200
3201 log.debug("findOutdatedToAnalyze: no trivial ready, using heuristic; {d} outdated, {d} PO", .{
3202 zcu.outdated.count(),
3203 zcu.potentially_outdated.count(),
3204 });
3205
3206 var chosen_decl_idx: ?Decl.Index = null;
3207 var chosen_decl_dependers: u32 = undefined;
3208
3209 for (zcu.outdated.keys()) |depender| {
3210 const decl_index = switch (depender.unwrap()) {
3211 .decl => |d| d,
3212 .func => continue,
3213 };
3214
3215 var n: u32 = 0;
3216 var it = zcu.intern_pool.dependencyIterator(.{ .decl_val = decl_index });
3217 while (it.next()) |_| n += 1;
3218
3219 if (chosen_decl_idx == null or n > chosen_decl_dependers) {
3220 chosen_decl_idx = decl_index;
3221 chosen_decl_dependers = n;
3222 }
3223 }
3224
3225 for (zcu.potentially_outdated.keys()) |depender| {
3226 const decl_index = switch (depender.unwrap()) {
3227 .decl => |d| d,
3228 .func => continue,
3229 };
3230
3231 var n: u32 = 0;
3232 var it = zcu.intern_pool.dependencyIterator(.{ .decl_val = decl_index });
3233 while (it.next()) |_| n += 1;
3234
3235 if (chosen_decl_idx == null or n > chosen_decl_dependers) {
3236 chosen_decl_idx = decl_index;
3237 chosen_decl_dependers = n;
3238 }
3239 }
3240
3241 log.debug("findOutdatedToAnalyze: heuristic returned Decl {d} ({d} dependers)", .{
3242 chosen_decl_idx.?,
3243 chosen_decl_dependers,
3244 });
3245
3246 return InternPool.Depender.wrap(.{ .decl = chosen_decl_idx.? });
3247}
3248
3249/// During an incremental update, before semantic analysis, call this to flush all values from
3250/// `retryable_failures` and mark them as outdated so they get re-analyzed.
3251pub fn flushRetryableFailures(zcu: *Zcu) !void {
3252 const gpa = zcu.gpa;
3253 for (zcu.retryable_failures.items) |depender| {
3254 if (zcu.outdated.contains(depender)) continue;
3255 if (zcu.potentially_outdated.fetchSwapRemove(depender)) |kv| {
3256 // This Depender was already PO, but we now consider it outdated.
3257 // Any transitive dependencies are already marked PO.
3258 try zcu.outdated.put(gpa, depender, kv.value);
3259 continue;
3260 }
3261 // This Depender was not marked PO, but is now outdated. Mark it as
3262 // such, then recursively mark transitive dependencies as PO.
3263 try zcu.outdated.put(gpa, depender, 0);
3264 switch (depender.unwrap()) {
3265 .decl => |decl| try zcu.markDeclDependenciesPotentiallyOutdated(decl),
3266 .func => {},
3267 }
3268 }
3269 zcu.retryable_failures.clearRetainingCapacity();
3270}
3271
2972pub fn mapOldZirToNew(3272pub fn mapOldZirToNew(
2973 gpa: Allocator,3273 gpa: Allocator,
2974 old_zir: Zir,3274 old_zir: Zir,
...@@ -3096,7 +3396,7 @@ pub fn mapOldZirToNew(...@@ -3096,7 +3396,7 @@ pub fn mapOldZirToNew(
3096 }3396 }
3097}3397}
30983398
3099/// This ensures that the Decl will have a Type and Value populated.3399/// This ensures that the Decl will have an up-to-date Type and Value populated.
3100/// However the resolution status of the Type may not be fully resolved.3400/// However the resolution status of the Type may not be fully resolved.
3101/// For example an inferred error set is not resolved until after `analyzeFnBody`.3401/// For example an inferred error set is not resolved until after `analyzeFnBody`.
3102/// is called.3402/// is called.
...@@ -3106,40 +3406,57 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {...@@ -3106,40 +3406,57 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
31063406
3107 const decl = mod.declPtr(decl_index);3407 const decl = mod.declPtr(decl_index);
31083408
3109 const subsequent_analysis = switch (decl.analysis) {3409 // Determine whether or not this Decl is outdated, i.e. requires re-analysis
3410 // even if `complete`. If a Decl is PO, we pessismistically assume that it
3411 // *does* require re-analysis, to ensure that the Decl is definitely
3412 // up-to-date when this function returns.
3413
3414 // If analysis occurs in a poor order, this could result in over-analysis.
3415 // We do our best to avoid this by the other dependency logic in this file
3416 // which tries to limit re-analysis to Decls whose previously listed
3417 // dependencies are all up-to-date.
3418
3419 const decl_as_depender = InternPool.Depender.wrap(.{ .decl = decl_index });
3420 const was_outdated = mod.outdated.swapRemove(decl_as_depender) or
3421 mod.potentially_outdated.swapRemove(decl_as_depender);
3422
3423 if (was_outdated) {
3424 _ = mod.outdated_ready.swapRemove(decl_as_depender);
3425 }
3426
3427 switch (decl.analysis) {
3110 .in_progress => unreachable,3428 .in_progress => unreachable,
31113429
3112 .file_failure,3430 .file_failure => return error.AnalysisFail,
3431
3113 .sema_failure,3432 .sema_failure,
3114 .sema_failure_retryable,
3115 .liveness_failure,
3116 .codegen_failure,
3117 .dependency_failure,3433 .dependency_failure,
3118 .codegen_failure_retryable,3434 .codegen_failure,
3119 => return error.AnalysisFail,3435 => if (!was_outdated) return error.AnalysisFail,
3120
3121 .complete => return,
31223436
3123 .outdated => blk: {3437 .complete => if (!was_outdated) return,
3124 if (build_options.only_c) unreachable;
3125 // The exports this Decl performs will be re-discovered, so we remove them here
3126 // prior to re-analysis.
3127 try mod.deleteDeclExports(decl_index);
31283438
3129 break :blk true;3439 .unreferenced => {},
3130 },3440 }
31313441
3132 .unreferenced => false,3442 if (was_outdated) {
3133 };3443 // The exports this Decl performs will be re-discovered, so we remove them here
3444 // prior to re-analysis.
3445 if (build_options.only_c) unreachable;
3446 try mod.deleteDeclExports(decl_index);
3447 }
31343448
3135 var decl_prog_node = mod.sema_prog_node.start("", 0);3449 var decl_prog_node = mod.sema_prog_node.start("", 0);
3136 decl_prog_node.activate();3450 decl_prog_node.activate();
3137 defer decl_prog_node.end();3451 defer decl_prog_node.end();
31383452
3139 const type_changed = blk: {3453 const sema_result: SemaDeclResult = blk: {
3140 if (decl.zir_decl_index == .none and !mod.declIsRoot(decl_index)) {3454 if (decl.zir_decl_index == .none and !mod.declIsRoot(decl_index)) {
3141 // Anonymous decl. We don't semantically analyze these.3455 // Anonymous decl. We don't semantically analyze these.
3142 break :blk false; // tv unchanged3456 break :blk .{
3457 .invalidate_decl_val = false,
3458 .invalidate_decl_ref = false,
3459 };
3143 }3460 }
31443461
3145 break :blk mod.semaDecl(decl_index) catch |err| switch (err) {3462 break :blk mod.semaDecl(decl_index) catch |err| switch (err) {
...@@ -3155,8 +3472,9 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {...@@ -3155,8 +3472,9 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
3155 error.NeededSourceLocation => unreachable,3472 error.NeededSourceLocation => unreachable,
3156 error.GenericPoison => unreachable,3473 error.GenericPoison => unreachable,
3157 else => |e| {3474 else => |e| {
3158 decl.analysis = .sema_failure_retryable;3475 decl.analysis = .sema_failure;
3159 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);3476 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);
3477 try mod.retryable_failures.append(mod.gpa, InternPool.Depender.wrap(.{ .decl = decl_index }));
3160 mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create(3478 mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create(
3161 mod.gpa,3479 mod.gpa,
3162 decl.srcLoc(mod),3480 decl.srcLoc(mod),
...@@ -3168,9 +3486,18 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {...@@ -3168,9 +3486,18 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
3168 };3486 };
3169 };3487 };
31703488
3171 if (subsequent_analysis) {3489 // TODO: we do not yet have separate dependencies for decl values vs types.
3172 _ = type_changed;3490 if (was_outdated) {
3173 @panic("TODO re-implement incremental compilation");3491 if (sema_result.invalidate_decl_val or sema_result.invalidate_decl_ref) {
3492 // This dependency was marked as PO, meaning dependees were waiting
3493 // on its analysis result, and it has turned out to be outdated.
3494 // Update dependees accordingly.
3495 try mod.markDependeeOutdated(.{ .decl_val = decl_index });
3496 } else {
3497 // This dependency was previously PO, but turned out to be up-to-date.
3498 // We do not need to queue successive analysis.
3499 try mod.markPoDependeeUpToDate(.{ .decl_val = decl_index });
3500 }
3174 }3501 }
3175}3502}
31763503
...@@ -3186,119 +3513,129 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError...@@ -3186,119 +3513,129 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError
3186 switch (decl.analysis) {3513 switch (decl.analysis) {
3187 .unreferenced => unreachable,3514 .unreferenced => unreachable,
3188 .in_progress => unreachable,3515 .in_progress => unreachable,
3189 .outdated => unreachable,3516
3517 .codegen_failure => unreachable, // functions do not perform constant value generation
31903518
3191 .file_failure,3519 .file_failure,
3192 .sema_failure,3520 .sema_failure,
3193 .liveness_failure,
3194 .codegen_failure,
3195 .dependency_failure,3521 .dependency_failure,
3196 .sema_failure_retryable,
3197 => return error.AnalysisFail,3522 => return error.AnalysisFail,
31983523
3199 .complete, .codegen_failure_retryable => {3524 .complete => {},
3200 switch (func.analysis(ip).state) {3525 }
3201 .sema_failure, .dependency_failure => return error.AnalysisFail,
3202 .none, .queued => {},
3203 .in_progress => unreachable,
3204 .inline_only => unreachable, // don't queue work for this
3205 .success => return,
3206 }
32073526
3208 const gpa = zcu.gpa;3527 const func_as_depender = InternPool.Depender.wrap(.{ .func = func_index });
3528 const was_outdated = zcu.outdated.swapRemove(func_as_depender) or
3529 zcu.potentially_outdated.swapRemove(func_as_depender);
32093530
3210 var tmp_arena = std.heap.ArenaAllocator.init(gpa);3531 if (was_outdated) {
3211 defer tmp_arena.deinit();3532 _ = zcu.outdated_ready.swapRemove(func_as_depender);
3212 const sema_arena = tmp_arena.allocator();3533 }
32133534
3214 var air = zcu.analyzeFnBody(func_index, sema_arena) catch |err| switch (err) {3535 switch (func.analysis(ip).state) {
3215 error.AnalysisFail => {3536 .success,
3216 if (func.analysis(ip).state == .in_progress) {3537 .sema_failure,
3217 // If this decl caused the compile error, the analysis field would3538 .dependency_failure,
3218 // be changed to indicate it was this Decl's fault. Because this3539 .codegen_failure,
3219 // did not happen, we infer here that it was a dependency failure.3540 => if (!was_outdated) return error.AnalysisFail,
3220 func.analysis(ip).state = .dependency_failure;3541 .none, .queued => {},
3221 }3542 .in_progress => unreachable,
3222 return error.AnalysisFail;3543 .inline_only => unreachable, // don't queue work for this
3223 },3544 }
3224 error.OutOfMemory => return error.OutOfMemory,
3225 };
3226 defer air.deinit(gpa);
32273545
3228 const comp = zcu.comp;3546 const gpa = zcu.gpa;
32293547
3230 const dump_air = builtin.mode == .Debug and comp.verbose_air;3548 var tmp_arena = std.heap.ArenaAllocator.init(gpa);
3231 const dump_llvm_ir = builtin.mode == .Debug and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null);3549 defer tmp_arena.deinit();
3550 const sema_arena = tmp_arena.allocator();
32323551
3233 if (comp.bin_file == null and zcu.llvm_object == null and !dump_air and !dump_llvm_ir) {3552 var air = zcu.analyzeFnBody(func_index, sema_arena) catch |err| switch (err) {
3234 return;3553 error.AnalysisFail => {
3554 if (func.analysis(ip).state == .in_progress) {
3555 // If this decl caused the compile error, the analysis field would
3556 // be changed to indicate it was this Decl's fault. Because this
3557 // did not happen, we infer here that it was a dependency failure.
3558 func.analysis(ip).state = .dependency_failure;
3235 }3559 }
3560 return error.AnalysisFail;
3561 },
3562 error.OutOfMemory => return error.OutOfMemory,
3563 };
3564 defer air.deinit(gpa);
32363565
3237 var liveness = try Liveness.analyze(gpa, air, ip);3566 const comp = zcu.comp;
3238 defer liveness.deinit(gpa);
32393567
3240 if (dump_air) {3568 const dump_air = builtin.mode == .Debug and comp.verbose_air;
3241 const fqn = try decl.getFullyQualifiedName(zcu);3569 const dump_llvm_ir = builtin.mode == .Debug and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null);
3242 std.debug.print("# Begin Function AIR: {}:\n", .{fqn.fmt(ip)});
3243 @import("print_air.zig").dump(zcu, air, liveness);
3244 std.debug.print("# End Function AIR: {}\n\n", .{fqn.fmt(ip)});
3245 }
32463570
3247 if (std.debug.runtime_safety) {3571 if (comp.bin_file == null and zcu.llvm_object == null and !dump_air and !dump_llvm_ir) {
3248 var verify = Liveness.Verify{3572 return;
3249 .gpa = gpa,3573 }
3250 .air = air,
3251 .liveness = liveness,
3252 .intern_pool = ip,
3253 };
3254 defer verify.deinit();
3255
3256 verify.verify() catch |err| switch (err) {
3257 error.OutOfMemory => return error.OutOfMemory,
3258 else => {
3259 try zcu.failed_decls.ensureUnusedCapacity(gpa, 1);
3260 zcu.failed_decls.putAssumeCapacityNoClobber(
3261 decl_index,
3262 try Module.ErrorMsg.create(
3263 gpa,
3264 decl.srcLoc(zcu),
3265 "invalid liveness: {s}",
3266 .{@errorName(err)},
3267 ),
3268 );
3269 decl.analysis = .liveness_failure;
3270 return error.AnalysisFail;
3271 },
3272 };
3273 }
32743574
3275 if (comp.bin_file) |lf| {3575 var liveness = try Liveness.analyze(gpa, air, ip);
3276 lf.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) {3576 defer liveness.deinit(gpa);
3277 error.OutOfMemory => return error.OutOfMemory,3577
3278 error.AnalysisFail => {3578 if (dump_air) {
3279 decl.analysis = .codegen_failure;3579 const fqn = try decl.getFullyQualifiedName(zcu);
3280 },3580 std.debug.print("# Begin Function AIR: {}:\n", .{fqn.fmt(ip)});
3281 else => {3581 @import("print_air.zig").dump(zcu, air, liveness);
3282 try zcu.failed_decls.ensureUnusedCapacity(gpa, 1);3582 std.debug.print("# End Function AIR: {}\n\n", .{fqn.fmt(ip)});
3283 zcu.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create(3583 }
3284 gpa,3584
3285 decl.srcLoc(zcu),3585 if (std.debug.runtime_safety) {
3286 "unable to codegen: {s}",3586 var verify = Liveness.Verify{
3287 .{@errorName(err)},3587 .gpa = gpa,
3288 ));3588 .air = air,
3289 decl.analysis = .codegen_failure_retryable;3589 .liveness = liveness,
3290 },3590 .intern_pool = ip,
3291 };3591 };
3292 } else if (zcu.llvm_object) |llvm_object| {3592 defer verify.deinit();
3293 if (build_options.only_c) unreachable;3593
3294 llvm_object.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) {3594 verify.verify() catch |err| switch (err) {
3295 error.OutOfMemory => return error.OutOfMemory,3595 error.OutOfMemory => return error.OutOfMemory,
3296 error.AnalysisFail => {3596 else => {
3297 decl.analysis = .codegen_failure;3597 try zcu.failed_decls.ensureUnusedCapacity(gpa, 1);
3298 },3598 zcu.failed_decls.putAssumeCapacityNoClobber(
3299 };3599 decl_index,
3300 }3600 try Module.ErrorMsg.create(
3301 },3601 gpa,
3602 decl.srcLoc(zcu),
3603 "invalid liveness: {s}",
3604 .{@errorName(err)},
3605 ),
3606 );
3607 func.analysis(ip).state = .codegen_failure;
3608 return;
3609 },
3610 };
3611 }
3612
3613 if (comp.bin_file) |lf| {
3614 lf.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) {
3615 error.OutOfMemory => return error.OutOfMemory,
3616 error.AnalysisFail => {
3617 func.analysis(ip).state = .codegen_failure;
3618 },
3619 else => {
3620 try zcu.failed_decls.ensureUnusedCapacity(gpa, 1);
3621 zcu.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create(
3622 gpa,
3623 decl.srcLoc(zcu),
3624 "unable to codegen: {s}",
3625 .{@errorName(err)},
3626 ));
3627 func.analysis(ip).state = .codegen_failure;
3628 try zcu.retryable_failures.append(zcu.gpa, InternPool.Depender.wrap(.{ .func = func_index }));
3629 },
3630 };
3631 } else if (zcu.llvm_object) |llvm_object| {
3632 if (build_options.only_c) unreachable;
3633 llvm_object.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) {
3634 error.OutOfMemory => return error.OutOfMemory,
3635 error.AnalysisFail => {
3636 func.analysis(ip).state = .codegen_failure;
3637 },
3638 };
3302 }3639 }
3303}3640}
33043641
...@@ -3318,18 +3655,14 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index)...@@ -3318,18 +3655,14 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index)
3318 switch (decl.analysis) {3655 switch (decl.analysis) {
3319 .unreferenced => unreachable,3656 .unreferenced => unreachable,
3320 .in_progress => unreachable,3657 .in_progress => unreachable,
3321 .outdated => unreachable,
33223658
3323 .file_failure,3659 .file_failure,
3324 .sema_failure,3660 .sema_failure,
3325 .liveness_failure,
3326 .codegen_failure,3661 .codegen_failure,
3327 .dependency_failure,3662 .dependency_failure,
3328 .sema_failure_retryable,3663 // Analysis of the function Decl itself failed, but we've already
3329 .codegen_failure_retryable,3664 // emitted an error for that. The callee doesn't need the function to be
3330 // The function analysis failed, but we've already emitted an error for3665 // analyzed right now, so its analysis can safely continue.
3331 // that. The callee doesn't need the function to be analyzed right now,
3332 // so its analysis can safely continue.
3333 => return,3666 => return,
33343667
3335 .complete => {},3668 .complete => {},
...@@ -3337,14 +3670,21 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index)...@@ -3337,14 +3670,21 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index)
33373670
3338 assert(decl.has_tv);3671 assert(decl.has_tv);
33393672
3673 const func_as_depender = InternPool.Depender.wrap(.{ .func = func_index });
3674 const is_outdated = mod.outdated.contains(func_as_depender) or
3675 mod.potentially_outdated.contains(func_as_depender);
3676
3340 switch (func.analysis(ip).state) {3677 switch (func.analysis(ip).state) {
3341 .none => {},3678 .none => {},
3342 .queued => return,3679 .queued => return,
3343 // As above, we don't need to forward errors here.3680 // As above, we don't need to forward errors here.
3344 .sema_failure, .dependency_failure => return,3681 .sema_failure,
3682 .dependency_failure,
3683 .codegen_failure,
3684 .success,
3685 => if (!is_outdated) return,
3345 .in_progress => return,3686 .in_progress => return,
3346 .inline_only => unreachable, // don't queue work for this3687 .inline_only => unreachable, // don't queue work for this
3347 .success => return,
3348 }3688 }
33493689
3350 // Decl itself is safely analyzed, and body analysis is not yet queued3690 // Decl itself is safely analyzed, and body analysis is not yet queued
...@@ -3404,7 +3744,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {...@@ -3404,7 +3744,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
3404 new_decl.@"linksection" = .none;3744 new_decl.@"linksection" = .none;
3405 new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive.3745 new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive.
3406 new_decl.analysis = .in_progress;3746 new_decl.analysis = .in_progress;
3407 new_decl.generation = mod.generation;
34083747
3409 if (file.status != .success_zir) {3748 if (file.status != .success_zir) {
3410 new_decl.analysis = .file_failure;3749 new_decl.analysis = .file_failure;
...@@ -3483,12 +3822,19 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {...@@ -3483,12 +3822,19 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
3483 },3822 },
3484 .incremental => {},3823 .incremental => {},
3485 }3824 }
3825
3826 // Since this is our first time analyzing this file, there can be no dependencies on
3827 // its root Decl. Thus, we do not need to invalidate any dependencies.
3486}3828}
34873829
3488/// Returns `true` if the Decl type changed.3830const SemaDeclResult = packed struct {
3489/// Returns `true` if this is the first time analyzing the Decl.3831 /// Whether the value of a `decl_val` of this Decl changed.
3490/// Returns `false` otherwise.3832 invalidate_decl_val: bool,
3491fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {3833 /// Whether the type of a `decl_ref` of this Decl changed.
3834 invalidate_decl_ref: bool,
3835};
3836
3837fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
3492 const tracy = trace(@src());3838 const tracy = trace(@src());
3493 defer tracy.end();3839 defer tracy.end();
34943840
...@@ -3499,6 +3845,15 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -3499,6 +3845,15 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
3499 return error.AnalysisFail;3845 return error.AnalysisFail;
3500 }3846 }
35013847
3848 if (mod.declIsRoot(decl_index)) {
3849 // This comes from an `analyze_decl` job on an incremental update where
3850 // this file changed.
3851 @panic("TODO: update root Decl of modified file");
3852 } else if (decl.owns_tv) {
3853 // We are re-analyzing an owner Decl (for a function or a namespace type).
3854 @panic("TODO: update owner Decl");
3855 }
3856
3502 const gpa = mod.gpa;3857 const gpa = mod.gpa;
3503 const zir = decl.getFileScope(mod).zir;3858 const zir = decl.getFileScope(mod).zir;
35043859
...@@ -3535,6 +3890,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -3535,6 +3890,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
3535 break :blk .none;3890 break :blk .none;
3536 };3891 };
35373892
3893 mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .decl = decl_index }));
3894
3538 decl.analysis = .in_progress;3895 decl.analysis = .in_progress;
35393896
3540 var analysis_arena = std.heap.ArenaAllocator.init(gpa);3897 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
...@@ -3564,7 +3921,12 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -3564,7 +3921,12 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
3564 };3921 };
3565 defer sema.deinit();3922 defer sema.deinit();
35663923
3567 assert(!mod.declIsRoot(decl_index));3924 // Every Decl (other than file root Decls, which do not have a ZIR index) has a dependency on its own source.
3925 try sema.declareDependency(.{ .src_hash = try ip.trackZir(
3926 sema.gpa,
3927 decl.getFileScope(mod),
3928 decl.zir_decl_index.unwrap().?,
3929 ) });
35683930
3569 var block_scope: Sema.Block = .{3931 var block_scope: Sema.Block = .{
3570 .parent = null,3932 .parent = null,
...@@ -3620,9 +3982,12 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -3620,9 +3982,12 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
3620 decl.has_tv = true;3982 decl.has_tv = true;
3621 decl.owns_tv = false;3983 decl.owns_tv = false;
3622 decl.analysis = .complete;3984 decl.analysis = .complete;
3623 decl.generation = mod.generation;
36243985
3625 return true;3986 // TODO: usingnamespace cannot currently participate in incremental compilation
3987 return .{
3988 .invalidate_decl_val = true,
3989 .invalidate_decl_ref = true,
3990 };
3626 }3991 }
36273992
3628 switch (ip.indexToKey(decl_tv.val.toIntern())) {3993 switch (ip.indexToKey(decl_tv.val.toIntern())) {
...@@ -3647,7 +4012,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -3647,7 +4012,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
3647 decl.has_tv = true;4012 decl.has_tv = true;
3648 decl.owns_tv = owns_tv;4013 decl.owns_tv = owns_tv;
3649 decl.analysis = .complete;4014 decl.analysis = .complete;
3650 decl.generation = mod.generation;
36514015
3652 const is_inline = decl.ty.fnCallingConvention(mod) == .Inline;4016 const is_inline = decl.ty.fnCallingConvention(mod) == .Inline;
3653 if (decl.is_exported) {4017 if (decl.is_exported) {
...@@ -3658,15 +4022,16 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -3658,15 +4022,16 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
3658 // The scope needs to have the decl in it.4022 // The scope needs to have the decl in it.
3659 try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);4023 try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);
3660 }4024 }
3661 return type_changed or is_inline != prev_is_inline;4025 // TODO: align, linksection, addrspace?
4026 const changed = type_changed or is_inline != prev_is_inline;
4027 return .{
4028 .invalidate_decl_val = changed,
4029 .invalidate_decl_ref = changed,
4030 };
3662 }4031 }
3663 },4032 },
3664 else => {},4033 else => {},
3665 }4034 }
3666 var type_changed = true;
3667 if (decl.has_tv) {
3668 type_changed = !decl.ty.eql(decl_tv.ty, mod);
3669 }
36704035
3671 decl.owns_tv = false;4036 decl.owns_tv = false;
3672 var queue_linker_work = false;4037 var queue_linker_work = false;
...@@ -3694,6 +4059,14 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -3694,6 +4059,14 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
3694 },4059 },
3695 }4060 }
36964061
4062 const old_has_tv = decl.has_tv;
4063 // The following values are ignored if `!old_has_tv`
4064 const old_ty = decl.ty;
4065 const old_val = decl.val;
4066 const old_align = decl.alignment;
4067 const old_linksection = decl.@"linksection";
4068 const old_addrspace = decl.@"addrspace";
4069
3697 decl.ty = decl_tv.ty;4070 decl.ty = decl_tv.ty;
3698 decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod)));4071 decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod)));
3699 decl.alignment = blk: {4072 decl.alignment = blk: {
...@@ -3735,7 +4108,17 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -3735,7 +4108,17 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
3735 };4108 };
3736 decl.has_tv = true;4109 decl.has_tv = true;
3737 decl.analysis = .complete;4110 decl.analysis = .complete;
3738 decl.generation = mod.generation;4111
4112 const result: SemaDeclResult = if (old_has_tv) .{
4113 .invalidate_decl_val = !decl.ty.eql(old_ty, mod) or !decl.val.eql(old_val, decl.ty, mod),
4114 .invalidate_decl_ref = !decl.ty.eql(old_ty, mod) or
4115 decl.alignment != old_align or
4116 decl.@"linksection" != old_linksection or
4117 decl.@"addrspace" != old_addrspace,
4118 } else .{
4119 .invalidate_decl_val = true,
4120 .invalidate_decl_ref = true,
4121 };
37394122
3740 const has_runtime_bits = is_extern or4123 const has_runtime_bits = is_extern or
3741 (queue_linker_work and try sema.typeHasRuntimeBits(decl.ty));4124 (queue_linker_work and try sema.typeHasRuntimeBits(decl.ty));
...@@ -3748,7 +4131,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -3748,7 +4131,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
37484131
3749 try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index });4132 try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index });
37504133
3751 if (type_changed and mod.emit_h != null) {4134 if (result.invalidate_decl_ref and mod.emit_h != null) {
3752 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index });4135 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index });
3753 }4136 }
3754 }4137 }
...@@ -3759,7 +4142,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {...@@ -3759,7 +4142,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
3759 try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);4142 try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);
3760 }4143 }
37614144
3762 return type_changed;4145 return result;
3763}4146}
37644147
3765pub const ImportFileResult = struct {4148pub const ImportFileResult = struct {
...@@ -4362,6 +4745,8 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato...@@ -4362,6 +4745,8 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
4362 const decl_index = func.owner_decl;4745 const decl_index = func.owner_decl;
4363 const decl = mod.declPtr(decl_index);4746 const decl = mod.declPtr(decl_index);
43644747
4748 mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index }));
4749
4365 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);4750 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
4366 defer comptime_mutable_decls.deinit();4751 defer comptime_mutable_decls.deinit();
43674752
...@@ -4633,7 +5018,6 @@ pub fn allocateNewDecl(...@@ -4633,7 +5018,6 @@ pub fn allocateNewDecl(
4633 .analysis = .unreferenced,5018 .analysis = .unreferenced,
4634 .zir_decl_index = .none,5019 .zir_decl_index = .none,
4635 .src_scope = src_scope,5020 .src_scope = src_scope,
4636 .generation = 0,
4637 .is_pub = false,5021 .is_pub = false,
4638 .is_exported = false,5022 .is_exported = false,
4639 .alive = false,5023 .alive = false,
...@@ -4711,7 +5095,6 @@ pub fn initNewAnonDecl(...@@ -4711,7 +5095,6 @@ pub fn initNewAnonDecl(
4711 new_decl.@"linksection" = .none;5095 new_decl.@"linksection" = .none;
4712 new_decl.has_tv = true;5096 new_decl.has_tv = true;
4713 new_decl.analysis = .complete;5097 new_decl.analysis = .complete;
4714 new_decl.generation = mod.generation;
4715}5098}
47165099
4717pub fn errNoteNonLazy(5100pub fn errNoteNonLazy(
...@@ -5373,7 +5756,8 @@ pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void {...@@ -5373,7 +5756,8 @@ pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void {
5373 "unable to codegen: {s}",5756 "unable to codegen: {s}",
5374 .{@errorName(err)},5757 .{@errorName(err)},
5375 ));5758 ));
5376 decl.analysis = .codegen_failure_retryable;5759 decl.analysis = .codegen_failure;
5760 try zcu.retryable_failures.append(zcu.gpa, InternPool.Depender.wrap(.{ .decl = decl_index }));
5377 },5761 },
5378 };5762 };
5379 } else if (zcu.llvm_object) |llvm_object| {5763 } else if (zcu.llvm_object) |llvm_object| {
src/Sema.zig+94-22
...@@ -2583,7 +2583,6 @@ fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Module.ErrorMsg)...@@ -2583,7 +2583,6 @@ fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Module.ErrorMsg)
2583 ip.funcAnalysis(sema.owner_func_index).state = .sema_failure;2583 ip.funcAnalysis(sema.owner_func_index).state = .sema_failure;
2584 } else {2584 } else {
2585 sema.owner_decl.analysis = .sema_failure;2585 sema.owner_decl.analysis = .sema_failure;
2586 sema.owner_decl.generation = mod.generation;
2587 }2586 }
2588 if (sema.func_index != .none) {2587 if (sema.func_index != .none) {
2589 ip.funcAnalysis(sema.func_index).state = .sema_failure;2588 ip.funcAnalysis(sema.func_index).state = .sema_failure;
...@@ -2718,7 +2717,7 @@ pub fn getStructType(...@@ -2718,7 +2717,7 @@ pub fn getStructType(
2718 assert(extended.opcode == .struct_decl);2717 assert(extended.opcode == .struct_decl);
2719 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);2718 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
27202719
2721 var extra_index: usize = extended.operand;2720 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
2722 extra_index += @intFromBool(small.has_src_node);2721 extra_index += @intFromBool(small.has_src_node);
2723 const fields_len = if (small.has_fields_len) blk: {2722 const fields_len = if (small.has_fields_len) blk: {
2724 const fields_len = sema.code.extra[extra_index];2723 const fields_len = sema.code.extra[extra_index];
...@@ -2748,7 +2747,7 @@ pub fn getStructType(...@@ -2748,7 +2747,7 @@ pub fn getStructType(
2748 const ty = try ip.getStructType(gpa, .{2747 const ty = try ip.getStructType(gpa, .{
2749 .decl = decl,2748 .decl = decl,
2750 .namespace = namespace.toOptional(),2749 .namespace = namespace.toOptional(),
2751 .zir_index = tracked_inst,2750 .zir_index = tracked_inst.toOptional(),
2752 .layout = small.layout,2751 .layout = small.layout,
2753 .known_non_opv = small.known_non_opv,2752 .known_non_opv = small.known_non_opv,
2754 .is_tuple = small.is_tuple,2753 .is_tuple = small.is_tuple,
...@@ -2773,7 +2772,7 @@ fn zirStructDecl(...@@ -2773,7 +2772,7 @@ fn zirStructDecl(
2773 const ip = &mod.intern_pool;2772 const ip = &mod.intern_pool;
2774 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);2773 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
2775 const src: LazySrcLoc = if (small.has_src_node) blk: {2774 const src: LazySrcLoc = if (small.has_src_node) blk: {
2776 const node_offset: i32 = @bitCast(sema.code.extra[extended.operand]);2775 const node_offset: i32 = @bitCast(sema.code.extra[extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len]);
2777 break :blk LazySrcLoc.nodeOffset(node_offset);2776 break :blk LazySrcLoc.nodeOffset(node_offset);
2778 } else sema.src;2777 } else sema.src;
27792778
...@@ -2789,6 +2788,14 @@ fn zirStructDecl(...@@ -2789,6 +2788,14 @@ fn zirStructDecl(
2789 new_decl.owns_tv = true;2788 new_decl.owns_tv = true;
2790 errdefer mod.abortAnonDecl(new_decl_index);2789 errdefer mod.abortAnonDecl(new_decl_index);
27912790
2791 if (sema.mod.comp.debug_incremental) {
2792 try ip.addDependency(
2793 sema.gpa,
2794 InternPool.Depender.wrap(.{ .decl = new_decl_index }),
2795 .{ .src_hash = try ip.trackZir(sema.gpa, block.getFileScope(mod), inst) },
2796 );
2797 }
2798
2792 const new_namespace_index = try mod.createNamespace(.{2799 const new_namespace_index = try mod.createNamespace(.{
2793 .parent = block.namespace.toOptional(),2800 .parent = block.namespace.toOptional(),
2794 .ty = undefined,2801 .ty = undefined,
...@@ -2927,7 +2934,7 @@ fn zirEnumDecl(...@@ -2927,7 +2934,7 @@ fn zirEnumDecl(
2927 const mod = sema.mod;2934 const mod = sema.mod;
2928 const gpa = sema.gpa;2935 const gpa = sema.gpa;
2929 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);2936 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
2930 var extra_index: usize = extended.operand;2937 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.EnumDecl).Struct.fields.len;
29312938
2932 const src: LazySrcLoc = if (small.has_src_node) blk: {2939 const src: LazySrcLoc = if (small.has_src_node) blk: {
2933 const node_offset: i32 = @bitCast(sema.code.extra[extra_index]);2940 const node_offset: i32 = @bitCast(sema.code.extra[extra_index]);
...@@ -2973,6 +2980,14 @@ fn zirEnumDecl(...@@ -2973,6 +2980,14 @@ fn zirEnumDecl(
2973 new_decl.owns_tv = true;2980 new_decl.owns_tv = true;
2974 errdefer if (!done) mod.abortAnonDecl(new_decl_index);2981 errdefer if (!done) mod.abortAnonDecl(new_decl_index);
29752982
2983 if (sema.mod.comp.debug_incremental) {
2984 try mod.intern_pool.addDependency(
2985 sema.gpa,
2986 InternPool.Depender.wrap(.{ .decl = new_decl_index }),
2987 .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
2988 );
2989 }
2990
2976 const new_namespace_index = try mod.createNamespace(.{2991 const new_namespace_index = try mod.createNamespace(.{
2977 .parent = block.namespace.toOptional(),2992 .parent = block.namespace.toOptional(),
2978 .ty = undefined,2993 .ty = undefined,
...@@ -3008,6 +3023,7 @@ fn zirEnumDecl(...@@ -3008,6 +3023,7 @@ fn zirEnumDecl(
3008 .auto3023 .auto
3009 else3024 else
3010 .explicit,3025 .explicit,
3026 .zir_index = (try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst)).toOptional(),
3011 });3027 });
3012 if (sema.builtin_type_target_index != .none) {3028 if (sema.builtin_type_target_index != .none) {
3013 mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, incomplete_enum.index);3029 mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, incomplete_enum.index);
...@@ -3191,7 +3207,7 @@ fn zirUnionDecl(...@@ -3191,7 +3207,7 @@ fn zirUnionDecl(
3191 const mod = sema.mod;3207 const mod = sema.mod;
3192 const gpa = sema.gpa;3208 const gpa = sema.gpa;
3193 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);3209 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
3194 var extra_index: usize = extended.operand;3210 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.UnionDecl).Struct.fields.len;
31953211
3196 const src: LazySrcLoc = if (small.has_src_node) blk: {3212 const src: LazySrcLoc = if (small.has_src_node) blk: {
3197 const node_offset: i32 = @bitCast(sema.code.extra[extra_index]);3213 const node_offset: i32 = @bitCast(sema.code.extra[extra_index]);
...@@ -3225,6 +3241,14 @@ fn zirUnionDecl(...@@ -3225,6 +3241,14 @@ fn zirUnionDecl(
3225 new_decl.owns_tv = true;3241 new_decl.owns_tv = true;
3226 errdefer mod.abortAnonDecl(new_decl_index);3242 errdefer mod.abortAnonDecl(new_decl_index);
32273243
3244 if (sema.mod.comp.debug_incremental) {
3245 try mod.intern_pool.addDependency(
3246 sema.gpa,
3247 InternPool.Depender.wrap(.{ .decl = new_decl_index }),
3248 .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
3249 );
3250 }
3251
3228 const new_namespace_index = try mod.createNamespace(.{3252 const new_namespace_index = try mod.createNamespace(.{
3229 .parent = block.namespace.toOptional(),3253 .parent = block.namespace.toOptional(),
3230 .ty = undefined,3254 .ty = undefined,
...@@ -3254,7 +3278,7 @@ fn zirUnionDecl(...@@ -3254,7 +3278,7 @@ fn zirUnionDecl(
3254 },3278 },
3255 .decl = new_decl_index,3279 .decl = new_decl_index,
3256 .namespace = new_namespace_index,3280 .namespace = new_namespace_index,
3257 .zir_index = try mod.intern_pool.trackZir(gpa, block.getFileScope(mod), inst),3281 .zir_index = (try mod.intern_pool.trackZir(gpa, block.getFileScope(mod), inst)).toOptional(),
3258 .fields_len = fields_len,3282 .fields_len = fields_len,
3259 .enum_tag_ty = .none,3283 .enum_tag_ty = .none,
3260 .field_types = &.{},3284 .field_types = &.{},
...@@ -3318,6 +3342,14 @@ fn zirOpaqueDecl(...@@ -3318,6 +3342,14 @@ fn zirOpaqueDecl(
3318 new_decl.owns_tv = true;3342 new_decl.owns_tv = true;
3319 errdefer mod.abortAnonDecl(new_decl_index);3343 errdefer mod.abortAnonDecl(new_decl_index);
33203344
3345 if (sema.mod.comp.debug_incremental) {
3346 try mod.intern_pool.addDependency(
3347 sema.gpa,
3348 InternPool.Depender.wrap(.{ .decl = new_decl_index }),
3349 .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
3350 );
3351 }
3352
3321 const new_namespace_index = try mod.createNamespace(.{3353 const new_namespace_index = try mod.createNamespace(.{
3322 .parent = block.namespace.toOptional(),3354 .parent = block.namespace.toOptional(),
3323 .ty = undefined,3355 .ty = undefined,
...@@ -3329,6 +3361,7 @@ fn zirOpaqueDecl(...@@ -3329,6 +3361,7 @@ fn zirOpaqueDecl(
3329 const opaque_ty = try mod.intern(.{ .opaque_type = .{3361 const opaque_ty = try mod.intern(.{ .opaque_type = .{
3330 .decl = new_decl_index,3362 .decl = new_decl_index,
3331 .namespace = new_namespace_index,3363 .namespace = new_namespace_index,
3364 .zir_index = (try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst)).toOptional(),
3332 } });3365 } });
3333 // TODO: figure out InternPool removals for incremental compilation3366 // TODO: figure out InternPool removals for incremental compilation
3334 //errdefer mod.intern_pool.remove(opaque_ty);3367 //errdefer mod.intern_pool.remove(opaque_ty);
...@@ -7890,6 +7923,8 @@ fn instantiateGenericCall(...@@ -7890,6 +7923,8 @@ fn instantiateGenericCall(
7890 const generic_owner_func = mod.intern_pool.indexToKey(generic_owner).func;7923 const generic_owner_func = mod.intern_pool.indexToKey(generic_owner).func;
7891 const generic_owner_ty_info = mod.typeToFunc(Type.fromInterned(generic_owner_func.ty)).?;7924 const generic_owner_ty_info = mod.typeToFunc(Type.fromInterned(generic_owner_func.ty)).?;
78927925
7926 try sema.declareDependency(.{ .src_hash = generic_owner_func.zir_body_inst });
7927
7893 // Even though there may already be a generic instantiation corresponding7928 // Even though there may already be a generic instantiation corresponding
7894 // to this callsite, we must evaluate the expressions of the generic7929 // to this callsite, we must evaluate the expressions of the generic
7895 // function signature with the values of the callsite plugged in.7930 // function signature with the values of the callsite plugged in.
...@@ -9440,7 +9475,6 @@ fn funcCommon(...@@ -9440,7 +9475,6 @@ fn funcCommon(
9440 .inferred_error_set = inferred_error_set,9475 .inferred_error_set = inferred_error_set,
9441 .generic_owner = sema.generic_owner,9476 .generic_owner = sema.generic_owner,
9442 .comptime_args = sema.comptime_args,9477 .comptime_args = sema.comptime_args,
9443 .generation = mod.generation,
9444 });9478 });
9445 return finishFunc(9479 return finishFunc(
9446 sema,9480 sema,
...@@ -13598,6 +13632,12 @@ fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -13598,6 +13632,12 @@ fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
13598 });13632 });
1359913633
13600 try sema.checkNamespaceType(block, lhs_src, container_type);13634 try sema.checkNamespaceType(block, lhs_src, container_type);
13635 if (container_type.typeDeclInst(mod)) |type_decl_inst| {
13636 try sema.declareDependency(.{ .namespace_name = .{
13637 .namespace = type_decl_inst,
13638 .name = decl_name,
13639 } });
13640 }
1360113641
13602 const namespace = container_type.getNamespaceIndex(mod).unwrap() orelse13642 const namespace = container_type.getNamespaceIndex(mod).unwrap() orelse
13603 return .bool_false;13643 return .bool_false;
...@@ -17451,6 +17491,10 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17451,6 +17491,10 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17451 const type_info_ty = try sema.getBuiltinType("Type");17491 const type_info_ty = try sema.getBuiltinType("Type");
17452 const type_info_tag_ty = type_info_ty.unionTagType(mod).?;17492 const type_info_tag_ty = type_info_ty.unionTagType(mod).?;
1745317493
17494 if (ty.typeDeclInst(mod)) |type_decl_inst| {
17495 try sema.declareDependency(.{ .namespace = type_decl_inst });
17496 }
17497
17454 switch (ty.zigTypeTag(mod)) {17498 switch (ty.zigTypeTag(mod)) {
17455 .Type,17499 .Type,
17456 .Void,17500 .Void,
...@@ -21318,6 +21362,7 @@ fn zirReify(...@@ -21318,6 +21362,7 @@ fn zirReify(
21318 else21362 else
21319 .explicit,21363 .explicit,
21320 .tag_ty = int_tag_ty.toIntern(),21364 .tag_ty = int_tag_ty.toIntern(),
21365 .zir_index = .none,
21321 });21366 });
21322 // TODO: figure out InternPool removals for incremental compilation21367 // TODO: figure out InternPool removals for incremental compilation
21323 //errdefer ip.remove(incomplete_enum.index);21368 //errdefer ip.remove(incomplete_enum.index);
...@@ -21415,6 +21460,7 @@ fn zirReify(...@@ -21415,6 +21460,7 @@ fn zirReify(
21415 const opaque_ty = try mod.intern(.{ .opaque_type = .{21460 const opaque_ty = try mod.intern(.{ .opaque_type = .{
21416 .decl = new_decl_index,21461 .decl = new_decl_index,
21417 .namespace = new_namespace_index,21462 .namespace = new_namespace_index,
21463 .zir_index = .none,
21418 } });21464 } });
21419 // TODO: figure out InternPool removals for incremental compilation21465 // TODO: figure out InternPool removals for incremental compilation
21420 //errdefer ip.remove(opaque_ty);21466 //errdefer ip.remove(opaque_ty);
...@@ -21633,7 +21679,7 @@ fn zirReify(...@@ -21633,7 +21679,7 @@ fn zirReify(
21633 .namespace = new_namespace_index,21679 .namespace = new_namespace_index,
21634 .enum_tag_ty = enum_tag_ty,21680 .enum_tag_ty = enum_tag_ty,
21635 .fields_len = fields_len,21681 .fields_len = fields_len,
21636 .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst), // TODO: should reified types be handled differently?21682 .zir_index = .none,
21637 .flags = .{21683 .flags = .{
21638 .layout = layout,21684 .layout = layout,
21639 .status = .have_field_types,21685 .status = .have_field_types,
...@@ -21801,7 +21847,7 @@ fn reifyStruct(...@@ -21801,7 +21847,7 @@ fn reifyStruct(
21801 const ty = try ip.getStructType(gpa, .{21847 const ty = try ip.getStructType(gpa, .{
21802 .decl = new_decl_index,21848 .decl = new_decl_index,
21803 .namespace = .none,21849 .namespace = .none,
21804 .zir_index = try mod.intern_pool.trackZir(gpa, block.getFileScope(mod), inst), // TODO: should reified types be handled differently?21850 .zir_index = .none,
21805 .layout = layout,21851 .layout = layout,
21806 .known_non_opv = false,21852 .known_non_opv = false,
21807 .fields_len = fields_len,21853 .fields_len = fields_len,
...@@ -25922,7 +25968,6 @@ fn zirBuiltinExtern(...@@ -25922,7 +25968,6 @@ fn zirBuiltinExtern(
25922 new_decl.has_tv = true;25968 new_decl.has_tv = true;
25923 new_decl.owns_tv = true;25969 new_decl.owns_tv = true;
25924 new_decl.analysis = .complete;25970 new_decl.analysis = .complete;
25925 new_decl.generation = mod.generation;
2592625971
25927 try sema.ensureDeclAnalyzed(new_decl_index);25972 try sema.ensureDeclAnalyzed(new_decl_index);
2592825973
...@@ -26421,6 +26466,7 @@ fn prepareSimplePanic(sema: *Sema, block: *Block) !void {...@@ -26421,6 +26466,7 @@ fn prepareSimplePanic(sema: *Sema, block: *Block) !void {
26421 // owns the function.26466 // owns the function.
26422 try sema.ensureDeclAnalyzed(decl_index);26467 try sema.ensureDeclAnalyzed(decl_index);
26423 const tv = try mod.declPtr(decl_index).typedValue();26468 const tv = try mod.declPtr(decl_index).typedValue();
26469 try sema.declareDependency(.{ .decl_val = decl_index });
26424 assert(tv.ty.zigTypeTag(mod) == .Fn);26470 assert(tv.ty.zigTypeTag(mod) == .Fn);
26425 assert(try sema.fnHasRuntimeBits(tv.ty));26471 assert(try sema.fnHasRuntimeBits(tv.ty));
26426 const func_index = tv.val.toIntern();26472 const func_index = tv.val.toIntern();
...@@ -26842,6 +26888,13 @@ fn fieldVal(...@@ -26842,6 +26888,13 @@ fn fieldVal(
26842 const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?;26888 const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?;
26843 const child_type = val.toType();26889 const child_type = val.toType();
2684426890
26891 if (child_type.typeDeclInst(mod)) |type_decl_inst| {
26892 try sema.declareDependency(.{ .namespace_name = .{
26893 .namespace = type_decl_inst,
26894 .name = field_name,
26895 } });
26896 }
26897
26845 switch (try child_type.zigTypeTagOrPoison(mod)) {26898 switch (try child_type.zigTypeTagOrPoison(mod)) {
26846 .ErrorSet => {26899 .ErrorSet => {
26847 switch (ip.indexToKey(child_type.toIntern())) {26900 switch (ip.indexToKey(child_type.toIntern())) {
...@@ -27065,6 +27118,13 @@ fn fieldPtr(...@@ -27065,6 +27118,13 @@ fn fieldPtr(
27065 const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?;27118 const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?;
27066 const child_type = val.toType();27119 const child_type = val.toType();
2706727120
27121 if (child_type.typeDeclInst(mod)) |type_decl_inst| {
27122 try sema.declareDependency(.{ .namespace_name = .{
27123 .namespace = type_decl_inst,
27124 .name = field_name,
27125 } });
27126 }
27127
27068 switch (child_type.zigTypeTag(mod)) {27128 switch (child_type.zigTypeTag(mod)) {
27069 .ErrorSet => {27129 .ErrorSet => {
27070 switch (ip.indexToKey(child_type.toIntern())) {27130 switch (ip.indexToKey(child_type.toIntern())) {
...@@ -31134,6 +31194,7 @@ fn beginComptimePtrLoad(...@@ -31134,6 +31194,7 @@ fn beginComptimePtrLoad(
31134 const is_mutable = ptr.addr == .mut_decl;31194 const is_mutable = ptr.addr == .mut_decl;
31135 const decl = mod.declPtr(decl_index);31195 const decl = mod.declPtr(decl_index);
31136 const decl_tv = try decl.typedValue();31196 const decl_tv = try decl.typedValue();
31197 try sema.declareDependency(.{ .decl_val = decl_index });
31137 if (decl.val.getVariable(mod) != null) return error.RuntimeLoad;31198 if (decl.val.getVariable(mod) != null) return error.RuntimeLoad;
3113831199
31139 const layout_defined = decl.ty.hasWellDefinedLayout(mod);31200 const layout_defined = decl.ty.hasWellDefinedLayout(mod);
...@@ -32387,6 +32448,8 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn...@@ -32387,6 +32448,8 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn
3238732448
32388 const decl = mod.declPtr(decl_index);32449 const decl = mod.declPtr(decl_index);
32389 const decl_tv = try decl.typedValue();32450 const decl_tv = try decl.typedValue();
32451 // TODO: if this is a `decl_ref` of a non-variable decl, only depend on decl type
32452 try sema.declareDependency(.{ .decl_val = decl_index });
32390 const ptr_ty = try sema.ptrType(.{32453 const ptr_ty = try sema.ptrType(.{
32391 .child = decl_tv.ty.toIntern(),32454 .child = decl_tv.ty.toIntern(),
32392 .flags = .{32455 .flags = .{
...@@ -35683,13 +35746,13 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp...@@ -35683,13 +35746,13 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp
35683 break :blk accumulator;35746 break :blk accumulator;
35684 };35747 };
3568535748
35686 const zir_index = struct_type.zir_index.resolve(ip);35749 const zir_index = struct_type.zir_index.unwrap().?.resolve(ip);
35687 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;35750 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
35688 assert(extended.opcode == .struct_decl);35751 assert(extended.opcode == .struct_decl);
35689 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);35752 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
3569035753
35691 if (small.has_backing_int) {35754 if (small.has_backing_int) {
35692 var extra_index: usize = extended.operand;35755 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
35693 extra_index += @intFromBool(small.has_src_node);35756 extra_index += @intFromBool(small.has_src_node);
35694 extra_index += @intFromBool(small.has_fields_len);35757 extra_index += @intFromBool(small.has_fields_len);
35695 extra_index += @intFromBool(small.has_decls_len);35758 extra_index += @intFromBool(small.has_decls_len);
...@@ -36162,10 +36225,8 @@ pub fn resolveTypeFieldsStruct(...@@ -36162,10 +36225,8 @@ pub fn resolveTypeFieldsStruct(
36162 .file_failure,36225 .file_failure,
36163 .dependency_failure,36226 .dependency_failure,
36164 .sema_failure,36227 .sema_failure,
36165 .sema_failure_retryable,
36166 => {36228 => {
36167 sema.owner_decl.analysis = .dependency_failure;36229 sema.owner_decl.analysis = .dependency_failure;
36168 sema.owner_decl.generation = mod.generation;
36169 return error.AnalysisFail;36230 return error.AnalysisFail;
36170 },36231 },
36171 else => {},36232 else => {},
...@@ -36221,10 +36282,8 @@ pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key....@@ -36221,10 +36282,8 @@ pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.
36221 .file_failure,36282 .file_failure,
36222 .dependency_failure,36283 .dependency_failure,
36223 .sema_failure,36284 .sema_failure,
36224 .sema_failure_retryable,
36225 => {36285 => {
36226 sema.owner_decl.analysis = .dependency_failure;36286 sema.owner_decl.analysis = .dependency_failure;
36227 sema.owner_decl.generation = mod.generation;
36228 return error.AnalysisFail;36287 return error.AnalysisFail;
36229 },36288 },
36230 else => {},36289 else => {},
...@@ -36404,7 +36463,7 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {...@@ -36404,7 +36463,7 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
36404 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;36463 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
36405 assert(extended.opcode == .struct_decl);36464 assert(extended.opcode == .struct_decl);
36406 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);36465 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
36407 var extra_index: usize = extended.operand;36466 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
3640836467
36409 extra_index += @intFromBool(small.has_src_node);36468 extra_index += @intFromBool(small.has_src_node);
3641036469
...@@ -36448,7 +36507,7 @@ fn semaStructFields(...@@ -36448,7 +36507,7 @@ fn semaStructFields(
36448 const decl = mod.declPtr(decl_index);36507 const decl = mod.declPtr(decl_index);
36449 const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace;36508 const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace;
36450 const zir = mod.namespacePtr(namespace_index).file_scope.zir;36509 const zir = mod.namespacePtr(namespace_index).file_scope.zir;
36451 const zir_index = struct_type.zir_index.resolve(ip);36510 const zir_index = struct_type.zir_index.unwrap().?.resolve(ip);
3645236511
36453 const fields_len, const small, var extra_index = structZirInfo(zir, zir_index);36512 const fields_len, const small, var extra_index = structZirInfo(zir, zir_index);
3645436513
...@@ -36719,7 +36778,7 @@ fn semaStructFieldInits(...@@ -36719,7 +36778,7 @@ fn semaStructFieldInits(
36719 const decl = mod.declPtr(decl_index);36778 const decl = mod.declPtr(decl_index);
36720 const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace;36779 const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace;
36721 const zir = mod.namespacePtr(namespace_index).file_scope.zir;36780 const zir = mod.namespacePtr(namespace_index).file_scope.zir;
36722 const zir_index = struct_type.zir_index.resolve(ip);36781 const zir_index = struct_type.zir_index.unwrap().?.resolve(ip);
36723 const fields_len, const small, var extra_index = structZirInfo(zir, zir_index);36782 const fields_len, const small, var extra_index = structZirInfo(zir, zir_index);
3672436783
36725 var comptime_mutable_decls = std.ArrayList(InternPool.DeclIndex).init(gpa);36784 var comptime_mutable_decls = std.ArrayList(InternPool.DeclIndex).init(gpa);
...@@ -36868,11 +36927,11 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un...@@ -36868,11 +36927,11 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
36868 const ip = &mod.intern_pool;36927 const ip = &mod.intern_pool;
36869 const decl_index = union_type.decl;36928 const decl_index = union_type.decl;
36870 const zir = mod.namespacePtr(union_type.namespace).file_scope.zir;36929 const zir = mod.namespacePtr(union_type.namespace).file_scope.zir;
36871 const zir_index = union_type.zir_index.resolve(ip);36930 const zir_index = union_type.zir_index.unwrap().?.resolve(ip);
36872 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;36931 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
36873 assert(extended.opcode == .union_decl);36932 assert(extended.opcode == .union_decl);
36874 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);36933 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
36875 var extra_index: usize = extended.operand;36934 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.UnionDecl).Struct.fields.len;
3687636935
36877 const src = LazySrcLoc.nodeOffset(0);36936 const src = LazySrcLoc.nodeOffset(0);
36878 extra_index += @intFromBool(small.has_src_node);36937 extra_index += @intFromBool(small.has_src_node);
...@@ -37312,6 +37371,7 @@ fn generateUnionTagTypeNumbered(...@@ -37312,6 +37371,7 @@ fn generateUnionTagTypeNumbered(
37312 .names = enum_field_names,37371 .names = enum_field_names,
37313 .values = enum_field_vals,37372 .values = enum_field_vals,
37314 .tag_mode = .explicit,37373 .tag_mode = .explicit,
37374 .zir_index = .none,
37315 });37375 });
3731637376
37317 new_decl.ty = Type.type;37377 new_decl.ty = Type.type;
...@@ -37362,6 +37422,7 @@ fn generateUnionTagTypeSimple(...@@ -37362,6 +37422,7 @@ fn generateUnionTagTypeSimple(
37362 .names = enum_field_names,37422 .names = enum_field_names,
37363 .values = &.{},37423 .values = &.{},
37364 .tag_mode = .auto,37424 .tag_mode = .auto,
37425 .zir_index = .none,
37365 });37426 });
3736637427
37367 const new_decl = mod.declPtr(new_decl_index);37428 const new_decl = mod.declPtr(new_decl_index);
...@@ -38876,3 +38937,14 @@ fn ptrType(sema: *Sema, info: InternPool.Key.PtrType) CompileError!Type {...@@ -38876,3 +38937,14 @@ fn ptrType(sema: *Sema, info: InternPool.Key.PtrType) CompileError!Type {
38876 }38937 }
38877 return sema.mod.ptrType(info);38938 return sema.mod.ptrType(info);
38878}38939}
38940
38941pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
38942 if (!sema.mod.comp.debug_incremental) return;
38943 const depender = InternPool.Depender.wrap(
38944 if (sema.owner_func_index != .none)
38945 .{ .func = sema.owner_func_index }
38946 else
38947 .{ .decl = sema.owner_decl_index },
38948 );
38949 try sema.mod.intern_pool.addDependency(sema.gpa, depender, dependee);
38950}
src/Zir.zig+131-3
...@@ -2497,6 +2497,7 @@ pub const Inst = struct {...@@ -2497,6 +2497,7 @@ pub const Inst = struct {
2497 /// }2497 /// }
2498 /// 2. body: Index // for each body_len2498 /// 2. body: Index // for each body_len
2499 /// 3. src_locs: SrcLocs // if body_len != 02499 /// 3. src_locs: SrcLocs // if body_len != 0
2500 /// 4. proto_hash: std.zig.SrcHash // if body_len != 0; hash of function prototype
2500 pub const Func = struct {2501 pub const Func = struct {
2501 /// If this is 0 it means a void return type.2502 /// If this is 0 it means a void return type.
2502 /// If this is 1 it means return_type is a simple Ref2503 /// If this is 1 it means return_type is a simple Ref
...@@ -2558,6 +2559,7 @@ pub const Inst = struct {...@@ -2558,6 +2559,7 @@ pub const Inst = struct {
2558 /// - each bit starting with LSB corresponds to parameter indexes2559 /// - each bit starting with LSB corresponds to parameter indexes
2559 /// 17. body: Index // for each body_len2560 /// 17. body: Index // for each body_len
2560 /// 18. src_locs: Func.SrcLocs // if body_len != 02561 /// 18. src_locs: Func.SrcLocs // if body_len != 0
2562 /// 19. proto_hash: std.zig.SrcHash // if body_len != 0; hash of function prototype
2561 pub const FuncFancy = struct {2563 pub const FuncFancy = struct {
2562 /// Points to the block that contains the param instructions for this function.2564 /// 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.2565 /// If this is a `declaration`, it refers to the declaration's value body.
...@@ -3040,6 +3042,12 @@ pub const Inst = struct {...@@ -3040,6 +3042,12 @@ pub const Inst = struct {
3040 /// init_body_inst: Inst, // for each init_body_len3042 /// init_body_inst: Inst, // for each init_body_len
3041 /// }3043 /// }
3042 pub const StructDecl = struct {3044 pub const StructDecl = struct {
3045 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
3046 // This hash contains the source of all fields, and any specified attributes (`extern`, backing type, etc).
3047 fields_hash_0: u32,
3048 fields_hash_1: u32,
3049 fields_hash_2: u32,
3050 fields_hash_3: u32,
3043 pub const Small = packed struct {3051 pub const Small = packed struct {
3044 has_src_node: bool,3052 has_src_node: bool,
3045 has_fields_len: bool,3053 has_fields_len: bool,
...@@ -3102,6 +3110,12 @@ pub const Inst = struct {...@@ -3102,6 +3110,12 @@ pub const Inst = struct {
3102 /// value: Ref, // if corresponding bit is set3110 /// value: Ref, // if corresponding bit is set
3103 /// }3111 /// }
3104 pub const EnumDecl = struct {3112 pub const EnumDecl = struct {
3113 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
3114 // This hash contains the source of all fields, and the backing type if specified.
3115 fields_hash_0: u32,
3116 fields_hash_1: u32,
3117 fields_hash_2: u32,
3118 fields_hash_3: u32,
3105 pub const Small = packed struct {3119 pub const Small = packed struct {
3106 has_src_node: bool,3120 has_src_node: bool,
3107 has_tag_type: bool,3121 has_tag_type: bool,
...@@ -3137,6 +3151,12 @@ pub const Inst = struct {...@@ -3137,6 +3151,12 @@ pub const Inst = struct {
3137 /// tag_value: Ref, // if corresponding bit is set3151 /// tag_value: Ref, // if corresponding bit is set
3138 /// }3152 /// }
3139 pub const UnionDecl = struct {3153 pub const UnionDecl = struct {
3154 // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
3155 // This hash contains the source of all fields, and any specified attributes (`extern` etc).
3156 fields_hash_0: u32,
3157 fields_hash_1: u32,
3158 fields_hash_2: u32,
3159 fields_hash_3: u32,
3140 pub const Small = packed struct {3160 pub const Small = packed struct {
3141 has_src_node: bool,3161 has_src_node: bool,
3142 has_tag_type: bool,3162 has_tag_type: bool,
...@@ -3455,7 +3475,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {...@@ -3455,7 +3475,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3455 switch (extended.opcode) {3475 switch (extended.opcode) {
3456 .struct_decl => {3476 .struct_decl => {
3457 const small: Inst.StructDecl.Small = @bitCast(extended.small);3477 const small: Inst.StructDecl.Small = @bitCast(extended.small);
3458 var extra_index: u32 = extended.operand;3478 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.StructDecl).Struct.fields.len);
3459 extra_index += @intFromBool(small.has_src_node);3479 extra_index += @intFromBool(small.has_src_node);
3460 extra_index += @intFromBool(small.has_fields_len);3480 extra_index += @intFromBool(small.has_fields_len);
3461 const decls_len = if (small.has_decls_len) decls_len: {3481 const decls_len = if (small.has_decls_len) decls_len: {
...@@ -3482,7 +3502,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {...@@ -3482,7 +3502,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3482 },3502 },
3483 .enum_decl => {3503 .enum_decl => {
3484 const small: Inst.EnumDecl.Small = @bitCast(extended.small);3504 const small: Inst.EnumDecl.Small = @bitCast(extended.small);
3485 var extra_index: u32 = extended.operand;3505 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.EnumDecl).Struct.fields.len);
3486 extra_index += @intFromBool(small.has_src_node);3506 extra_index += @intFromBool(small.has_src_node);
3487 extra_index += @intFromBool(small.has_tag_type);3507 extra_index += @intFromBool(small.has_tag_type);
3488 extra_index += @intFromBool(small.has_body_len);3508 extra_index += @intFromBool(small.has_body_len);
...@@ -3501,7 +3521,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {...@@ -3501,7 +3521,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
3501 },3521 },
3502 .union_decl => {3522 .union_decl => {
3503 const small: Inst.UnionDecl.Small = @bitCast(extended.small);3523 const small: Inst.UnionDecl.Small = @bitCast(extended.small);
3504 var extra_index: u32 = extended.operand;3524 var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.UnionDecl).Struct.fields.len);
3505 extra_index += @intFromBool(small.has_src_node);3525 extra_index += @intFromBool(small.has_src_node);
3506 extra_index += @intFromBool(small.has_tag_type);3526 extra_index += @intFromBool(small.has_tag_type);
3507 extra_index += @intFromBool(small.has_body_len);3527 extra_index += @intFromBool(small.has_body_len);
...@@ -3938,3 +3958,111 @@ pub fn getDeclaration(zir: Zir, inst: Zir.Inst.Index) struct { Inst.Declaration,...@@ -3938,3 +3958,111 @@ pub fn getDeclaration(zir: Zir, inst: Zir.Inst.Index) struct { Inst.Declaration,
3938 @intCast(extra.end),3958 @intCast(extra.end),
3939 };3959 };
3940}3960}
3961
3962pub fn getAssociatedSrcHash(zir: Zir, inst: Zir.Inst.Index) ?std.zig.SrcHash {
3963 const tag = zir.instructions.items(.tag);
3964 const data = zir.instructions.items(.data);
3965 switch (tag[@intFromEnum(inst)]) {
3966 .declaration => {
3967 const pl_node = data[@intFromEnum(inst)].pl_node;
3968 const extra = zir.extraData(Inst.Declaration, pl_node.payload_index);
3969 return @bitCast([4]u32{
3970 extra.data.src_hash_0,
3971 extra.data.src_hash_1,
3972 extra.data.src_hash_2,
3973 extra.data.src_hash_3,
3974 });
3975 },
3976 .func, .func_inferred => {
3977 const pl_node = data[@intFromEnum(inst)].pl_node;
3978 const extra = zir.extraData(Inst.Func, pl_node.payload_index);
3979 if (extra.data.body_len == 0) {
3980 // Function type or extern fn - no associated hash
3981 return null;
3982 }
3983 const extra_index = extra.end +
3984 1 +
3985 extra.data.body_len +
3986 @typeInfo(Inst.Func.SrcLocs).Struct.fields.len;
3987 return @bitCast([4]u32{
3988 zir.extra[extra_index + 0],
3989 zir.extra[extra_index + 1],
3990 zir.extra[extra_index + 2],
3991 zir.extra[extra_index + 3],
3992 });
3993 },
3994 .func_fancy => {
3995 const pl_node = data[@intFromEnum(inst)].pl_node;
3996 const extra = zir.extraData(Inst.FuncFancy, pl_node.payload_index);
3997 if (extra.data.body_len == 0) {
3998 // Function type or extern fn - no associated hash
3999 return null;
4000 }
4001 const bits = extra.data.bits;
4002 var extra_index = extra.end;
4003 extra_index += @intFromBool(bits.has_lib_name);
4004 if (bits.has_align_body) {
4005 const body_len = zir.extra[extra_index];
4006 extra_index += 1 + body_len;
4007 } else extra_index += @intFromBool(bits.has_align_ref);
4008 if (bits.has_addrspace_body) {
4009 const body_len = zir.extra[extra_index];
4010 extra_index += 1 + body_len;
4011 } else extra_index += @intFromBool(bits.has_addrspace_ref);
4012 if (bits.has_section_body) {
4013 const body_len = zir.extra[extra_index];
4014 extra_index += 1 + body_len;
4015 } else extra_index += @intFromBool(bits.has_section_ref);
4016 if (bits.has_cc_body) {
4017 const body_len = zir.extra[extra_index];
4018 extra_index += 1 + body_len;
4019 } else extra_index += @intFromBool(bits.has_cc_ref);
4020 if (bits.has_ret_ty_body) {
4021 const body_len = zir.extra[extra_index];
4022 extra_index += 1 + body_len;
4023 } else extra_index += @intFromBool(bits.has_ret_ty_ref);
4024 extra_index += @intFromBool(bits.has_any_noalias);
4025 extra_index += extra.data.body_len;
4026 extra_index += @typeInfo(Zir.Inst.Func.SrcLocs).Struct.fields.len;
4027 return @bitCast([4]u32{
4028 zir.extra[extra_index + 0],
4029 zir.extra[extra_index + 1],
4030 zir.extra[extra_index + 2],
4031 zir.extra[extra_index + 3],
4032 });
4033 },
4034 .extended => {},
4035 else => return null,
4036 }
4037 const extended = data[@intFromEnum(inst)].extended;
4038 switch (extended.opcode) {
4039 .struct_decl => {
4040 const extra = zir.extraData(Inst.StructDecl, extended.operand).data;
4041 return @bitCast([4]u32{
4042 extra.fields_hash_0,
4043 extra.fields_hash_1,
4044 extra.fields_hash_2,
4045 extra.fields_hash_3,
4046 });
4047 },
4048 .union_decl => {
4049 const extra = zir.extraData(Inst.UnionDecl, extended.operand).data;
4050 return @bitCast([4]u32{
4051 extra.fields_hash_0,
4052 extra.fields_hash_1,
4053 extra.fields_hash_2,
4054 extra.fields_hash_3,
4055 });
4056 },
4057 .enum_decl => {
4058 const extra = zir.extraData(Inst.EnumDecl, extended.operand).data;
4059 return @bitCast([4]u32{
4060 extra.fields_hash_0,
4061 extra.fields_hash_1,
4062 extra.fields_hash_2,
4063 extra.fields_hash_3,
4064 });
4065 },
4066 else => return null,
4067 }
4068}
src/main.zig+1
...@@ -3255,6 +3255,7 @@ fn buildOutputType(...@@ -3255,6 +3255,7 @@ fn buildOutputType(
3255 .cache_mode = cache_mode,3255 .cache_mode = cache_mode,
3256 .subsystem = subsystem,3256 .subsystem = subsystem,
3257 .debug_compile_errors = debug_compile_errors,3257 .debug_compile_errors = debug_compile_errors,
3258 .debug_incremental = debug_incremental,
3258 .enable_link_snapshots = enable_link_snapshots,3259 .enable_link_snapshots = enable_link_snapshots,
3259 .install_name = install_name,3260 .install_name = install_name,
3260 .entitlements = entitlements,3261 .entitlements = entitlements,
src/print_zir.zig+34-3
...@@ -1401,7 +1401,17 @@ const Writer = struct {...@@ -1401,7 +1401,17 @@ const Writer = struct {
1401 fn writeStructDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {1401 fn writeStructDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
1402 const small = @as(Zir.Inst.StructDecl.Small, @bitCast(extended.small));1402 const small = @as(Zir.Inst.StructDecl.Small, @bitCast(extended.small));
14031403
1404 var extra_index: usize = extended.operand;1404 const extra = self.code.extraData(Zir.Inst.StructDecl, extended.operand);
1405 const fields_hash: std.zig.SrcHash = @bitCast([4]u32{
1406 extra.data.fields_hash_0,
1407 extra.data.fields_hash_1,
1408 extra.data.fields_hash_2,
1409 extra.data.fields_hash_3,
1410 });
1411
1412 try stream.print("hash({}) ", .{std.fmt.fmtSliceHexLower(&fields_hash)});
1413
1414 var extra_index: usize = extra.end;
14051415
1406 const src_node: ?i32 = if (small.has_src_node) blk: {1416 const src_node: ?i32 = if (small.has_src_node) blk: {
1407 const src_node = @as(i32, @bitCast(self.code.extra[extra_index]));1417 const src_node = @as(i32, @bitCast(self.code.extra[extra_index]));
...@@ -1591,7 +1601,17 @@ const Writer = struct {...@@ -1591,7 +1601,17 @@ const Writer = struct {
1591 fn writeUnionDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {1601 fn writeUnionDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
1592 const small = @as(Zir.Inst.UnionDecl.Small, @bitCast(extended.small));1602 const small = @as(Zir.Inst.UnionDecl.Small, @bitCast(extended.small));
15931603
1594 var extra_index: usize = extended.operand;1604 const extra = self.code.extraData(Zir.Inst.UnionDecl, extended.operand);
1605 const fields_hash: std.zig.SrcHash = @bitCast([4]u32{
1606 extra.data.fields_hash_0,
1607 extra.data.fields_hash_1,
1608 extra.data.fields_hash_2,
1609 extra.data.fields_hash_3,
1610 });
1611
1612 try stream.print("hash({}) ", .{std.fmt.fmtSliceHexLower(&fields_hash)});
1613
1614 var extra_index: usize = extra.end;
15951615
1596 const src_node: ?i32 = if (small.has_src_node) blk: {1616 const src_node: ?i32 = if (small.has_src_node) blk: {
1597 const src_node = @as(i32, @bitCast(self.code.extra[extra_index]));1617 const src_node = @as(i32, @bitCast(self.code.extra[extra_index]));
...@@ -1733,7 +1753,18 @@ const Writer = struct {...@@ -1733,7 +1753,18 @@ const Writer = struct {
17331753
1734 fn writeEnumDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {1754 fn writeEnumDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
1735 const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small));1755 const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small));
1736 var extra_index: usize = extended.operand;1756
1757 const extra = self.code.extraData(Zir.Inst.EnumDecl, extended.operand);
1758 const fields_hash: std.zig.SrcHash = @bitCast([4]u32{
1759 extra.data.fields_hash_0,
1760 extra.data.fields_hash_1,
1761 extra.data.fields_hash_2,
1762 extra.data.fields_hash_3,
1763 });
1764
1765 try stream.print("hash({}) ", .{std.fmt.fmtSliceHexLower(&fields_hash)});
1766
1767 var extra_index: usize = extra.end;
17371768
1738 const src_node: ?i32 = if (small.has_src_node) blk: {1769 const src_node: ?i32 = if (small.has_src_node) blk: {
1739 const src_node = @as(i32, @bitCast(self.code.extra[extra_index]));1770 const src_node = @as(i32, @bitCast(self.code.extra[extra_index]));
src/type.zig+12
...@@ -4,6 +4,7 @@ const Value = @import("Value.zig");...@@ -4,6 +4,7 @@ const Value = @import("Value.zig");
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const Target = std.Target;5const Target = std.Target;
6const Module = @import("Module.zig");6const Module = @import("Module.zig");
7const Zcu = Module;
7const log = std.log.scoped(.Type);8const log = std.log.scoped(.Type);
8const target_util = @import("target.zig");9const target_util = @import("target.zig");
9const TypedValue = @import("TypedValue.zig");10const TypedValue = @import("TypedValue.zig");
...@@ -3228,6 +3229,17 @@ pub const Type = struct {...@@ -3228,6 +3229,17 @@ pub const Type = struct {
3228 };3229 };
3229 }3230 }
32303231
3232 pub fn typeDeclInst(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index {
3233 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
3234 inline .struct_type,
3235 .union_type,
3236 .enum_type,
3237 .opaque_type,
3238 => |info| info.zir_index.unwrap(),
3239 else => null,
3240 };
3241 }
3242
3231 pub const @"u1": Type = .{ .ip_index = .u1_type };3243 pub const @"u1": Type = .{ .ip_index = .u1_type };
3232 pub const @"u8": Type = .{ .ip_index = .u8_type };3244 pub const @"u8": Type = .{ .ip_index = .u8_type };
3233 pub const @"u16": Type = .{ .ip_index = .u16_type };3245 pub const @"u16": Type = .{ .ip_index = .u16_type };