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;
2727pub const c_builtins = @import("zig/c_builtins.zig");
2828pub const c_translation = @import("zig/c_translation.zig");
2929
30pub const SrcHasher = std.crypto.hash.Blake3;
3031pub const SrcHash = [16]u8;
3132
3233pub fn hashSrc(src: []const u8) SrcHash {
3334 var out: SrcHash = undefined;
34 std.crypto.hash.Blake3.hash(src, &out, .{});
35 SrcHasher.hash(src, &out, .{});
3536 return out;
3637}
3738
......@@ -41,7 +42,7 @@ pub fn srcHashEql(a: SrcHash, b: SrcHash) bool {
4142
4243pub fn hashName(parent_hash: SrcHash, sep: []const u8, name: []const u8) SrcHash {
4344 var out: SrcHash = undefined;
44 var hasher = std.crypto.hash.Blake3.init(.{});
45 var hasher = SrcHasher.init(.{});
4546 hasher.update(&parent_hash);
4647 hasher.update(sep);
4748 hasher.update(name);
src/AstGen.zig+93-16
......@@ -4815,6 +4815,7 @@ fn structDeclInner(
48154815 .any_comptime_fields = false,
48164816 .any_default_inits = false,
48174817 .any_aligned_fields = false,
4818 .fields_hash = std.zig.hashSrc(@tagName(layout)),
48184819 });
48194820 return decl_inst.toRef();
48204821 }
......@@ -4936,6 +4937,12 @@ fn structDeclInner(
49364937 }
49374938 };
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
49394946 var sfba = std.heap.stackFallback(256, astgen.arena);
49404947 const sfba_allocator = sfba.get();
49414948
......@@ -4956,6 +4963,8 @@ fn structDeclInner(
49564963 .field => |field| field,
49574964 };
49584965
4966 fields_hasher.update(tree.getNodeSource(member_node));
4967
49594968 if (!is_tuple) {
49604969 const field_name = try astgen.identAsString(member.ast.main_token);
49614970
......@@ -5083,6 +5092,9 @@ fn structDeclInner(
50835092 return error.AnalysisFail;
50845093 }
50855094
5095 var fields_hash: std.zig.SrcHash = undefined;
5096 fields_hasher.final(&fields_hash);
5097
50865098 try gz.setStruct(decl_inst, .{
50875099 .src_node = node,
50885100 .layout = layout,
......@@ -5096,6 +5108,7 @@ fn structDeclInner(
50965108 .any_comptime_fields = any_comptime_fields,
50975109 .any_default_inits = any_default_inits,
50985110 .any_aligned_fields = any_aligned_fields,
5111 .fields_hash = fields_hash,
50995112 });
51005113
51015114 wip_members.finishBits(bits_per_field);
......@@ -5174,6 +5187,13 @@ fn unionDeclInner(
51745187 var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size);
51755188 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
51775197 var sfba = std.heap.stackFallback(256, astgen.arena);
51785198 const sfba_allocator = sfba.get();
51795199
......@@ -5188,6 +5208,7 @@ fn unionDeclInner(
51885208 .decl => continue,
51895209 .field => |field| field,
51905210 };
5211 fields_hasher.update(astgen.tree.getNodeSource(member_node));
51915212 member.convertToNonTupleLike(astgen.tree.nodes);
51925213 if (member.ast.tuple_like) {
51935214 return astgen.failTok(member.ast.main_token, "union field missing name", .{});
......@@ -5289,6 +5310,9 @@ fn unionDeclInner(
52895310 return error.AnalysisFail;
52905311 }
52915312
5313 var fields_hash: std.zig.SrcHash = undefined;
5314 fields_hasher.final(&fields_hash);
5315
52925316 if (!block_scope.isEmpty()) {
52935317 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
52945318 }
......@@ -5305,6 +5329,7 @@ fn unionDeclInner(
53055329 .decls_len = decl_count,
53065330 .auto_enum_tag = auto_enum_tok != null,
53075331 .any_aligned_fields = any_aligned_fields,
5332 .fields_hash = fields_hash,
53085333 });
53095334
53105335 wip_members.finishBits(bits_per_field);
......@@ -5498,6 +5523,12 @@ fn containerDecl(
54985523 var wip_members = try WipMembers.init(gpa, &astgen.scratch, @intCast(counts.decls), @intCast(counts.total_fields), bits_per_field, max_field_size);
54995524 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
55015532 var sfba = std.heap.stackFallback(256, astgen.arena);
55025533 const sfba_allocator = sfba.get();
55035534
......@@ -5510,6 +5541,7 @@ fn containerDecl(
55105541 for (container_decl.ast.members) |member_node| {
55115542 if (member_node == counts.nonexhaustive_node)
55125543 continue;
5544 fields_hasher.update(tree.getNodeSource(member_node));
55135545 namespace.base.tag = .namespace;
55145546 var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) {
55155547 .decl => continue,
......@@ -5590,6 +5622,9 @@ fn containerDecl(
55905622 _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value);
55915623 }
55925624
5625 var fields_hash: std.zig.SrcHash = undefined;
5626 fields_hasher.final(&fields_hash);
5627
55935628 const body = block_scope.instructionsSlice();
55945629 const body_len = astgen.countBodyLenAfterFixups(body);
55955630
......@@ -5600,6 +5635,7 @@ fn containerDecl(
56005635 .body_len = body_len,
56015636 .fields_len = @intCast(counts.total_fields),
56025637 .decls_len = @intCast(counts.decls),
5638 .fields_hash = fields_hash,
56035639 });
56045640
56055641 wip_members.finishBits(bits_per_field);
......@@ -11900,8 +11936,8 @@ const GenZir = struct {
1190011936
1190111937 var body: []Zir.Inst.Index = &[0]Zir.Inst.Index{};
1190211938 var ret_body: []Zir.Inst.Index = &[0]Zir.Inst.Index{};
11903 var src_locs_buffer: [3]u32 = undefined;
11904 var src_locs: []u32 = src_locs_buffer[0..0];
11939 var src_locs_and_hash_buffer: [7]u32 = undefined;
11940 var src_locs_and_hash: []u32 = src_locs_and_hash_buffer[0..0];
1190511941 if (args.body_gz) |body_gz| {
1190611942 const tree = astgen.tree;
1190711943 const node_tags = tree.nodes.items(.tag);
......@@ -11916,10 +11952,27 @@ const GenZir = struct {
1191611952 const rbrace_column: u32 = @intCast(astgen.source_column);
1191711953
1191811954 const columns = args.lbrace_column | (rbrace_column << 16);
11919 src_locs_buffer[0] = args.lbrace_line;
11920 src_locs_buffer[1] = rbrace_line;
11921 src_locs_buffer[2] = columns;
11922 src_locs = &src_locs_buffer;
11955
11956 const proto_hash: std.zig.SrcHash = switch (node_tags[fn_decl]) {
11957 .fn_decl => sig_hash: {
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
1192411977 body = body_gz.instructionsSlice();
1192511978 if (args.ret_gz) |ret_gz|
......@@ -11953,7 +12006,7 @@ const GenZir = struct {
1195312006 fancyFnExprExtraLen(astgen, section_body, args.section_ref) +
1195412007 fancyFnExprExtraLen(astgen, cc_body, args.cc_ref) +
1195512008 fancyFnExprExtraLen(astgen, ret_body, ret_ref) +
11956 body_len + src_locs.len +
12009 body_len + src_locs_and_hash.len +
1195712010 @intFromBool(args.lib_name != .empty) +
1195812011 @intFromBool(args.noalias_bits != 0),
1195912012 );
......@@ -12040,7 +12093,7 @@ const GenZir = struct {
1204012093 }
1204112094
1204212095 astgen.appendBodyWithFixups(body);
12043 astgen.extra.appendSliceAssumeCapacity(src_locs);
12096 astgen.extra.appendSliceAssumeCapacity(src_locs_and_hash);
1204412097
1204512098 // Order is important when unstacking.
1204612099 if (args.body_gz) |body_gz| body_gz.unstack();
......@@ -12068,7 +12121,7 @@ const GenZir = struct {
1206812121 gpa,
1206912122 @typeInfo(Zir.Inst.Func).Struct.fields.len + 1 +
1207012123 fancyFnExprExtraLen(astgen, ret_body, ret_ref) +
12071 body_len + src_locs.len,
12124 body_len + src_locs_and_hash.len,
1207212125 );
1207312126
1207412127 const ret_body_len = if (ret_body.len != 0)
......@@ -12092,7 +12145,7 @@ const GenZir = struct {
1209212145 astgen.extra.appendAssumeCapacity(@intFromEnum(ret_ref));
1209312146 }
1209412147 astgen.appendBodyWithFixups(body);
12095 astgen.extra.appendSliceAssumeCapacity(src_locs);
12148 astgen.extra.appendSliceAssumeCapacity(src_locs_and_hash);
1209612149
1209712150 // Order is important when unstacking.
1209812151 if (args.body_gz) |body_gz| body_gz.unstack();
......@@ -12853,12 +12906,20 @@ const GenZir = struct {
1285312906 any_comptime_fields: bool,
1285412907 any_default_inits: bool,
1285512908 any_aligned_fields: bool,
12909 fields_hash: std.zig.SrcHash,
1285612910 }) !void {
1285712911 const astgen = gz.astgen;
1285812912 const gpa = astgen.gpa;
1285912913
12860 try astgen.extra.ensureUnusedCapacity(gpa, 6);
12861 const payload_index: u32 = @intCast(astgen.extra.items.len);
12914 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
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
1286312924 if (args.src_node != 0) {
1286412925 const node_offset = gz.nodeIndexToRelative(args.src_node);
......@@ -12908,12 +12969,20 @@ const GenZir = struct {
1290812969 layout: std.builtin.Type.ContainerLayout,
1290912970 auto_enum_tag: bool,
1291012971 any_aligned_fields: bool,
12972 fields_hash: std.zig.SrcHash,
1291112973 }) !void {
1291212974 const astgen = gz.astgen;
1291312975 const gpa = astgen.gpa;
1291412976
12915 try astgen.extra.ensureUnusedCapacity(gpa, 5);
12916 const payload_index: u32 = @intCast(astgen.extra.items.len);
12977 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
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
1291812987 if (args.src_node != 0) {
1291912988 const node_offset = gz.nodeIndexToRelative(args.src_node);
......@@ -12958,12 +13027,20 @@ const GenZir = struct {
1295813027 fields_len: u32,
1295913028 decls_len: u32,
1296013029 nonexhaustive: bool,
13030 fields_hash: std.zig.SrcHash,
1296113031 }) !void {
1296213032 const astgen = gz.astgen;
1296313033 const gpa = astgen.gpa;
1296413034
12965 try astgen.extra.ensureUnusedCapacity(gpa, 5);
12966 const payload_index: u32 = @intCast(astgen.extra.items.len);
13035 const fields_hash_arr: [4]u32 = @bitCast(args.fields_hash);
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
1296813045 if (args.src_node != 0) {
1296913046 const node_offset = gz.nodeIndexToRelative(args.src_node);
src/Autodoc.zig+3-3
......@@ -3497,7 +3497,7 @@ fn walkInstruction(
34973497 };
34983498
34993499 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
35023502 const src_node: ?i32 = if (small.has_src_node) blk: {
35033503 const src_node = @as(i32, @bitCast(file.zir.extra[extra_index]));
......@@ -3627,7 +3627,7 @@ fn walkInstruction(
36273627 };
36283628
36293629 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
36323632 const src_node: ?i32 = if (small.has_src_node) blk: {
36333633 const src_node = @as(i32, @bitCast(file.zir.extra[extra_index]));
......@@ -3778,7 +3778,7 @@ fn walkInstruction(
37783778 };
37793779
37803780 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
37833783 const src_node: ?i32 = if (small.has_src_node) blk: {
37843784 const src_node = @as(i32, @bitCast(file.zir.extra[extra_index]));
src/Compilation.zig+48-13
......@@ -156,6 +156,7 @@ time_report: bool,
156156stack_report: bool,
157157debug_compiler_runtime_libs: bool,
158158debug_compile_errors: bool,
159debug_incremental: bool,
159160job_queued_compiler_rt_lib: bool = false,
160161job_queued_compiler_rt_obj: bool = false,
161162job_queued_update_builtin_zig: bool,
......@@ -1079,6 +1080,7 @@ pub const CreateOptions = struct {
10791080 verbose_llvm_cpu_features: bool = false,
10801081 debug_compiler_runtime_libs: bool = false,
10811082 debug_compile_errors: bool = false,
1083 debug_incremental: bool = false,
10821084 /// Normally when you create a `Compilation`, Zig will automatically build
10831085 /// and link in required dependencies, such as compiler-rt and libc. When
10841086 /// 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
15081510 .test_name_prefix = options.test_name_prefix,
15091511 .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs,
15101512 .debug_compile_errors = options.debug_compile_errors,
1513 .debug_incremental = options.debug_incremental,
15111514 .libcxx_abi_version = options.libcxx_abi_version,
15121515 .root_name = root_name,
15131516 .sysroot = sysroot,
......@@ -2141,7 +2144,6 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void
21412144
21422145 if (comp.module) |module| {
21432146 module.compile_log_text.shrinkAndFree(gpa, 0);
2144 module.generation += 1;
21452147
21462148 // Make sure std.zig is inside the import_table. We unconditionally need
21472149 // it for start.zig.
......@@ -2807,6 +2809,13 @@ const Header = extern struct {
28072809 limbs_len: u32,
28082810 string_bytes_len: u32,
28092811 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,
28102819 },
28112820};
28122821
......@@ -2814,7 +2823,7 @@ const Header = extern struct {
28142823/// saved, such as the target and most CLI flags. A cache hit will only occur
28152824/// when subsequent compiler invocations use the same set of flags.
28162825pub 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;
28182827 var bufs_len: usize = 0;
28192828
28202829 const lf = comp.bin_file orelse return;
......@@ -2828,6 +2837,13 @@ pub fn saveState(comp: *Compilation) !void {
28282837 .limbs_len = @intCast(ip.limbs.items.len),
28292838 .string_bytes_len = @intCast(ip.string_bytes.items.len),
28302839 .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),
28312847 },
28322848 };
28332849 addBuf(&bufs_list, &bufs_len, mem.asBytes(&header));
......@@ -2838,6 +2854,20 @@ pub fn saveState(comp: *Compilation) !void {
28382854 addBuf(&bufs_list, &bufs_len, ip.string_bytes.items);
28392855 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
28412871 // TODO: compilation errors
28422872 // TODO: files
28432873 // TODO: namespaces
......@@ -3463,9 +3493,7 @@ pub fn performAllTheWork(
34633493
34643494 if (comp.module) |mod| {
34653495 try reportMultiModuleErrors(mod);
3466 }
3467
3468 if (comp.module) |mod| {
3496 try mod.flushRetryableFailures();
34693497 mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
34703498 mod.sema_prog_node.activate();
34713499 }
......@@ -3486,6 +3514,17 @@ pub fn performAllTheWork(
34863514 try processOneJob(comp, work_item, main_progress_node);
34873515 continue;
34883516 }
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 }
34893528 break;
34903529 }
34913530
......@@ -3509,17 +3548,14 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
35093548 switch (decl.analysis) {
35103549 .unreferenced => unreachable,
35113550 .in_progress => unreachable,
3512 .outdated => unreachable,
35133551
35143552 .file_failure,
35153553 .sema_failure,
3516 .liveness_failure,
35173554 .codegen_failure,
35183555 .dependency_failure,
3519 .sema_failure_retryable,
35203556 => return,
35213557
3522 .complete, .codegen_failure_retryable => {
3558 .complete => {
35233559 const named_frame = tracy.namedFrame("codegen_decl");
35243560 defer named_frame.end();
35253561
......@@ -3554,17 +3590,15 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
35543590 switch (decl.analysis) {
35553591 .unreferenced => unreachable,
35563592 .in_progress => unreachable,
3557 .outdated => unreachable,
35583593
35593594 .file_failure,
35603595 .sema_failure,
35613596 .dependency_failure,
3562 .sema_failure_retryable,
35633597 => return,
35643598
35653599 // emit-h only requires semantic analysis of the Decl to be complete,
35663600 // it does not depend on machine code generation to succeed.
3567 .liveness_failure, .codegen_failure, .codegen_failure_retryable, .complete => {
3601 .codegen_failure, .complete => {
35683602 const named_frame = tracy.namedFrame("emit_h_decl");
35693603 defer named_frame.end();
35703604
......@@ -3636,7 +3670,8 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
36363670 "unable to update line number: {s}",
36373671 .{@errorName(err)},
36383672 ));
3639 decl.analysis = .codegen_failure_retryable;
3673 decl.analysis = .codegen_failure;
3674 try module.retryable_failures.append(gpa, InternPool.Depender.wrap(.{ .decl = decl_index }));
36403675 };
36413676 },
36423677 .analyze_mod => |pkg| {
src/InternPool.zig+283-16
......@@ -58,6 +58,38 @@ string_table: std.HashMapUnmanaged(
5858/// persists across incremental updates.
5959tracked_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
6193pub const TrackedInst = extern struct {
6294 path_digest: Cache.BinDigest,
6395 inst: Zir.Inst.Index,
......@@ -70,6 +102,19 @@ pub const TrackedInst = extern struct {
70102 pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) Zir.Inst.Index {
71103 return ip.tracked_insts.keys()[@intFromEnum(i)].inst;
72104 }
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 };
73118 };
74119};
75120
......@@ -82,6 +127,202 @@ pub fn trackZir(ip: *InternPool, gpa: Allocator, file: *Module.File, inst: Zir.I
82127 return @enumFromInt(gop.index);
83128}
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
85326const FieldMap = std.ArrayHashMapUnmanaged(void, void, std.array_hash_map.AutoContext(void), false);
86327
87328const builtin = @import("builtin");
......@@ -428,6 +669,7 @@ pub const Key = union(enum) {
428669 decl: DeclIndex,
429670 /// Represents the declarations inside this opaque.
430671 namespace: NamespaceIndex,
672 zir_index: TrackedInst.Index.Optional,
431673 };
432674
433675 /// Although packed structs and non-packed structs are encoded differently,
......@@ -440,7 +682,7 @@ pub const Key = union(enum) {
440682 /// `none` when the struct has no declarations.
441683 namespace: OptionalNamespaceIndex,
442684 /// Index of the struct_decl ZIR instruction.
443 zir_index: TrackedInst.Index,
685 zir_index: TrackedInst.Index.Optional,
444686 layout: std.builtin.Type.ContainerLayout,
445687 field_names: NullTerminatedString.Slice,
446688 field_types: Index.Slice,
......@@ -684,7 +926,7 @@ pub const Key = union(enum) {
684926 }
685927
686928 /// 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 {
688930 assert(s.layout != .Packed);
689931 const field_index = std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?;
690932 ip.extra.items[s.extra_index + field_index] = @intFromEnum(new_zir_index);
......@@ -800,7 +1042,7 @@ pub const Key = union(enum) {
8001042 flags: Tag.TypeUnion.Flags,
8011043 /// The enum that provides the list of field names and values.
8021044 enum_tag_ty: Index,
803 zir_index: TrackedInst.Index,
1045 zir_index: TrackedInst.Index.Optional,
8041046
8051047 /// The returned pointer expires with any addition to the `InternPool`.
8061048 pub fn flagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeUnion.Flags {
......@@ -889,6 +1131,7 @@ pub const Key = union(enum) {
8891131 /// This is ignored by `get` but will be provided by `indexToKey` when
8901132 /// a value map exists.
8911133 values_map: OptionalMapIndex = .none,
1134 zir_index: TrackedInst.Index.Optional,
8921135
8931136 pub const TagMode = enum {
8941137 /// The integer tag type was auto-numbered by zig.
......@@ -953,6 +1196,7 @@ pub const Key = union(enum) {
9531196 tag_mode: EnumType.TagMode,
9541197 /// This may be updated via `setTagType` later.
9551198 tag_ty: Index = .none,
1199 zir_index: TrackedInst.Index.Optional,
9561200
9571201 pub fn toEnumType(self: @This()) EnumType {
9581202 return .{
......@@ -962,6 +1206,7 @@ pub const Key = union(enum) {
9621206 .tag_mode = self.tag_mode,
9631207 .names = .{ .start = 0, .len = 0 },
9641208 .values = .{ .start = 0, .len = 0 },
1209 .zir_index = self.zir_index,
9651210 };
9661211 }
9671212
......@@ -1909,7 +2154,7 @@ pub const UnionType = struct {
19092154 /// If this slice has length 0 it means all elements are `none`.
19102155 field_aligns: Alignment.Slice,
19112156 /// Index of the union_decl ZIR instruction.
1912 zir_index: TrackedInst.Index,
2157 zir_index: TrackedInst.Index.Optional,
19132158 /// Index into extra array of the `flags` field.
19142159 flags_index: u32,
19152160 /// Copied from `enum_tag_ty`.
......@@ -2003,10 +2248,10 @@ pub const UnionType = struct {
20032248 }
20042249
20052250 /// 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 {
20072252 const flags_field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;
20082253 const zir_index_field_index = std.meta.fieldIndex(Tag.TypeUnion, "zir_index").?;
2009 const ptr: *TrackedInst.Index =
2254 const ptr: *TrackedInst.Index.Optional =
20102255 @ptrCast(&ip.extra.items[self.flags_index - flags_field_index + zir_index_field_index]);
20112256 ptr.* = new_zir_index;
20122257 }
......@@ -3099,7 +3344,7 @@ pub const Tag = enum(u8) {
30993344 namespace: NamespaceIndex,
31003345 /// The enum that provides the list of field names and values.
31013346 tag_ty: Index,
3102 zir_index: TrackedInst.Index,
3347 zir_index: TrackedInst.Index.Optional,
31033348
31043349 pub const Flags = packed struct(u32) {
31053350 runtime_tag: UnionType.RuntimeTag,
......@@ -3121,7 +3366,7 @@ pub const Tag = enum(u8) {
31213366 /// 2. init: Index for each fields_len // if tag is type_struct_packed_inits
31223367 pub const TypeStructPacked = struct {
31233368 decl: DeclIndex,
3124 zir_index: TrackedInst.Index,
3369 zir_index: TrackedInst.Index.Optional,
31253370 fields_len: u32,
31263371 namespace: OptionalNamespaceIndex,
31273372 backing_int_ty: Index,
......@@ -3168,7 +3413,7 @@ pub const Tag = enum(u8) {
31683413 /// 7. field_offset: u32 // for each field in declared order, undef until layout_resolved
31693414 pub const TypeStruct = struct {
31703415 decl: DeclIndex,
3171 zir_index: TrackedInst.Index,
3416 zir_index: TrackedInst.Index.Optional,
31723417 fields_len: u32,
31733418 flags: Flags,
31743419 size: u32,
......@@ -3238,6 +3483,11 @@ pub const FuncAnalysis = packed struct(u32) {
32383483 /// This function might be OK but it depends on another Decl which did not
32393484 /// successfully complete semantic analysis.
32403485 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.
32413491 success,
32423492 };
32433493};
......@@ -3523,6 +3773,7 @@ pub const EnumExplicit = struct {
35233773 /// If this is `none`, it means the trailing tag values are absent because
35243774 /// they are auto-numbered.
35253775 values_map: OptionalMapIndex,
3776 zir_index: TrackedInst.Index.Optional,
35263777};
35273778
35283779/// Trailing:
......@@ -3538,6 +3789,7 @@ pub const EnumAuto = struct {
35383789 fields_len: u32,
35393790 /// Maps field names to declaration index.
35403791 names_map: MapIndex,
3792 zir_index: TrackedInst.Index.Optional,
35413793};
35423794
35433795pub const PackedU64 = packed struct(u64) {
......@@ -3759,6 +4011,16 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
37594011
37604012 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
37624024 ip.* = undefined;
37634025}
37644026
......@@ -3885,6 +4147,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
38854147 .tag_mode = .auto,
38864148 .names_map = enum_auto.data.names_map.toOptional(),
38874149 .values_map = .none,
4150 .zir_index = enum_auto.data.zir_index,
38884151 } };
38894152 },
38904153 .type_enum_explicit => ip.indexToKeyEnum(data, .explicit),
......@@ -4493,6 +4756,7 @@ fn indexToKeyEnum(ip: *const InternPool, data: u32, tag_mode: Key.EnumType.TagMo
44934756 .tag_mode = tag_mode,
44944757 .names_map = enum_explicit.data.names_map.toOptional(),
44954758 .values_map = enum_explicit.data.values_map,
4759 .zir_index = enum_explicit.data.zir_index,
44964760 } };
44974761}
44984762
......@@ -5329,7 +5593,7 @@ pub const UnionTypeInit = struct {
53295593 flags: Tag.TypeUnion.Flags,
53305594 decl: DeclIndex,
53315595 namespace: NamespaceIndex,
5332 zir_index: TrackedInst.Index,
5596 zir_index: TrackedInst.Index.Optional,
53335597 fields_len: u32,
53345598 enum_tag_ty: Index,
53355599 /// May have length 0 which leaves the values unset until later.
......@@ -5401,7 +5665,7 @@ pub const StructTypeInit = struct {
54015665 decl: DeclIndex,
54025666 namespace: OptionalNamespaceIndex,
54035667 layout: std.builtin.Type.ContainerLayout,
5404 zir_index: TrackedInst.Index,
5668 zir_index: TrackedInst.Index.Optional,
54055669 fields_len: u32,
54065670 known_non_opv: bool,
54075671 requires_comptime: RequiresComptime,
......@@ -5923,7 +6187,6 @@ pub const GetFuncInstanceKey = struct {
59236187 is_noinline: bool,
59246188 generic_owner: Index,
59256189 inferred_error_set: bool,
5926 generation: u32,
59276190};
59286191
59296192pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey) Allocator.Error!Index {
......@@ -5990,7 +6253,6 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey)
59906253 generic_owner,
59916254 func_index,
59926255 func_extra_index,
5993 arg.generation,
59946256 func_ty,
59956257 arg.section,
59966258 );
......@@ -6122,7 +6384,6 @@ pub fn getFuncInstanceIes(
61226384 generic_owner,
61236385 func_index,
61246386 func_extra_index,
6125 arg.generation,
61266387 func_ty,
61276388 arg.section,
61286389 );
......@@ -6134,7 +6395,6 @@ fn finishFuncInstance(
61346395 generic_owner: Index,
61356396 func_index: Index,
61366397 func_extra_index: u32,
6137 generation: u32,
61386398 func_ty: Index,
61396399 section: OptionalNullTerminatedString,
61406400) Allocator.Error!Index {
......@@ -6154,7 +6414,6 @@ fn finishFuncInstance(
61546414 .analysis = .complete,
61556415 .zir_decl_index = fn_owner_decl.zir_decl_index,
61566416 .src_scope = fn_owner_decl.src_scope,
6157 .generation = generation,
61586417 .is_pub = fn_owner_decl.is_pub,
61596418 .is_exported = fn_owner_decl.is_exported,
61606419 .alive = true,
......@@ -6264,6 +6523,7 @@ fn getIncompleteEnumAuto(
62646523 .int_tag_type = int_tag_type,
62656524 .names_map = names_map,
62666525 .fields_len = enum_type.fields_len,
6526 .zir_index = enum_type.zir_index,
62676527 });
62686528
62696529 ip.items.appendAssumeCapacity(.{
......@@ -6314,6 +6574,7 @@ fn getIncompleteEnumExplicit(
63146574 .fields_len = enum_type.fields_len,
63156575 .names_map = names_map,
63166576 .values_map = values_map,
6577 .zir_index = enum_type.zir_index,
63176578 });
63186579
63196580 ip.items.appendAssumeCapacity(.{
......@@ -6339,6 +6600,7 @@ pub const GetEnumInit = struct {
63396600 names: []const NullTerminatedString,
63406601 values: []const Index,
63416602 tag_mode: Key.EnumType.TagMode,
6603 zir_index: TrackedInst.Index.Optional,
63426604};
63436605
63446606pub 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
63556617 .tag_mode = undefined,
63566618 .names_map = undefined,
63576619 .values_map = undefined,
6620 .zir_index = undefined,
63586621 },
63596622 }, adapter);
63606623 if (gop.found_existing) return @enumFromInt(gop.index);
......@@ -6380,6 +6643,7 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro
63806643 .int_tag_type = ini.tag_ty,
63816644 .names_map = names_map,
63826645 .fields_len = fields_len,
6646 .zir_index = ini.zir_index,
63836647 }),
63846648 });
63856649 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));
......@@ -6416,6 +6680,7 @@ pub fn finishGetEnum(
64166680 .fields_len = fields_len,
64176681 .names_map = names_map,
64186682 .values_map = values_map,
6683 .zir_index = ini.zir_index,
64196684 }),
64206685 });
64216686 ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names));
......@@ -6507,6 +6772,7 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 {
65076772 OptionalNullTerminatedString,
65086773 Tag.TypePointer.VectorIndex,
65096774 TrackedInst.Index,
6775 TrackedInst.Index.Optional,
65106776 => @intFromEnum(@field(extra, field.name)),
65116777
65126778 u32,
......@@ -6583,6 +6849,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct
65836849 OptionalNullTerminatedString,
65846850 Tag.TypePointer.VectorIndex,
65856851 TrackedInst.Index,
6852 TrackedInst.Index.Optional,
65866853 => @enumFromInt(int32),
65876854
65886855 u32,
src/Module.zig+606-222
......@@ -144,10 +144,26 @@ global_error_set: GlobalErrorSet = .{},
144144/// Maximum amount of distinct error values, set by --error-limit
145145error_limit: ErrorInt,
146146
147/// Incrementing integer used to compare against the corresponding Decl
148/// field to determine whether a Decl's status applies to an ongoing update, or a
149/// previous analysis.
150generation: u32 = 0,
147/// Value is the number of PO or outdated Decls which this Depender depends on.
148potentially_outdated: std.AutoArrayHashMapUnmanaged(InternPool.Depender, u32) = .{},
149/// Value is the number of PO or outdated Decls which this Depender depends on.
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
152168stage1_flags: packed struct {
153169 have_winmain: bool = false,
......@@ -364,21 +380,14 @@ pub const Decl = struct {
364380 alignment: Alignment,
365381 /// Populated when `has_tv`.
366382 @"addrspace": std.builtin.AddressSpace,
367 /// The direct parent namespace of the Decl.
368 /// Reference to externally owned memory.
369 /// In the case of the Decl corresponding to a file, this is
370 /// the namespace of the struct, since there is no parent.
383 /// The direct parent namespace of the Decl. In the case of the Decl
384 /// corresponding to a file, this is the namespace of the struct, since
385 /// there is no parent.
371386 src_namespace: Namespace.Index,
372387
373 /// The scope which lexically contains this decl. A decl must depend
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.
388 /// The scope which lexically contains this decl.
376389 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,
382391 /// The AST node index of this declaration.
383392 /// Must be recomputed when the corresponding source file is modified.
384393 src_node: Ast.Node.Index,
......@@ -404,31 +413,20 @@ pub const Decl = struct {
404413 /// The file corresponding to this Decl had a parse error or ZIR error.
405414 /// There will be a corresponding ErrorMsg in Module.failed_files.
406415 file_failure,
407 /// This Decl might be OK but it depends on another one which did not successfully complete
408 /// semantic analysis.
416 /// This Decl might be OK but it depends on another one which did not
417 /// successfully complete semantic analysis.
409418 dependency_failure,
410419 /// Semantic analysis failure.
411420 /// There will be a corresponding ErrorMsg in Module.failed_decls.
412421 sema_failure,
413422 /// 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.
420423 codegen_failure,
421 /// There will be a corresponding ErrorMsg in Module.failed_decls.
422 /// This indicates the failure was something like running out of disk space,
423 /// and attempting codegen again may succeed.
424 codegen_failure_retryable,
425 /// Everything is done. During an update, this Decl may be out of date, depending
426 /// on its dependencies. The `generation` field can be used to determine if this
427 /// completion status occurred before or after a given update.
424 /// Sematic analysis and constant value codegen of this Decl has
425 /// succeeded. However, the Decl may be outdated due to an in-progress
426 /// update. Note that for a function, this does not mean codegen of the
427 /// function body succeded: that state is indicated by the function's
428 /// `analysis` field.
428429 complete,
429 /// A Module update is in progress, and this Decl has been flagged as being known
430 /// to require re-analysis.
431 outdated,
432430 },
433431 /// Whether `typed_value`, `align`, `linksection` and `addrspace` are populated.
434432 has_tv: bool,
......@@ -680,14 +678,6 @@ pub const Decl = struct {
680678 return mod.namespacePtr(decl.src_namespace).file_scope;
681679 }
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
691681 pub fn getExternDecl(decl: Decl, mod: *Module) OptionalIndex {
692682 assert(decl.has_tv);
693683 return switch (mod.intern_pool.indexToKey(decl.val.toIntern())) {
......@@ -734,8 +724,7 @@ pub const Namespace = struct {
734724 file_scope: *File,
735725 /// Will be a struct, enum, union, or opaque.
736726 ty: Type,
737 /// Direct children of the namespace. Used during an update to detect
738 /// which decls have been added/removed from source.
727 /// Direct children of the namespace.
739728 /// Declaration order is preserved via entry order.
740729 /// These are only declarations named directly by the AST; anonymous
741730 /// declarations are not stored here.
......@@ -838,14 +827,6 @@ pub const File = struct {
838827 /// undefined until `zir_loaded == true`.
839828 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
849830 /// The most recent successful ZIR for this file, with no errors.
850831 /// This is only populated when a previously successful ZIR
851832 /// newly introduces compile errors during an update. When ZIR is
......@@ -898,8 +879,6 @@ pub const File = struct {
898879 gpa.free(file.sub_file_path);
899880 file.unload(gpa);
900881 }
901 file.deleted_decls.deinit(gpa);
902 file.outdated_decls.deinit(gpa);
903882 file.references.deinit(gpa);
904883 if (file.root_decl.unwrap()) |root_decl| {
905884 mod.destroyDecl(root_decl);
......@@ -2498,6 +2477,12 @@ pub fn deinit(zcu: *Zcu) void {
24982477
24992478 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
25012486 zcu.test_functions.deinit(gpa);
25022487
25032488 for (zcu.global_assembly.values()) |s| {
......@@ -2856,27 +2841,20 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
28562841 }
28572842
28582843 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.
28672844 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.
28702845 // No need to keep previous ZIR.
28712846 prev_zir.deinit(gpa);
28722847 gpa.destroy(prev_zir);
28732848 file.prev_zir = null;
2874 } else if (file.root_decl.unwrap()) |root_decl| {
2875 // This is an update, but it is the first time the File has succeeded
2876 // ZIR. We must mark it outdated since we have already tried to
2877 // semantically analyze it.
2878 try file.outdated_decls.resize(gpa, 1);
2879 file.outdated_decls.items[0] = root_decl;
2849 }
2850
2851 if (file.root_decl.unwrap()) |root_decl| {
2852 // The root of this file must be re-analyzed, since the file has changed.
2853 comp.mutex.lock();
2854 defer comp.mutex.unlock();
2855
2856 log.debug("outdated root Decl: {}", .{root_decl});
2857 try mod.outdated_file_root.put(gpa, root_decl, {});
28802858 }
28812859}
28822860
......@@ -2950,25 +2928,347 @@ fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.File)
29502928 return zir;
29512929}
29522930
2931/// This is called from the AstGen thread pool, so must acquire
2932/// the Compilation mutex when acting on shared state.
29532933fn updateZirRefs(zcu: *Module, file: *File, old_zir: Zir) !void {
29542934 const gpa = zcu.gpa;
2935 const new_zir = file.zir;
29552936
29562937 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};
29572938 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
29612945 // TODO: this should be done after all AstGen workers complete, to avoid
29622946 // 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);
29642949 if (!std.mem.eql(u8, &ti.path_digest, &file.path_digest)) continue;
2950 const old_inst = ti.inst;
29652951 ti.inst = inst_map.get(ti.inst) orelse {
2966 // TODO: invalidate this `TrackedInst` via the dependency mechanism
2952 // 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 });
29672957 continue;
29682958 };
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 }
29693047 }
29703048}
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
29723272pub fn mapOldZirToNew(
29733273 gpa: Allocator,
29743274 old_zir: Zir,
......@@ -3096,7 +3396,7 @@ pub fn mapOldZirToNew(
30963396 }
30973397}
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.
31003400/// However the resolution status of the Type may not be fully resolved.
31013401/// For example an inferred error set is not resolved until after `analyzeFnBody`.
31023402/// is called.
......@@ -3106,40 +3406,57 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
31063406
31073407 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) {
31103428 .in_progress => unreachable,
31113429
3112 .file_failure,
3430 .file_failure => return error.AnalysisFail,
3431
31133432 .sema_failure,
3114 .sema_failure_retryable,
3115 .liveness_failure,
3116 .codegen_failure,
31173433 .dependency_failure,
3118 .codegen_failure_retryable,
3119 => return error.AnalysisFail,
3120
3121 .complete => return,
3434 .codegen_failure,
3435 => if (!was_outdated) return error.AnalysisFail,
31223436
3123 .outdated => blk: {
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);
3437 .complete => if (!was_outdated) return,
31283438
3129 break :blk true;
3130 },
3439 .unreferenced => {},
3440 }
31313441
3132 .unreferenced => false,
3133 };
3442 if (was_outdated) {
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
31353449 var decl_prog_node = mod.sema_prog_node.start("", 0);
31363450 decl_prog_node.activate();
31373451 defer decl_prog_node.end();
31383452
3139 const type_changed = blk: {
3453 const sema_result: SemaDeclResult = blk: {
31403454 if (decl.zir_decl_index == .none and !mod.declIsRoot(decl_index)) {
31413455 // Anonymous decl. We don't semantically analyze these.
3142 break :blk false; // tv unchanged
3456 break :blk .{
3457 .invalidate_decl_val = false,
3458 .invalidate_decl_ref = false,
3459 };
31433460 }
31443461
31453462 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 {
31553472 error.NeededSourceLocation => unreachable,
31563473 error.GenericPoison => unreachable,
31573474 else => |e| {
3158 decl.analysis = .sema_failure_retryable;
3475 decl.analysis = .sema_failure;
31593476 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);
3477 try mod.retryable_failures.append(mod.gpa, InternPool.Depender.wrap(.{ .decl = decl_index }));
31603478 mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create(
31613479 mod.gpa,
31623480 decl.srcLoc(mod),
......@@ -3168,9 +3486,18 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
31683486 };
31693487 };
31703488
3171 if (subsequent_analysis) {
3172 _ = type_changed;
3173 @panic("TODO re-implement incremental compilation");
3489 // TODO: we do not yet have separate dependencies for decl values vs types.
3490 if (was_outdated) {
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 }
31743501 }
31753502}
31763503
......@@ -3186,119 +3513,129 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError
31863513 switch (decl.analysis) {
31873514 .unreferenced => unreachable,
31883515 .in_progress => unreachable,
3189 .outdated => unreachable,
3516
3517 .codegen_failure => unreachable, // functions do not perform constant value generation
31903518
31913519 .file_failure,
31923520 .sema_failure,
3193 .liveness_failure,
3194 .codegen_failure,
31953521 .dependency_failure,
3196 .sema_failure_retryable,
31973522 => return error.AnalysisFail,
31983523
3199 .complete, .codegen_failure_retryable => {
3200 switch (func.analysis(ip).state) {
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 }
3524 .complete => {},
3525 }
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);
3211 defer tmp_arena.deinit();
3212 const sema_arena = tmp_arena.allocator();
3531 if (was_outdated) {
3532 _ = zcu.outdated_ready.swapRemove(func_as_depender);
3533 }
32133534
3214 var air = zcu.analyzeFnBody(func_index, sema_arena) catch |err| switch (err) {
3215 error.AnalysisFail => {
3216 if (func.analysis(ip).state == .in_progress) {
3217 // If this decl caused the compile error, the analysis field would
3218 // be changed to indicate it was this Decl's fault. Because this
3219 // did not happen, we infer here that it was a dependency failure.
3220 func.analysis(ip).state = .dependency_failure;
3221 }
3222 return error.AnalysisFail;
3223 },
3224 error.OutOfMemory => return error.OutOfMemory,
3225 };
3226 defer air.deinit(gpa);
3535 switch (func.analysis(ip).state) {
3536 .success,
3537 .sema_failure,
3538 .dependency_failure,
3539 .codegen_failure,
3540 => if (!was_outdated) return error.AnalysisFail,
3541 .none, .queued => {},
3542 .in_progress => unreachable,
3543 .inline_only => unreachable, // don't queue work for this
3544 }
32273545
3228 const comp = zcu.comp;
3546 const gpa = zcu.gpa;
32293547
3230 const dump_air = builtin.mode == .Debug and comp.verbose_air;
3231 const dump_llvm_ir = builtin.mode == .Debug and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null);
3548 var tmp_arena = std.heap.ArenaAllocator.init(gpa);
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) {
3234 return;
3552 var air = zcu.analyzeFnBody(func_index, sema_arena) catch |err| switch (err) {
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;
32353559 }
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);
3238 defer liveness.deinit(gpa);
3566 const comp = zcu.comp;
32393567
3240 if (dump_air) {
3241 const fqn = try decl.getFullyQualifiedName(zcu);
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 }
3568 const dump_air = builtin.mode == .Debug and comp.verbose_air;
3569 const dump_llvm_ir = builtin.mode == .Debug and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null);
32463570
3247 if (std.debug.runtime_safety) {
3248 var verify = Liveness.Verify{
3249 .gpa = gpa,
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 }
3571 if (comp.bin_file == null and zcu.llvm_object == null and !dump_air and !dump_llvm_ir) {
3572 return;
3573 }
32743574
3275 if (comp.bin_file) |lf| {
3276 lf.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) {
3277 error.OutOfMemory => return error.OutOfMemory,
3278 error.AnalysisFail => {
3279 decl.analysis = .codegen_failure;
3280 },
3281 else => {
3282 try zcu.failed_decls.ensureUnusedCapacity(gpa, 1);
3283 zcu.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create(
3284 gpa,
3285 decl.srcLoc(zcu),
3286 "unable to codegen: {s}",
3287 .{@errorName(err)},
3288 ));
3289 decl.analysis = .codegen_failure_retryable;
3290 },
3291 };
3292 } else if (zcu.llvm_object) |llvm_object| {
3293 if (build_options.only_c) unreachable;
3294 llvm_object.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) {
3295 error.OutOfMemory => return error.OutOfMemory,
3296 error.AnalysisFail => {
3297 decl.analysis = .codegen_failure;
3298 },
3299 };
3300 }
3301 },
3575 var liveness = try Liveness.analyze(gpa, air, ip);
3576 defer liveness.deinit(gpa);
3577
3578 if (dump_air) {
3579 const fqn = try decl.getFullyQualifiedName(zcu);
3580 std.debug.print("# Begin Function AIR: {}:\n", .{fqn.fmt(ip)});
3581 @import("print_air.zig").dump(zcu, air, liveness);
3582 std.debug.print("# End Function AIR: {}\n\n", .{fqn.fmt(ip)});
3583 }
3584
3585 if (std.debug.runtime_safety) {
3586 var verify = Liveness.Verify{
3587 .gpa = gpa,
3588 .air = air,
3589 .liveness = liveness,
3590 .intern_pool = ip,
3591 };
3592 defer verify.deinit();
3593
3594 verify.verify() catch |err| switch (err) {
3595 error.OutOfMemory => return error.OutOfMemory,
3596 else => {
3597 try zcu.failed_decls.ensureUnusedCapacity(gpa, 1);
3598 zcu.failed_decls.putAssumeCapacityNoClobber(
3599 decl_index,
3600 try Module.ErrorMsg.create(
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 };
33023639 }
33033640}
33043641
......@@ -3318,18 +3655,14 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index)
33183655 switch (decl.analysis) {
33193656 .unreferenced => unreachable,
33203657 .in_progress => unreachable,
3321 .outdated => unreachable,
33223658
33233659 .file_failure,
33243660 .sema_failure,
3325 .liveness_failure,
33263661 .codegen_failure,
33273662 .dependency_failure,
3328 .sema_failure_retryable,
3329 .codegen_failure_retryable,
3330 // The function analysis failed, but we've already emitted an error for
3331 // that. The callee doesn't need the function to be analyzed right now,
3332 // so its analysis can safely continue.
3663 // Analysis of the function Decl itself failed, but we've already
3664 // emitted an error for that. The callee doesn't need the function to be
3665 // analyzed right now, so its analysis can safely continue.
33333666 => return,
33343667
33353668 .complete => {},
......@@ -3337,14 +3670,21 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index)
33373670
33383671 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
33403677 switch (func.analysis(ip).state) {
33413678 .none => {},
33423679 .queued => return,
33433680 // 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,
33453686 .in_progress => return,
33463687 .inline_only => unreachable, // don't queue work for this
3347 .success => return,
33483688 }
33493689
33503690 // 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 {
34043744 new_decl.@"linksection" = .none;
34053745 new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive.
34063746 new_decl.analysis = .in_progress;
3407 new_decl.generation = mod.generation;
34083747
34093748 if (file.status != .success_zir) {
34103749 new_decl.analysis = .file_failure;
......@@ -3483,12 +3822,19 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
34833822 },
34843823 .incremental => {},
34853824 }
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.
34863828}
34873829
3488/// Returns `true` if the Decl type changed.
3489/// Returns `true` if this is the first time analyzing the Decl.
3490/// Returns `false` otherwise.
3491fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
3830const SemaDeclResult = packed struct {
3831 /// Whether the value of a `decl_val` of this Decl changed.
3832 invalidate_decl_val: 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 {
34923838 const tracy = trace(@src());
34933839 defer tracy.end();
34943840
......@@ -3499,6 +3845,15 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
34993845 return error.AnalysisFail;
35003846 }
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
35023857 const gpa = mod.gpa;
35033858 const zir = decl.getFileScope(mod).zir;
35043859
......@@ -3535,6 +3890,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
35353890 break :blk .none;
35363891 };
35373892
3893 mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .decl = decl_index }));
3894
35383895 decl.analysis = .in_progress;
35393896
35403897 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
......@@ -3564,7 +3921,12 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
35643921 };
35653922 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
35693931 var block_scope: Sema.Block = .{
35703932 .parent = null,
......@@ -3620,9 +3982,12 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
36203982 decl.has_tv = true;
36213983 decl.owns_tv = false;
36223984 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 };
36263991 }
36273992
36283993 switch (ip.indexToKey(decl_tv.val.toIntern())) {
......@@ -3647,7 +4012,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
36474012 decl.has_tv = true;
36484013 decl.owns_tv = owns_tv;
36494014 decl.analysis = .complete;
3650 decl.generation = mod.generation;
36514015
36524016 const is_inline = decl.ty.fnCallingConvention(mod) == .Inline;
36534017 if (decl.is_exported) {
......@@ -3658,15 +4022,16 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
36584022 // The scope needs to have the decl in it.
36594023 try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);
36604024 }
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 };
36624031 }
36634032 },
36644033 else => {},
36654034 }
3666 var type_changed = true;
3667 if (decl.has_tv) {
3668 type_changed = !decl.ty.eql(decl_tv.ty, mod);
3669 }
36704035
36714036 decl.owns_tv = false;
36724037 var queue_linker_work = false;
......@@ -3694,6 +4059,14 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
36944059 },
36954060 }
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
36974070 decl.ty = decl_tv.ty;
36984071 decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod)));
36994072 decl.alignment = blk: {
......@@ -3735,7 +4108,17 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
37354108 };
37364109 decl.has_tv = true;
37374110 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
37404123 const has_runtime_bits = is_extern or
37414124 (queue_linker_work and try sema.typeHasRuntimeBits(decl.ty));
......@@ -3748,7 +4131,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
37484131
37494132 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) {
37524135 try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index });
37534136 }
37544137 }
......@@ -3759,7 +4142,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
37594142 try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);
37604143 }
37614144
3762 return type_changed;
4145 return result;
37634146}
37644147
37654148pub const ImportFileResult = struct {
......@@ -4362,6 +4745,8 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
43624745 const decl_index = func.owner_decl;
43634746 const decl = mod.declPtr(decl_index);
43644747
4748 mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index }));
4749
43654750 var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
43664751 defer comptime_mutable_decls.deinit();
43674752
......@@ -4633,7 +5018,6 @@ pub fn allocateNewDecl(
46335018 .analysis = .unreferenced,
46345019 .zir_decl_index = .none,
46355020 .src_scope = src_scope,
4636 .generation = 0,
46375021 .is_pub = false,
46385022 .is_exported = false,
46395023 .alive = false,
......@@ -4711,7 +5095,6 @@ pub fn initNewAnonDecl(
47115095 new_decl.@"linksection" = .none;
47125096 new_decl.has_tv = true;
47135097 new_decl.analysis = .complete;
4714 new_decl.generation = mod.generation;
47155098}
47165099
47175100pub fn errNoteNonLazy(
......@@ -5373,7 +5756,8 @@ pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void {
53735756 "unable to codegen: {s}",
53745757 .{@errorName(err)},
53755758 ));
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 }));
53775761 },
53785762 };
53795763 } 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)
25832583 ip.funcAnalysis(sema.owner_func_index).state = .sema_failure;
25842584 } else {
25852585 sema.owner_decl.analysis = .sema_failure;
2586 sema.owner_decl.generation = mod.generation;
25872586 }
25882587 if (sema.func_index != .none) {
25892588 ip.funcAnalysis(sema.func_index).state = .sema_failure;
......@@ -2718,7 +2717,7 @@ pub fn getStructType(
27182717 assert(extended.opcode == .struct_decl);
27192718 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;
27222721 extra_index += @intFromBool(small.has_src_node);
27232722 const fields_len = if (small.has_fields_len) blk: {
27242723 const fields_len = sema.code.extra[extra_index];
......@@ -2748,7 +2747,7 @@ pub fn getStructType(
27482747 const ty = try ip.getStructType(gpa, .{
27492748 .decl = decl,
27502749 .namespace = namespace.toOptional(),
2751 .zir_index = tracked_inst,
2750 .zir_index = tracked_inst.toOptional(),
27522751 .layout = small.layout,
27532752 .known_non_opv = small.known_non_opv,
27542753 .is_tuple = small.is_tuple,
......@@ -2773,7 +2772,7 @@ fn zirStructDecl(
27732772 const ip = &mod.intern_pool;
27742773 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
27752774 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]);
27772776 break :blk LazySrcLoc.nodeOffset(node_offset);
27782777 } else sema.src;
27792778
......@@ -2789,6 +2788,14 @@ fn zirStructDecl(
27892788 new_decl.owns_tv = true;
27902789 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
27922799 const new_namespace_index = try mod.createNamespace(.{
27932800 .parent = block.namespace.toOptional(),
27942801 .ty = undefined,
......@@ -2927,7 +2934,7 @@ fn zirEnumDecl(
29272934 const mod = sema.mod;
29282935 const gpa = sema.gpa;
29292936 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
29322939 const src: LazySrcLoc = if (small.has_src_node) blk: {
29332940 const node_offset: i32 = @bitCast(sema.code.extra[extra_index]);
......@@ -2973,6 +2980,14 @@ fn zirEnumDecl(
29732980 new_decl.owns_tv = true;
29742981 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
29762991 const new_namespace_index = try mod.createNamespace(.{
29772992 .parent = block.namespace.toOptional(),
29782993 .ty = undefined,
......@@ -3008,6 +3023,7 @@ fn zirEnumDecl(
30083023 .auto
30093024 else
30103025 .explicit,
3026 .zir_index = (try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst)).toOptional(),
30113027 });
30123028 if (sema.builtin_type_target_index != .none) {
30133029 mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, incomplete_enum.index);
......@@ -3191,7 +3207,7 @@ fn zirUnionDecl(
31913207 const mod = sema.mod;
31923208 const gpa = sema.gpa;
31933209 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
31963212 const src: LazySrcLoc = if (small.has_src_node) blk: {
31973213 const node_offset: i32 = @bitCast(sema.code.extra[extra_index]);
......@@ -3225,6 +3241,14 @@ fn zirUnionDecl(
32253241 new_decl.owns_tv = true;
32263242 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
32283252 const new_namespace_index = try mod.createNamespace(.{
32293253 .parent = block.namespace.toOptional(),
32303254 .ty = undefined,
......@@ -3254,7 +3278,7 @@ fn zirUnionDecl(
32543278 },
32553279 .decl = new_decl_index,
32563280 .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(),
32583282 .fields_len = fields_len,
32593283 .enum_tag_ty = .none,
32603284 .field_types = &.{},
......@@ -3318,6 +3342,14 @@ fn zirOpaqueDecl(
33183342 new_decl.owns_tv = true;
33193343 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
33213353 const new_namespace_index = try mod.createNamespace(.{
33223354 .parent = block.namespace.toOptional(),
33233355 .ty = undefined,
......@@ -3329,6 +3361,7 @@ fn zirOpaqueDecl(
33293361 const opaque_ty = try mod.intern(.{ .opaque_type = .{
33303362 .decl = new_decl_index,
33313363 .namespace = new_namespace_index,
3364 .zir_index = (try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst)).toOptional(),
33323365 } });
33333366 // TODO: figure out InternPool removals for incremental compilation
33343367 //errdefer mod.intern_pool.remove(opaque_ty);
......@@ -7890,6 +7923,8 @@ fn instantiateGenericCall(
78907923 const generic_owner_func = mod.intern_pool.indexToKey(generic_owner).func;
78917924 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
78937928 // Even though there may already be a generic instantiation corresponding
78947929 // to this callsite, we must evaluate the expressions of the generic
78957930 // function signature with the values of the callsite plugged in.
......@@ -9440,7 +9475,6 @@ fn funcCommon(
94409475 .inferred_error_set = inferred_error_set,
94419476 .generic_owner = sema.generic_owner,
94429477 .comptime_args = sema.comptime_args,
9443 .generation = mod.generation,
94449478 });
94459479 return finishFunc(
94469480 sema,
......@@ -13598,6 +13632,12 @@ fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1359813632 });
1359913633
1360013634 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
1360213642 const namespace = container_type.getNamespaceIndex(mod).unwrap() orelse
1360313643 return .bool_false;
......@@ -17451,6 +17491,10 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1745117491 const type_info_ty = try sema.getBuiltinType("Type");
1745217492 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
1745417498 switch (ty.zigTypeTag(mod)) {
1745517499 .Type,
1745617500 .Void,
......@@ -21318,6 +21362,7 @@ fn zirReify(
2131821362 else
2131921363 .explicit,
2132021364 .tag_ty = int_tag_ty.toIntern(),
21365 .zir_index = .none,
2132121366 });
2132221367 // TODO: figure out InternPool removals for incremental compilation
2132321368 //errdefer ip.remove(incomplete_enum.index);
......@@ -21415,6 +21460,7 @@ fn zirReify(
2141521460 const opaque_ty = try mod.intern(.{ .opaque_type = .{
2141621461 .decl = new_decl_index,
2141721462 .namespace = new_namespace_index,
21463 .zir_index = .none,
2141821464 } });
2141921465 // TODO: figure out InternPool removals for incremental compilation
2142021466 //errdefer ip.remove(opaque_ty);
......@@ -21633,7 +21679,7 @@ fn zirReify(
2163321679 .namespace = new_namespace_index,
2163421680 .enum_tag_ty = enum_tag_ty,
2163521681 .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,
2163721683 .flags = .{
2163821684 .layout = layout,
2163921685 .status = .have_field_types,
......@@ -21801,7 +21847,7 @@ fn reifyStruct(
2180121847 const ty = try ip.getStructType(gpa, .{
2180221848 .decl = new_decl_index,
2180321849 .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,
2180521851 .layout = layout,
2180621852 .known_non_opv = false,
2180721853 .fields_len = fields_len,
......@@ -25922,7 +25968,6 @@ fn zirBuiltinExtern(
2592225968 new_decl.has_tv = true;
2592325969 new_decl.owns_tv = true;
2592425970 new_decl.analysis = .complete;
25925 new_decl.generation = mod.generation;
2592625971
2592725972 try sema.ensureDeclAnalyzed(new_decl_index);
2592825973
......@@ -26421,6 +26466,7 @@ fn prepareSimplePanic(sema: *Sema, block: *Block) !void {
2642126466 // owns the function.
2642226467 try sema.ensureDeclAnalyzed(decl_index);
2642326468 const tv = try mod.declPtr(decl_index).typedValue();
26469 try sema.declareDependency(.{ .decl_val = decl_index });
2642426470 assert(tv.ty.zigTypeTag(mod) == .Fn);
2642526471 assert(try sema.fnHasRuntimeBits(tv.ty));
2642626472 const func_index = tv.val.toIntern();
......@@ -26842,6 +26888,13 @@ fn fieldVal(
2684226888 const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?;
2684326889 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
2684526898 switch (try child_type.zigTypeTagOrPoison(mod)) {
2684626899 .ErrorSet => {
2684726900 switch (ip.indexToKey(child_type.toIntern())) {
......@@ -27065,6 +27118,13 @@ fn fieldPtr(
2706527118 const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?;
2706627119 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
2706827128 switch (child_type.zigTypeTag(mod)) {
2706927129 .ErrorSet => {
2707027130 switch (ip.indexToKey(child_type.toIntern())) {
......@@ -31134,6 +31194,7 @@ fn beginComptimePtrLoad(
3113431194 const is_mutable = ptr.addr == .mut_decl;
3113531195 const decl = mod.declPtr(decl_index);
3113631196 const decl_tv = try decl.typedValue();
31197 try sema.declareDependency(.{ .decl_val = decl_index });
3113731198 if (decl.val.getVariable(mod) != null) return error.RuntimeLoad;
3113831199
3113931200 const layout_defined = decl.ty.hasWellDefinedLayout(mod);
......@@ -32387,6 +32448,8 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn
3238732448
3238832449 const decl = mod.declPtr(decl_index);
3238932450 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 });
3239032453 const ptr_ty = try sema.ptrType(.{
3239132454 .child = decl_tv.ty.toIntern(),
3239232455 .flags = .{
......@@ -35683,13 +35746,13 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp
3568335746 break :blk accumulator;
3568435747 };
3568535748
35686 const zir_index = struct_type.zir_index.resolve(ip);
35749 const zir_index = struct_type.zir_index.unwrap().?.resolve(ip);
3568735750 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
3568835751 assert(extended.opcode == .struct_decl);
3568935752 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
3569035753
3569135754 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;
3569335756 extra_index += @intFromBool(small.has_src_node);
3569435757 extra_index += @intFromBool(small.has_fields_len);
3569535758 extra_index += @intFromBool(small.has_decls_len);
......@@ -36162,10 +36225,8 @@ pub fn resolveTypeFieldsStruct(
3616236225 .file_failure,
3616336226 .dependency_failure,
3616436227 .sema_failure,
36165 .sema_failure_retryable,
3616636228 => {
3616736229 sema.owner_decl.analysis = .dependency_failure;
36168 sema.owner_decl.generation = mod.generation;
3616936230 return error.AnalysisFail;
3617036231 },
3617136232 else => {},
......@@ -36221,10 +36282,8 @@ pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.
3622136282 .file_failure,
3622236283 .dependency_failure,
3622336284 .sema_failure,
36224 .sema_failure_retryable,
3622536285 => {
3622636286 sema.owner_decl.analysis = .dependency_failure;
36227 sema.owner_decl.generation = mod.generation;
3622836287 return error.AnalysisFail;
3622936288 },
3623036289 else => {},
......@@ -36404,7 +36463,7 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
3640436463 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
3640536464 assert(extended.opcode == .struct_decl);
3640636465 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
3640936468 extra_index += @intFromBool(small.has_src_node);
3641036469
......@@ -36448,7 +36507,7 @@ fn semaStructFields(
3644836507 const decl = mod.declPtr(decl_index);
3644936508 const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace;
3645036509 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
3645336512 const fields_len, const small, var extra_index = structZirInfo(zir, zir_index);
3645436513
......@@ -36719,7 +36778,7 @@ fn semaStructFieldInits(
3671936778 const decl = mod.declPtr(decl_index);
3672036779 const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace;
3672136780 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);
3672336782 const fields_len, const small, var extra_index = structZirInfo(zir, zir_index);
3672436783
3672536784 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
3686836927 const ip = &mod.intern_pool;
3686936928 const decl_index = union_type.decl;
3687036929 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);
3687236931 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
3687336932 assert(extended.opcode == .union_decl);
3687436933 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
3687736936 const src = LazySrcLoc.nodeOffset(0);
3687836937 extra_index += @intFromBool(small.has_src_node);
......@@ -37312,6 +37371,7 @@ fn generateUnionTagTypeNumbered(
3731237371 .names = enum_field_names,
3731337372 .values = enum_field_vals,
3731437373 .tag_mode = .explicit,
37374 .zir_index = .none,
3731537375 });
3731637376
3731737377 new_decl.ty = Type.type;
......@@ -37362,6 +37422,7 @@ fn generateUnionTagTypeSimple(
3736237422 .names = enum_field_names,
3736337423 .values = &.{},
3736437424 .tag_mode = .auto,
37425 .zir_index = .none,
3736537426 });
3736637427
3736737428 const new_decl = mod.declPtr(new_decl_index);
......@@ -38876,3 +38937,14 @@ fn ptrType(sema: *Sema, info: InternPool.Key.PtrType) CompileError!Type {
3887638937 }
3887738938 return sema.mod.ptrType(info);
3887838939}
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 {
24972497 /// }
24982498 /// 2. body: Index // for each body_len
24992499 /// 3. src_locs: SrcLocs // if body_len != 0
2500 /// 4. proto_hash: std.zig.SrcHash // if body_len != 0; hash of function prototype
25002501 pub const Func = struct {
25012502 /// If this is 0 it means a void return type.
25022503 /// If this is 1 it means return_type is a simple Ref
......@@ -2558,6 +2559,7 @@ pub const Inst = struct {
25582559 /// - each bit starting with LSB corresponds to parameter indexes
25592560 /// 17. body: Index // for each body_len
25602561 /// 18. src_locs: Func.SrcLocs // if body_len != 0
2562 /// 19. proto_hash: std.zig.SrcHash // if body_len != 0; hash of function prototype
25612563 pub const FuncFancy = struct {
25622564 /// Points to the block that contains the param instructions for this function.
25632565 /// If this is a `declaration`, it refers to the declaration's value body.
......@@ -3040,6 +3042,12 @@ pub const Inst = struct {
30403042 /// init_body_inst: Inst, // for each init_body_len
30413043 /// }
30423044 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,
30433051 pub const Small = packed struct {
30443052 has_src_node: bool,
30453053 has_fields_len: bool,
......@@ -3102,6 +3110,12 @@ pub const Inst = struct {
31023110 /// value: Ref, // if corresponding bit is set
31033111 /// }
31043112 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,
31053119 pub const Small = packed struct {
31063120 has_src_node: bool,
31073121 has_tag_type: bool,
......@@ -3137,6 +3151,12 @@ pub const Inst = struct {
31373151 /// tag_value: Ref, // if corresponding bit is set
31383152 /// }
31393153 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,
31403160 pub const Small = packed struct {
31413161 has_src_node: bool,
31423162 has_tag_type: bool,
......@@ -3455,7 +3475,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
34553475 switch (extended.opcode) {
34563476 .struct_decl => {
34573477 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);
34593479 extra_index += @intFromBool(small.has_src_node);
34603480 extra_index += @intFromBool(small.has_fields_len);
34613481 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 {
34823502 },
34833503 .enum_decl => {
34843504 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);
34863506 extra_index += @intFromBool(small.has_src_node);
34873507 extra_index += @intFromBool(small.has_tag_type);
34883508 extra_index += @intFromBool(small.has_body_len);
......@@ -3501,7 +3521,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
35013521 },
35023522 .union_decl => {
35033523 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);
35053525 extra_index += @intFromBool(small.has_src_node);
35063526 extra_index += @intFromBool(small.has_tag_type);
35073527 extra_index += @intFromBool(small.has_body_len);
......@@ -3938,3 +3958,111 @@ pub fn getDeclaration(zir: Zir, inst: Zir.Inst.Index) struct { Inst.Declaration,
39383958 @intCast(extra.end),
39393959 };
39403960}
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(
32553255 .cache_mode = cache_mode,
32563256 .subsystem = subsystem,
32573257 .debug_compile_errors = debug_compile_errors,
3258 .debug_incremental = debug_incremental,
32583259 .enable_link_snapshots = enable_link_snapshots,
32593260 .install_name = install_name,
32603261 .entitlements = entitlements,
src/print_zir.zig+34-3
......@@ -1401,7 +1401,17 @@ const Writer = struct {
14011401 fn writeStructDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
14021402 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
14061416 const src_node: ?i32 = if (small.has_src_node) blk: {
14071417 const src_node = @as(i32, @bitCast(self.code.extra[extra_index]));
......@@ -1591,7 +1601,17 @@ const Writer = struct {
15911601 fn writeUnionDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
15921602 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
15961616 const src_node: ?i32 = if (small.has_src_node) blk: {
15971617 const src_node = @as(i32, @bitCast(self.code.extra[extra_index]));
......@@ -1733,7 +1753,18 @@ const Writer = struct {
17331753
17341754 fn writeEnumDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void {
17351755 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
17381769 const src_node: ?i32 = if (small.has_src_node) blk: {
17391770 const src_node = @as(i32, @bitCast(self.code.extra[extra_index]));
src/type.zig+12
......@@ -4,6 +4,7 @@ const Value = @import("Value.zig");
44const assert = std.debug.assert;
55const Target = std.Target;
66const Module = @import("Module.zig");
7const Zcu = Module;
78const log = std.log.scoped(.Type);
89const target_util = @import("target.zig");
910const TypedValue = @import("TypedValue.zig");
......@@ -3228,6 +3229,17 @@ pub const Type = struct {
32283229 };
32293230 }
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
32313243 pub const @"u1": Type = .{ .ip_index = .u1_type };
32323244 pub const @"u8": Type = .{ .ip_index = .u8_type };
32333245 pub const @"u16": Type = .{ .ip_index = .u16_type };