| author | |
| committer | |
| log | 0c8072506883db21d5f8e3e7e7cb45b36d496f28 |
| tree | 2bdfd1254c7931322ea75ffb2c5823000c5083d0 |
| parent | 648b492ef1d962cabd7d2f017ef47aef73c0c3aa |
| parent | 0784d389844a127248bb724352ce7101bc49784c |
| signature |
Begin re-implementing incremental compilation11 files changed, 1308 insertions(+), 300 deletions(-)
lib/std/zig.zig+3-2| ... | ... | @@ -27,11 +27,12 @@ pub const parseNumberLiteral = number_literal.parseNumberLiteral; |
| 27 | 27 | pub const c_builtins = @import("zig/c_builtins.zig"); |
| 28 | 28 | pub const c_translation = @import("zig/c_translation.zig"); |
| 29 | 29 | |
| 30 | pub const SrcHasher = std.crypto.hash.Blake3; | |
| 30 | 31 | pub const SrcHash = [16]u8; |
| 31 | 32 | |
| 32 | 33 | pub fn hashSrc(src: []const u8) SrcHash { |
| 33 | 34 | var out: SrcHash = undefined; |
| 34 | std.crypto.hash.Blake3.hash(src, &out, .{}); | |
| 35 | SrcHasher.hash(src, &out, .{}); | |
| 35 | 36 | return out; |
| 36 | 37 | } |
| 37 | 38 | |
| ... | ... | @@ -41,7 +42,7 @@ pub fn srcHashEql(a: SrcHash, b: SrcHash) bool { |
| 41 | 42 | |
| 42 | 43 | pub fn hashName(parent_hash: SrcHash, sep: []const u8, name: []const u8) SrcHash { |
| 43 | 44 | var out: SrcHash = undefined; |
| 44 | var hasher = std.crypto.hash.Blake3.init(.{}); | |
| 45 | var hasher = SrcHasher.init(.{}); | |
| 45 | 46 | hasher.update(&parent_hash); |
| 46 | 47 | hasher.update(sep); |
| 47 | 48 | hasher.update(name); |
src/AstGen.zig+93-16| ... | ... | @@ -4815,6 +4815,7 @@ fn structDeclInner( |
| 4815 | 4815 | .any_comptime_fields = false, |
| 4816 | 4816 | .any_default_inits = false, |
| 4817 | 4817 | .any_aligned_fields = false, |
| 4818 | .fields_hash = std.zig.hashSrc(@tagName(layout)), | |
| 4818 | 4819 | }); |
| 4819 | 4820 | return decl_inst.toRef(); |
| 4820 | 4821 | } |
| ... | ... | @@ -4936,6 +4937,12 @@ fn structDeclInner( |
| 4936 | 4937 | } |
| 4937 | 4938 | }; |
| 4938 | 4939 | |
| 4940 | var fields_hasher = std.zig.SrcHasher.init(.{}); | |
| 4941 | fields_hasher.update(@tagName(layout)); | |
| 4942 | if (backing_int_node != 0) { | |
| 4943 | fields_hasher.update(tree.getNodeSource(backing_int_node)); | |
| 4944 | } | |
| 4945 | ||
| 4939 | 4946 | var sfba = std.heap.stackFallback(256, astgen.arena); |
| 4940 | 4947 | const sfba_allocator = sfba.get(); |
| 4941 | 4948 | |
| ... | ... | @@ -4956,6 +4963,8 @@ fn structDeclInner( |
| 4956 | 4963 | .field => |field| field, |
| 4957 | 4964 | }; |
| 4958 | 4965 | |
| 4966 | fields_hasher.update(tree.getNodeSource(member_node)); | |
| 4967 | ||
| 4959 | 4968 | if (!is_tuple) { |
| 4960 | 4969 | const field_name = try astgen.identAsString(member.ast.main_token); |
| 4961 | 4970 | |
| ... | ... | @@ -5083,6 +5092,9 @@ fn structDeclInner( |
| 5083 | 5092 | return error.AnalysisFail; |
| 5084 | 5093 | } |
| 5085 | 5094 | |
| 5095 | var fields_hash: std.zig.SrcHash = undefined; | |
| 5096 | fields_hasher.final(&fields_hash); | |
| 5097 | ||
| 5086 | 5098 | try gz.setStruct(decl_inst, .{ |
| 5087 | 5099 | .src_node = node, |
| 5088 | 5100 | .layout = layout, |
| ... | ... | @@ -5096,6 +5108,7 @@ fn structDeclInner( |
| 5096 | 5108 | .any_comptime_fields = any_comptime_fields, |
| 5097 | 5109 | .any_default_inits = any_default_inits, |
| 5098 | 5110 | .any_aligned_fields = any_aligned_fields, |
| 5111 | .fields_hash = fields_hash, | |
| 5099 | 5112 | }); |
| 5100 | 5113 | |
| 5101 | 5114 | wip_members.finishBits(bits_per_field); |
| ... | ... | @@ -5174,6 +5187,13 @@ fn unionDeclInner( |
| 5174 | 5187 | var wip_members = try WipMembers.init(gpa, &astgen.scratch, decl_count, field_count, bits_per_field, max_field_size); |
| 5175 | 5188 | defer wip_members.deinit(); |
| 5176 | 5189 | |
| 5190 | var fields_hasher = std.zig.SrcHasher.init(.{}); | |
| 5191 | fields_hasher.update(@tagName(layout)); | |
| 5192 | fields_hasher.update(&.{@intFromBool(auto_enum_tok != null)}); | |
| 5193 | if (arg_node != 0) { | |
| 5194 | fields_hasher.update(astgen.tree.getNodeSource(arg_node)); | |
| 5195 | } | |
| 5196 | ||
| 5177 | 5197 | var sfba = std.heap.stackFallback(256, astgen.arena); |
| 5178 | 5198 | const sfba_allocator = sfba.get(); |
| 5179 | 5199 | |
| ... | ... | @@ -5188,6 +5208,7 @@ fn unionDeclInner( |
| 5188 | 5208 | .decl => continue, |
| 5189 | 5209 | .field => |field| field, |
| 5190 | 5210 | }; |
| 5211 | fields_hasher.update(astgen.tree.getNodeSource(member_node)); | |
| 5191 | 5212 | member.convertToNonTupleLike(astgen.tree.nodes); |
| 5192 | 5213 | if (member.ast.tuple_like) { |
| 5193 | 5214 | return astgen.failTok(member.ast.main_token, "union field missing name", .{}); |
| ... | ... | @@ -5289,6 +5310,9 @@ fn unionDeclInner( |
| 5289 | 5310 | return error.AnalysisFail; |
| 5290 | 5311 | } |
| 5291 | 5312 | |
| 5313 | var fields_hash: std.zig.SrcHash = undefined; | |
| 5314 | fields_hasher.final(&fields_hash); | |
| 5315 | ||
| 5292 | 5316 | if (!block_scope.isEmpty()) { |
| 5293 | 5317 | _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); |
| 5294 | 5318 | } |
| ... | ... | @@ -5305,6 +5329,7 @@ fn unionDeclInner( |
| 5305 | 5329 | .decls_len = decl_count, |
| 5306 | 5330 | .auto_enum_tag = auto_enum_tok != null, |
| 5307 | 5331 | .any_aligned_fields = any_aligned_fields, |
| 5332 | .fields_hash = fields_hash, | |
| 5308 | 5333 | }); |
| 5309 | 5334 | |
| 5310 | 5335 | wip_members.finishBits(bits_per_field); |
| ... | ... | @@ -5498,6 +5523,12 @@ fn containerDecl( |
| 5498 | 5523 | var wip_members = try WipMembers.init(gpa, &astgen.scratch, @intCast(counts.decls), @intCast(counts.total_fields), bits_per_field, max_field_size); |
| 5499 | 5524 | defer wip_members.deinit(); |
| 5500 | 5525 | |
| 5526 | var fields_hasher = std.zig.SrcHasher.init(.{}); | |
| 5527 | if (container_decl.ast.arg != 0) { | |
| 5528 | fields_hasher.update(tree.getNodeSource(container_decl.ast.arg)); | |
| 5529 | } | |
| 5530 | fields_hasher.update(&.{@intFromBool(nonexhaustive)}); | |
| 5531 | ||
| 5501 | 5532 | var sfba = std.heap.stackFallback(256, astgen.arena); |
| 5502 | 5533 | const sfba_allocator = sfba.get(); |
| 5503 | 5534 | |
| ... | ... | @@ -5510,6 +5541,7 @@ fn containerDecl( |
| 5510 | 5541 | for (container_decl.ast.members) |member_node| { |
| 5511 | 5542 | if (member_node == counts.nonexhaustive_node) |
| 5512 | 5543 | continue; |
| 5544 | fields_hasher.update(tree.getNodeSource(member_node)); | |
| 5513 | 5545 | namespace.base.tag = .namespace; |
| 5514 | 5546 | var member = switch (try containerMember(&block_scope, &namespace.base, &wip_members, member_node)) { |
| 5515 | 5547 | .decl => continue, |
| ... | ... | @@ -5590,6 +5622,9 @@ fn containerDecl( |
| 5590 | 5622 | _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); |
| 5591 | 5623 | } |
| 5592 | 5624 | |
| 5625 | var fields_hash: std.zig.SrcHash = undefined; | |
| 5626 | fields_hasher.final(&fields_hash); | |
| 5627 | ||
| 5593 | 5628 | const body = block_scope.instructionsSlice(); |
| 5594 | 5629 | const body_len = astgen.countBodyLenAfterFixups(body); |
| 5595 | 5630 | |
| ... | ... | @@ -5600,6 +5635,7 @@ fn containerDecl( |
| 5600 | 5635 | .body_len = body_len, |
| 5601 | 5636 | .fields_len = @intCast(counts.total_fields), |
| 5602 | 5637 | .decls_len = @intCast(counts.decls), |
| 5638 | .fields_hash = fields_hash, | |
| 5603 | 5639 | }); |
| 5604 | 5640 | |
| 5605 | 5641 | wip_members.finishBits(bits_per_field); |
| ... | ... | @@ -11900,8 +11936,8 @@ const GenZir = struct { |
| 11900 | 11936 | |
| 11901 | 11937 | var body: []Zir.Inst.Index = &[0]Zir.Inst.Index{}; |
| 11902 | 11938 | 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]; | |
| 11905 | 11941 | if (args.body_gz) |body_gz| { |
| 11906 | 11942 | const tree = astgen.tree; |
| 11907 | 11943 | const node_tags = tree.nodes.items(.tag); |
| ... | ... | @@ -11916,10 +11952,27 @@ const GenZir = struct { |
| 11916 | 11952 | const rbrace_column: u32 = @intCast(astgen.source_column); |
| 11917 | 11953 | |
| 11918 | 11954 | 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; | |
| 11923 | 11976 | |
| 11924 | 11977 | body = body_gz.instructionsSlice(); |
| 11925 | 11978 | if (args.ret_gz) |ret_gz| |
| ... | ... | @@ -11953,7 +12006,7 @@ const GenZir = struct { |
| 11953 | 12006 | fancyFnExprExtraLen(astgen, section_body, args.section_ref) + |
| 11954 | 12007 | fancyFnExprExtraLen(astgen, cc_body, args.cc_ref) + |
| 11955 | 12008 | fancyFnExprExtraLen(astgen, ret_body, ret_ref) + |
| 11956 | body_len + src_locs.len + | |
| 12009 | body_len + src_locs_and_hash.len + | |
| 11957 | 12010 | @intFromBool(args.lib_name != .empty) + |
| 11958 | 12011 | @intFromBool(args.noalias_bits != 0), |
| 11959 | 12012 | ); |
| ... | ... | @@ -12040,7 +12093,7 @@ const GenZir = struct { |
| 12040 | 12093 | } |
| 12041 | 12094 | |
| 12042 | 12095 | astgen.appendBodyWithFixups(body); |
| 12043 | astgen.extra.appendSliceAssumeCapacity(src_locs); | |
| 12096 | astgen.extra.appendSliceAssumeCapacity(src_locs_and_hash); | |
| 12044 | 12097 | |
| 12045 | 12098 | // Order is important when unstacking. |
| 12046 | 12099 | if (args.body_gz) |body_gz| body_gz.unstack(); |
| ... | ... | @@ -12068,7 +12121,7 @@ const GenZir = struct { |
| 12068 | 12121 | gpa, |
| 12069 | 12122 | @typeInfo(Zir.Inst.Func).Struct.fields.len + 1 + |
| 12070 | 12123 | fancyFnExprExtraLen(astgen, ret_body, ret_ref) + |
| 12071 | body_len + src_locs.len, | |
| 12124 | body_len + src_locs_and_hash.len, | |
| 12072 | 12125 | ); |
| 12073 | 12126 | |
| 12074 | 12127 | const ret_body_len = if (ret_body.len != 0) |
| ... | ... | @@ -12092,7 +12145,7 @@ const GenZir = struct { |
| 12092 | 12145 | astgen.extra.appendAssumeCapacity(@intFromEnum(ret_ref)); |
| 12093 | 12146 | } |
| 12094 | 12147 | astgen.appendBodyWithFixups(body); |
| 12095 | astgen.extra.appendSliceAssumeCapacity(src_locs); | |
| 12148 | astgen.extra.appendSliceAssumeCapacity(src_locs_and_hash); | |
| 12096 | 12149 | |
| 12097 | 12150 | // Order is important when unstacking. |
| 12098 | 12151 | if (args.body_gz) |body_gz| body_gz.unstack(); |
| ... | ... | @@ -12853,12 +12906,20 @@ const GenZir = struct { |
| 12853 | 12906 | any_comptime_fields: bool, |
| 12854 | 12907 | any_default_inits: bool, |
| 12855 | 12908 | any_aligned_fields: bool, |
| 12909 | fields_hash: std.zig.SrcHash, | |
| 12856 | 12910 | }) !void { |
| 12857 | 12911 | const astgen = gz.astgen; |
| 12858 | 12912 | const gpa = astgen.gpa; |
| 12859 | 12913 | |
| 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 | }); | |
| 12862 | 12923 | |
| 12863 | 12924 | if (args.src_node != 0) { |
| 12864 | 12925 | const node_offset = gz.nodeIndexToRelative(args.src_node); |
| ... | ... | @@ -12908,12 +12969,20 @@ const GenZir = struct { |
| 12908 | 12969 | layout: std.builtin.Type.ContainerLayout, |
| 12909 | 12970 | auto_enum_tag: bool, |
| 12910 | 12971 | any_aligned_fields: bool, |
| 12972 | fields_hash: std.zig.SrcHash, | |
| 12911 | 12973 | }) !void { |
| 12912 | 12974 | const astgen = gz.astgen; |
| 12913 | 12975 | const gpa = astgen.gpa; |
| 12914 | 12976 | |
| 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 | }); | |
| 12917 | 12986 | |
| 12918 | 12987 | if (args.src_node != 0) { |
| 12919 | 12988 | const node_offset = gz.nodeIndexToRelative(args.src_node); |
| ... | ... | @@ -12958,12 +13027,20 @@ const GenZir = struct { |
| 12958 | 13027 | fields_len: u32, |
| 12959 | 13028 | decls_len: u32, |
| 12960 | 13029 | nonexhaustive: bool, |
| 13030 | fields_hash: std.zig.SrcHash, | |
| 12961 | 13031 | }) !void { |
| 12962 | 13032 | const astgen = gz.astgen; |
| 12963 | 13033 | const gpa = astgen.gpa; |
| 12964 | 13034 | |
| 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 | }); | |
| 12967 | 13044 | |
| 12968 | 13045 | if (args.src_node != 0) { |
| 12969 | 13046 | const node_offset = gz.nodeIndexToRelative(args.src_node); |
src/Autodoc.zig+3-3| ... | ... | @@ -3497,7 +3497,7 @@ fn walkInstruction( |
| 3497 | 3497 | }; |
| 3498 | 3498 | |
| 3499 | 3499 | const small = @as(Zir.Inst.UnionDecl.Small, @bitCast(extended.small)); |
| 3500 | var extra_index: usize = extended.operand; | |
| 3500 | var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.UnionDecl).Struct.fields.len; | |
| 3501 | 3501 | |
| 3502 | 3502 | const src_node: ?i32 = if (small.has_src_node) blk: { |
| 3503 | 3503 | const src_node = @as(i32, @bitCast(file.zir.extra[extra_index])); |
| ... | ... | @@ -3627,7 +3627,7 @@ fn walkInstruction( |
| 3627 | 3627 | }; |
| 3628 | 3628 | |
| 3629 | 3629 | const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small)); |
| 3630 | var extra_index: usize = extended.operand; | |
| 3630 | var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.EnumDecl).Struct.fields.len; | |
| 3631 | 3631 | |
| 3632 | 3632 | const src_node: ?i32 = if (small.has_src_node) blk: { |
| 3633 | 3633 | const src_node = @as(i32, @bitCast(file.zir.extra[extra_index])); |
| ... | ... | @@ -3778,7 +3778,7 @@ fn walkInstruction( |
| 3778 | 3778 | }; |
| 3779 | 3779 | |
| 3780 | 3780 | const small = @as(Zir.Inst.StructDecl.Small, @bitCast(extended.small)); |
| 3781 | var extra_index: usize = extended.operand; | |
| 3781 | var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len; | |
| 3782 | 3782 | |
| 3783 | 3783 | const src_node: ?i32 = if (small.has_src_node) blk: { |
| 3784 | 3784 | const src_node = @as(i32, @bitCast(file.zir.extra[extra_index])); |
src/Compilation.zig+48-13| ... | ... | @@ -156,6 +156,7 @@ time_report: bool, |
| 156 | 156 | stack_report: bool, |
| 157 | 157 | debug_compiler_runtime_libs: bool, |
| 158 | 158 | debug_compile_errors: bool, |
| 159 | debug_incremental: bool, | |
| 159 | 160 | job_queued_compiler_rt_lib: bool = false, |
| 160 | 161 | job_queued_compiler_rt_obj: bool = false, |
| 161 | 162 | job_queued_update_builtin_zig: bool, |
| ... | ... | @@ -1079,6 +1080,7 @@ pub const CreateOptions = struct { |
| 1079 | 1080 | verbose_llvm_cpu_features: bool = false, |
| 1080 | 1081 | debug_compiler_runtime_libs: bool = false, |
| 1081 | 1082 | debug_compile_errors: bool = false, |
| 1083 | debug_incremental: bool = false, | |
| 1082 | 1084 | /// Normally when you create a `Compilation`, Zig will automatically build |
| 1083 | 1085 | /// and link in required dependencies, such as compiler-rt and libc. When |
| 1084 | 1086 | /// building such dependencies themselves, this flag must be set to avoid |
| ... | ... | @@ -1508,6 +1510,7 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil |
| 1508 | 1510 | .test_name_prefix = options.test_name_prefix, |
| 1509 | 1511 | .debug_compiler_runtime_libs = options.debug_compiler_runtime_libs, |
| 1510 | 1512 | .debug_compile_errors = options.debug_compile_errors, |
| 1513 | .debug_incremental = options.debug_incremental, | |
| 1511 | 1514 | .libcxx_abi_version = options.libcxx_abi_version, |
| 1512 | 1515 | .root_name = root_name, |
| 1513 | 1516 | .sysroot = sysroot, |
| ... | ... | @@ -2141,7 +2144,6 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void |
| 2141 | 2144 | |
| 2142 | 2145 | if (comp.module) |module| { |
| 2143 | 2146 | module.compile_log_text.shrinkAndFree(gpa, 0); |
| 2144 | module.generation += 1; | |
| 2145 | 2147 | |
| 2146 | 2148 | // Make sure std.zig is inside the import_table. We unconditionally need |
| 2147 | 2149 | // it for start.zig. |
| ... | ... | @@ -2807,6 +2809,13 @@ const Header = extern struct { |
| 2807 | 2809 | limbs_len: u32, |
| 2808 | 2810 | string_bytes_len: u32, |
| 2809 | 2811 | tracked_insts_len: u32, |
| 2812 | src_hash_deps_len: u32, | |
| 2813 | decl_val_deps_len: u32, | |
| 2814 | namespace_deps_len: u32, | |
| 2815 | namespace_name_deps_len: u32, | |
| 2816 | first_dependency_len: u32, | |
| 2817 | dep_entries_len: u32, | |
| 2818 | free_dep_entries_len: u32, | |
| 2810 | 2819 | }, |
| 2811 | 2820 | }; |
| 2812 | 2821 | |
| ... | ... | @@ -2814,7 +2823,7 @@ const Header = extern struct { |
| 2814 | 2823 | /// saved, such as the target and most CLI flags. A cache hit will only occur |
| 2815 | 2824 | /// when subsequent compiler invocations use the same set of flags. |
| 2816 | 2825 | pub fn saveState(comp: *Compilation) !void { |
| 2817 | var bufs_list: [7]std.os.iovec_const = undefined; | |
| 2826 | var bufs_list: [19]std.os.iovec_const = undefined; | |
| 2818 | 2827 | var bufs_len: usize = 0; |
| 2819 | 2828 | |
| 2820 | 2829 | const lf = comp.bin_file orelse return; |
| ... | ... | @@ -2828,6 +2837,13 @@ pub fn saveState(comp: *Compilation) !void { |
| 2828 | 2837 | .limbs_len = @intCast(ip.limbs.items.len), |
| 2829 | 2838 | .string_bytes_len = @intCast(ip.string_bytes.items.len), |
| 2830 | 2839 | .tracked_insts_len = @intCast(ip.tracked_insts.count()), |
| 2840 | .src_hash_deps_len = @intCast(ip.src_hash_deps.count()), | |
| 2841 | .decl_val_deps_len = @intCast(ip.decl_val_deps.count()), | |
| 2842 | .namespace_deps_len = @intCast(ip.namespace_deps.count()), | |
| 2843 | .namespace_name_deps_len = @intCast(ip.namespace_name_deps.count()), | |
| 2844 | .first_dependency_len = @intCast(ip.first_dependency.count()), | |
| 2845 | .dep_entries_len = @intCast(ip.dep_entries.items.len), | |
| 2846 | .free_dep_entries_len = @intCast(ip.free_dep_entries.items.len), | |
| 2831 | 2847 | }, |
| 2832 | 2848 | }; |
| 2833 | 2849 | addBuf(&bufs_list, &bufs_len, mem.asBytes(&header)); |
| ... | ... | @@ -2838,6 +2854,20 @@ pub fn saveState(comp: *Compilation) !void { |
| 2838 | 2854 | addBuf(&bufs_list, &bufs_len, ip.string_bytes.items); |
| 2839 | 2855 | addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.tracked_insts.keys())); |
| 2840 | 2856 | |
| 2857 | addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.src_hash_deps.keys())); | |
| 2858 | addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.src_hash_deps.values())); | |
| 2859 | addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.decl_val_deps.keys())); | |
| 2860 | addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.decl_val_deps.values())); | |
| 2861 | addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.namespace_deps.keys())); | |
| 2862 | addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.namespace_deps.values())); | |
| 2863 | addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.namespace_name_deps.keys())); | |
| 2864 | addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.namespace_name_deps.values())); | |
| 2865 | ||
| 2866 | addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.first_dependency.keys())); | |
| 2867 | addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.first_dependency.values())); | |
| 2868 | addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.dep_entries.items)); | |
| 2869 | addBuf(&bufs_list, &bufs_len, mem.sliceAsBytes(ip.free_dep_entries.items)); | |
| 2870 | ||
| 2841 | 2871 | // TODO: compilation errors |
| 2842 | 2872 | // TODO: files |
| 2843 | 2873 | // TODO: namespaces |
| ... | ... | @@ -3463,9 +3493,7 @@ pub fn performAllTheWork( |
| 3463 | 3493 | |
| 3464 | 3494 | if (comp.module) |mod| { |
| 3465 | 3495 | try reportMultiModuleErrors(mod); |
| 3466 | } | |
| 3467 | ||
| 3468 | if (comp.module) |mod| { | |
| 3496 | try mod.flushRetryableFailures(); | |
| 3469 | 3497 | mod.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); |
| 3470 | 3498 | mod.sema_prog_node.activate(); |
| 3471 | 3499 | } |
| ... | ... | @@ -3486,6 +3514,17 @@ pub fn performAllTheWork( |
| 3486 | 3514 | try processOneJob(comp, work_item, main_progress_node); |
| 3487 | 3515 | continue; |
| 3488 | 3516 | } |
| 3517 | if (comp.module) |zcu| { | |
| 3518 | // If there's no work queued, check if there's anything outdated | |
| 3519 | // which we need to work on, and queue it if so. | |
| 3520 | if (try zcu.findOutdatedToAnalyze()) |outdated| { | |
| 3521 | switch (outdated.unwrap()) { | |
| 3522 | .decl => |decl| try comp.work_queue.writeItem(.{ .analyze_decl = decl }), | |
| 3523 | .func => |func| try comp.work_queue.writeItem(.{ .codegen_func = func }), | |
| 3524 | } | |
| 3525 | continue; | |
| 3526 | } | |
| 3527 | } | |
| 3489 | 3528 | break; |
| 3490 | 3529 | } |
| 3491 | 3530 | |
| ... | ... | @@ -3509,17 +3548,14 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v |
| 3509 | 3548 | switch (decl.analysis) { |
| 3510 | 3549 | .unreferenced => unreachable, |
| 3511 | 3550 | .in_progress => unreachable, |
| 3512 | .outdated => unreachable, | |
| 3513 | 3551 | |
| 3514 | 3552 | .file_failure, |
| 3515 | 3553 | .sema_failure, |
| 3516 | .liveness_failure, | |
| 3517 | 3554 | .codegen_failure, |
| 3518 | 3555 | .dependency_failure, |
| 3519 | .sema_failure_retryable, | |
| 3520 | 3556 | => return, |
| 3521 | 3557 | |
| 3522 | .complete, .codegen_failure_retryable => { | |
| 3558 | .complete => { | |
| 3523 | 3559 | const named_frame = tracy.namedFrame("codegen_decl"); |
| 3524 | 3560 | defer named_frame.end(); |
| 3525 | 3561 | |
| ... | ... | @@ -3554,17 +3590,15 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v |
| 3554 | 3590 | switch (decl.analysis) { |
| 3555 | 3591 | .unreferenced => unreachable, |
| 3556 | 3592 | .in_progress => unreachable, |
| 3557 | .outdated => unreachable, | |
| 3558 | 3593 | |
| 3559 | 3594 | .file_failure, |
| 3560 | 3595 | .sema_failure, |
| 3561 | 3596 | .dependency_failure, |
| 3562 | .sema_failure_retryable, | |
| 3563 | 3597 | => return, |
| 3564 | 3598 | |
| 3565 | 3599 | // emit-h only requires semantic analysis of the Decl to be complete, |
| 3566 | 3600 | // it does not depend on machine code generation to succeed. |
| 3567 | .liveness_failure, .codegen_failure, .codegen_failure_retryable, .complete => { | |
| 3601 | .codegen_failure, .complete => { | |
| 3568 | 3602 | const named_frame = tracy.namedFrame("emit_h_decl"); |
| 3569 | 3603 | defer named_frame.end(); |
| 3570 | 3604 | |
| ... | ... | @@ -3636,7 +3670,8 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v |
| 3636 | 3670 | "unable to update line number: {s}", |
| 3637 | 3671 | .{@errorName(err)}, |
| 3638 | 3672 | )); |
| 3639 | decl.analysis = .codegen_failure_retryable; | |
| 3673 | decl.analysis = .codegen_failure; | |
| 3674 | try module.retryable_failures.append(gpa, InternPool.Depender.wrap(.{ .decl = decl_index })); | |
| 3640 | 3675 | }; |
| 3641 | 3676 | }, |
| 3642 | 3677 | .analyze_mod => |pkg| { |
src/InternPool.zig+283-16| ... | ... | @@ -58,6 +58,38 @@ string_table: std.HashMapUnmanaged( |
| 58 | 58 | /// persists across incremental updates. |
| 59 | 59 | tracked_insts: std.AutoArrayHashMapUnmanaged(TrackedInst, void) = .{}, |
| 60 | 60 | |
| 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. | |
| 67 | src_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. | |
| 70 | decl_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. | |
| 74 | namespace_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. | |
| 77 | namespace_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. | |
| 82 | first_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. | |
| 88 | dep_entries: std.ArrayListUnmanaged(DepEntry) = .{}, | |
| 89 | /// Stores unused indices in `dep_entries` which can be reused without a full | |
| 90 | /// garbage collection pass. | |
| 91 | free_dep_entries: std.ArrayListUnmanaged(DepEntry.Index) = .{}, | |
| 92 | ||
| 61 | 93 | pub const TrackedInst = extern struct { |
| 62 | 94 | path_digest: Cache.BinDigest, |
| 63 | 95 | inst: Zir.Inst.Index, |
| ... | ... | @@ -70,6 +102,19 @@ pub const TrackedInst = extern struct { |
| 70 | 102 | pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) Zir.Inst.Index { |
| 71 | 103 | return ip.tracked_insts.keys()[@intFromEnum(i)].inst; |
| 72 | 104 | } |
| 105 | pub fn toOptional(i: TrackedInst.Index) Optional { | |
| 106 | return @enumFromInt(@intFromEnum(i)); | |
| 107 | } | |
| 108 | pub const Optional = enum(u32) { | |
| 109 | none = std.math.maxInt(u32), | |
| 110 | _, | |
| 111 | pub fn unwrap(opt: Optional) ?TrackedInst.Index { | |
| 112 | return switch (opt) { | |
| 113 | .none => null, | |
| 114 | _ => @enumFromInt(@intFromEnum(opt)), | |
| 115 | }; | |
| 116 | } | |
| 117 | }; | |
| 73 | 118 | }; |
| 74 | 119 | }; |
| 75 | 120 | |
| ... | ... | @@ -82,6 +127,202 @@ pub fn trackZir(ip: *InternPool, gpa: Allocator, file: *Module.File, inst: Zir.I |
| 82 | 127 | return @enumFromInt(gop.index); |
| 83 | 128 | } |
| 84 | 129 | |
| 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. | |
| 133 | pub 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 | ||
| 168 | pub const Dependee = union(enum) { | |
| 169 | src_hash: TrackedInst.Index, | |
| 170 | decl_val: DeclIndex, | |
| 171 | namespace: TrackedInst.Index, | |
| 172 | namespace_name: NamespaceNameKey, | |
| 173 | }; | |
| 174 | ||
| 175 | pub 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 | ||
| 201 | pub 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 | ||
| 212 | pub 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 | ||
| 232 | pub 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. | |
| 283 | pub 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 | ||
| 290 | pub 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 | ||
| 85 | 326 | const FieldMap = std.ArrayHashMapUnmanaged(void, void, std.array_hash_map.AutoContext(void), false); |
| 86 | 327 | |
| 87 | 328 | const builtin = @import("builtin"); |
| ... | ... | @@ -428,6 +669,7 @@ pub const Key = union(enum) { |
| 428 | 669 | decl: DeclIndex, |
| 429 | 670 | /// Represents the declarations inside this opaque. |
| 430 | 671 | namespace: NamespaceIndex, |
| 672 | zir_index: TrackedInst.Index.Optional, | |
| 431 | 673 | }; |
| 432 | 674 | |
| 433 | 675 | /// Although packed structs and non-packed structs are encoded differently, |
| ... | ... | @@ -440,7 +682,7 @@ pub const Key = union(enum) { |
| 440 | 682 | /// `none` when the struct has no declarations. |
| 441 | 683 | namespace: OptionalNamespaceIndex, |
| 442 | 684 | /// Index of the struct_decl ZIR instruction. |
| 443 | zir_index: TrackedInst.Index, | |
| 685 | zir_index: TrackedInst.Index.Optional, | |
| 444 | 686 | layout: std.builtin.Type.ContainerLayout, |
| 445 | 687 | field_names: NullTerminatedString.Slice, |
| 446 | 688 | field_types: Index.Slice, |
| ... | ... | @@ -684,7 +926,7 @@ pub const Key = union(enum) { |
| 684 | 926 | } |
| 685 | 927 | |
| 686 | 928 | /// Asserts the struct is not packed. |
| 687 | pub fn setZirIndex(s: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index) void { | |
| 929 | pub fn setZirIndex(s: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void { | |
| 688 | 930 | assert(s.layout != .Packed); |
| 689 | 931 | const field_index = std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?; |
| 690 | 932 | ip.extra.items[s.extra_index + field_index] = @intFromEnum(new_zir_index); |
| ... | ... | @@ -800,7 +1042,7 @@ pub const Key = union(enum) { |
| 800 | 1042 | flags: Tag.TypeUnion.Flags, |
| 801 | 1043 | /// The enum that provides the list of field names and values. |
| 802 | 1044 | enum_tag_ty: Index, |
| 803 | zir_index: TrackedInst.Index, | |
| 1045 | zir_index: TrackedInst.Index.Optional, | |
| 804 | 1046 | |
| 805 | 1047 | /// The returned pointer expires with any addition to the `InternPool`. |
| 806 | 1048 | pub fn flagsPtr(self: @This(), ip: *const InternPool) *Tag.TypeUnion.Flags { |
| ... | ... | @@ -889,6 +1131,7 @@ pub const Key = union(enum) { |
| 889 | 1131 | /// This is ignored by `get` but will be provided by `indexToKey` when |
| 890 | 1132 | /// a value map exists. |
| 891 | 1133 | values_map: OptionalMapIndex = .none, |
| 1134 | zir_index: TrackedInst.Index.Optional, | |
| 892 | 1135 | |
| 893 | 1136 | pub const TagMode = enum { |
| 894 | 1137 | /// The integer tag type was auto-numbered by zig. |
| ... | ... | @@ -953,6 +1196,7 @@ pub const Key = union(enum) { |
| 953 | 1196 | tag_mode: EnumType.TagMode, |
| 954 | 1197 | /// This may be updated via `setTagType` later. |
| 955 | 1198 | tag_ty: Index = .none, |
| 1199 | zir_index: TrackedInst.Index.Optional, | |
| 956 | 1200 | |
| 957 | 1201 | pub fn toEnumType(self: @This()) EnumType { |
| 958 | 1202 | return .{ |
| ... | ... | @@ -962,6 +1206,7 @@ pub const Key = union(enum) { |
| 962 | 1206 | .tag_mode = self.tag_mode, |
| 963 | 1207 | .names = .{ .start = 0, .len = 0 }, |
| 964 | 1208 | .values = .{ .start = 0, .len = 0 }, |
| 1209 | .zir_index = self.zir_index, | |
| 965 | 1210 | }; |
| 966 | 1211 | } |
| 967 | 1212 | |
| ... | ... | @@ -1909,7 +2154,7 @@ pub const UnionType = struct { |
| 1909 | 2154 | /// If this slice has length 0 it means all elements are `none`. |
| 1910 | 2155 | field_aligns: Alignment.Slice, |
| 1911 | 2156 | /// Index of the union_decl ZIR instruction. |
| 1912 | zir_index: TrackedInst.Index, | |
| 2157 | zir_index: TrackedInst.Index.Optional, | |
| 1913 | 2158 | /// Index into extra array of the `flags` field. |
| 1914 | 2159 | flags_index: u32, |
| 1915 | 2160 | /// Copied from `enum_tag_ty`. |
| ... | ... | @@ -2003,10 +2248,10 @@ pub const UnionType = struct { |
| 2003 | 2248 | } |
| 2004 | 2249 | |
| 2005 | 2250 | /// This does not mutate the field of UnionType. |
| 2006 | pub fn setZirIndex(self: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index) void { | |
| 2251 | pub fn setZirIndex(self: @This(), ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void { | |
| 2007 | 2252 | const flags_field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?; |
| 2008 | 2253 | const zir_index_field_index = std.meta.fieldIndex(Tag.TypeUnion, "zir_index").?; |
| 2009 | const ptr: *TrackedInst.Index = | |
| 2254 | const ptr: *TrackedInst.Index.Optional = | |
| 2010 | 2255 | @ptrCast(&ip.extra.items[self.flags_index - flags_field_index + zir_index_field_index]); |
| 2011 | 2256 | ptr.* = new_zir_index; |
| 2012 | 2257 | } |
| ... | ... | @@ -3099,7 +3344,7 @@ pub const Tag = enum(u8) { |
| 3099 | 3344 | namespace: NamespaceIndex, |
| 3100 | 3345 | /// The enum that provides the list of field names and values. |
| 3101 | 3346 | tag_ty: Index, |
| 3102 | zir_index: TrackedInst.Index, | |
| 3347 | zir_index: TrackedInst.Index.Optional, | |
| 3103 | 3348 | |
| 3104 | 3349 | pub const Flags = packed struct(u32) { |
| 3105 | 3350 | runtime_tag: UnionType.RuntimeTag, |
| ... | ... | @@ -3121,7 +3366,7 @@ pub const Tag = enum(u8) { |
| 3121 | 3366 | /// 2. init: Index for each fields_len // if tag is type_struct_packed_inits |
| 3122 | 3367 | pub const TypeStructPacked = struct { |
| 3123 | 3368 | decl: DeclIndex, |
| 3124 | zir_index: TrackedInst.Index, | |
| 3369 | zir_index: TrackedInst.Index.Optional, | |
| 3125 | 3370 | fields_len: u32, |
| 3126 | 3371 | namespace: OptionalNamespaceIndex, |
| 3127 | 3372 | backing_int_ty: Index, |
| ... | ... | @@ -3168,7 +3413,7 @@ pub const Tag = enum(u8) { |
| 3168 | 3413 | /// 7. field_offset: u32 // for each field in declared order, undef until layout_resolved |
| 3169 | 3414 | pub const TypeStruct = struct { |
| 3170 | 3415 | decl: DeclIndex, |
| 3171 | zir_index: TrackedInst.Index, | |
| 3416 | zir_index: TrackedInst.Index.Optional, | |
| 3172 | 3417 | fields_len: u32, |
| 3173 | 3418 | flags: Flags, |
| 3174 | 3419 | size: u32, |
| ... | ... | @@ -3238,6 +3483,11 @@ pub const FuncAnalysis = packed struct(u32) { |
| 3238 | 3483 | /// This function might be OK but it depends on another Decl which did not |
| 3239 | 3484 | /// successfully complete semantic analysis. |
| 3240 | 3485 | dependency_failure, |
| 3486 | /// There will be a corresponding ErrorMsg in Module.failed_decls. | |
| 3487 | /// Indicates that semantic analysis succeeded, but code generation for | |
| 3488 | /// this function failed. | |
| 3489 | codegen_failure, | |
| 3490 | /// Semantic analysis and code generation of this function succeeded. | |
| 3241 | 3491 | success, |
| 3242 | 3492 | }; |
| 3243 | 3493 | }; |
| ... | ... | @@ -3523,6 +3773,7 @@ pub const EnumExplicit = struct { |
| 3523 | 3773 | /// If this is `none`, it means the trailing tag values are absent because |
| 3524 | 3774 | /// they are auto-numbered. |
| 3525 | 3775 | values_map: OptionalMapIndex, |
| 3776 | zir_index: TrackedInst.Index.Optional, | |
| 3526 | 3777 | }; |
| 3527 | 3778 | |
| 3528 | 3779 | /// Trailing: |
| ... | ... | @@ -3538,6 +3789,7 @@ pub const EnumAuto = struct { |
| 3538 | 3789 | fields_len: u32, |
| 3539 | 3790 | /// Maps field names to declaration index. |
| 3540 | 3791 | names_map: MapIndex, |
| 3792 | zir_index: TrackedInst.Index.Optional, | |
| 3541 | 3793 | }; |
| 3542 | 3794 | |
| 3543 | 3795 | pub const PackedU64 = packed struct(u64) { |
| ... | ... | @@ -3759,6 +4011,16 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void { |
| 3759 | 4011 | |
| 3760 | 4012 | ip.tracked_insts.deinit(gpa); |
| 3761 | 4013 | |
| 4014 | ip.src_hash_deps.deinit(gpa); | |
| 4015 | ip.decl_val_deps.deinit(gpa); | |
| 4016 | ip.namespace_deps.deinit(gpa); | |
| 4017 | ip.namespace_name_deps.deinit(gpa); | |
| 4018 | ||
| 4019 | ip.first_dependency.deinit(gpa); | |
| 4020 | ||
| 4021 | ip.dep_entries.deinit(gpa); | |
| 4022 | ip.free_dep_entries.deinit(gpa); | |
| 4023 | ||
| 3762 | 4024 | ip.* = undefined; |
| 3763 | 4025 | } |
| 3764 | 4026 | |
| ... | ... | @@ -3885,6 +4147,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 3885 | 4147 | .tag_mode = .auto, |
| 3886 | 4148 | .names_map = enum_auto.data.names_map.toOptional(), |
| 3887 | 4149 | .values_map = .none, |
| 4150 | .zir_index = enum_auto.data.zir_index, | |
| 3888 | 4151 | } }; |
| 3889 | 4152 | }, |
| 3890 | 4153 | .type_enum_explicit => ip.indexToKeyEnum(data, .explicit), |
| ... | ... | @@ -4493,6 +4756,7 @@ fn indexToKeyEnum(ip: *const InternPool, data: u32, tag_mode: Key.EnumType.TagMo |
| 4493 | 4756 | .tag_mode = tag_mode, |
| 4494 | 4757 | .names_map = enum_explicit.data.names_map.toOptional(), |
| 4495 | 4758 | .values_map = enum_explicit.data.values_map, |
| 4759 | .zir_index = enum_explicit.data.zir_index, | |
| 4496 | 4760 | } }; |
| 4497 | 4761 | } |
| 4498 | 4762 | |
| ... | ... | @@ -5329,7 +5593,7 @@ pub const UnionTypeInit = struct { |
| 5329 | 5593 | flags: Tag.TypeUnion.Flags, |
| 5330 | 5594 | decl: DeclIndex, |
| 5331 | 5595 | namespace: NamespaceIndex, |
| 5332 | zir_index: TrackedInst.Index, | |
| 5596 | zir_index: TrackedInst.Index.Optional, | |
| 5333 | 5597 | fields_len: u32, |
| 5334 | 5598 | enum_tag_ty: Index, |
| 5335 | 5599 | /// May have length 0 which leaves the values unset until later. |
| ... | ... | @@ -5401,7 +5665,7 @@ pub const StructTypeInit = struct { |
| 5401 | 5665 | decl: DeclIndex, |
| 5402 | 5666 | namespace: OptionalNamespaceIndex, |
| 5403 | 5667 | layout: std.builtin.Type.ContainerLayout, |
| 5404 | zir_index: TrackedInst.Index, | |
| 5668 | zir_index: TrackedInst.Index.Optional, | |
| 5405 | 5669 | fields_len: u32, |
| 5406 | 5670 | known_non_opv: bool, |
| 5407 | 5671 | requires_comptime: RequiresComptime, |
| ... | ... | @@ -5923,7 +6187,6 @@ pub const GetFuncInstanceKey = struct { |
| 5923 | 6187 | is_noinline: bool, |
| 5924 | 6188 | generic_owner: Index, |
| 5925 | 6189 | inferred_error_set: bool, |
| 5926 | generation: u32, | |
| 5927 | 6190 | }; |
| 5928 | 6191 | |
| 5929 | 6192 | pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey) Allocator.Error!Index { |
| ... | ... | @@ -5990,7 +6253,6 @@ pub fn getFuncInstance(ip: *InternPool, gpa: Allocator, arg: GetFuncInstanceKey) |
| 5990 | 6253 | generic_owner, |
| 5991 | 6254 | func_index, |
| 5992 | 6255 | func_extra_index, |
| 5993 | arg.generation, | |
| 5994 | 6256 | func_ty, |
| 5995 | 6257 | arg.section, |
| 5996 | 6258 | ); |
| ... | ... | @@ -6122,7 +6384,6 @@ pub fn getFuncInstanceIes( |
| 6122 | 6384 | generic_owner, |
| 6123 | 6385 | func_index, |
| 6124 | 6386 | func_extra_index, |
| 6125 | arg.generation, | |
| 6126 | 6387 | func_ty, |
| 6127 | 6388 | arg.section, |
| 6128 | 6389 | ); |
| ... | ... | @@ -6134,7 +6395,6 @@ fn finishFuncInstance( |
| 6134 | 6395 | generic_owner: Index, |
| 6135 | 6396 | func_index: Index, |
| 6136 | 6397 | func_extra_index: u32, |
| 6137 | generation: u32, | |
| 6138 | 6398 | func_ty: Index, |
| 6139 | 6399 | section: OptionalNullTerminatedString, |
| 6140 | 6400 | ) Allocator.Error!Index { |
| ... | ... | @@ -6154,7 +6414,6 @@ fn finishFuncInstance( |
| 6154 | 6414 | .analysis = .complete, |
| 6155 | 6415 | .zir_decl_index = fn_owner_decl.zir_decl_index, |
| 6156 | 6416 | .src_scope = fn_owner_decl.src_scope, |
| 6157 | .generation = generation, | |
| 6158 | 6417 | .is_pub = fn_owner_decl.is_pub, |
| 6159 | 6418 | .is_exported = fn_owner_decl.is_exported, |
| 6160 | 6419 | .alive = true, |
| ... | ... | @@ -6264,6 +6523,7 @@ fn getIncompleteEnumAuto( |
| 6264 | 6523 | .int_tag_type = int_tag_type, |
| 6265 | 6524 | .names_map = names_map, |
| 6266 | 6525 | .fields_len = enum_type.fields_len, |
| 6526 | .zir_index = enum_type.zir_index, | |
| 6267 | 6527 | }); |
| 6268 | 6528 | |
| 6269 | 6529 | ip.items.appendAssumeCapacity(.{ |
| ... | ... | @@ -6314,6 +6574,7 @@ fn getIncompleteEnumExplicit( |
| 6314 | 6574 | .fields_len = enum_type.fields_len, |
| 6315 | 6575 | .names_map = names_map, |
| 6316 | 6576 | .values_map = values_map, |
| 6577 | .zir_index = enum_type.zir_index, | |
| 6317 | 6578 | }); |
| 6318 | 6579 | |
| 6319 | 6580 | ip.items.appendAssumeCapacity(.{ |
| ... | ... | @@ -6339,6 +6600,7 @@ pub const GetEnumInit = struct { |
| 6339 | 6600 | names: []const NullTerminatedString, |
| 6340 | 6601 | values: []const Index, |
| 6341 | 6602 | tag_mode: Key.EnumType.TagMode, |
| 6603 | zir_index: TrackedInst.Index.Optional, | |
| 6342 | 6604 | }; |
| 6343 | 6605 | |
| 6344 | 6606 | pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Error!Index { |
| ... | ... | @@ -6355,6 +6617,7 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro |
| 6355 | 6617 | .tag_mode = undefined, |
| 6356 | 6618 | .names_map = undefined, |
| 6357 | 6619 | .values_map = undefined, |
| 6620 | .zir_index = undefined, | |
| 6358 | 6621 | }, |
| 6359 | 6622 | }, adapter); |
| 6360 | 6623 | if (gop.found_existing) return @enumFromInt(gop.index); |
| ... | ... | @@ -6380,6 +6643,7 @@ pub fn getEnum(ip: *InternPool, gpa: Allocator, ini: GetEnumInit) Allocator.Erro |
| 6380 | 6643 | .int_tag_type = ini.tag_ty, |
| 6381 | 6644 | .names_map = names_map, |
| 6382 | 6645 | .fields_len = fields_len, |
| 6646 | .zir_index = ini.zir_index, | |
| 6383 | 6647 | }), |
| 6384 | 6648 | }); |
| 6385 | 6649 | ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names)); |
| ... | ... | @@ -6416,6 +6680,7 @@ pub fn finishGetEnum( |
| 6416 | 6680 | .fields_len = fields_len, |
| 6417 | 6681 | .names_map = names_map, |
| 6418 | 6682 | .values_map = values_map, |
| 6683 | .zir_index = ini.zir_index, | |
| 6419 | 6684 | }), |
| 6420 | 6685 | }); |
| 6421 | 6686 | ip.extra.appendSliceAssumeCapacity(@ptrCast(ini.names)); |
| ... | ... | @@ -6507,6 +6772,7 @@ fn addExtraAssumeCapacity(ip: *InternPool, extra: anytype) u32 { |
| 6507 | 6772 | OptionalNullTerminatedString, |
| 6508 | 6773 | Tag.TypePointer.VectorIndex, |
| 6509 | 6774 | TrackedInst.Index, |
| 6775 | TrackedInst.Index.Optional, | |
| 6510 | 6776 | => @intFromEnum(@field(extra, field.name)), |
| 6511 | 6777 | |
| 6512 | 6778 | u32, |
| ... | ... | @@ -6583,6 +6849,7 @@ fn extraDataTrail(ip: *const InternPool, comptime T: type, index: usize) struct |
| 6583 | 6849 | OptionalNullTerminatedString, |
| 6584 | 6850 | Tag.TypePointer.VectorIndex, |
| 6585 | 6851 | TrackedInst.Index, |
| 6852 | TrackedInst.Index.Optional, | |
| 6586 | 6853 | => @enumFromInt(int32), |
| 6587 | 6854 | |
| 6588 | 6855 | u32, |
src/Module.zig+606-222| ... | ... | @@ -144,10 +144,26 @@ global_error_set: GlobalErrorSet = .{}, |
| 144 | 144 | /// Maximum amount of distinct error values, set by --error-limit |
| 145 | 145 | error_limit: ErrorInt, |
| 146 | 146 | |
| 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. | |
| 150 | generation: u32 = 0, | |
| 147 | /// Value is the number of PO or outdated Decls which this Depender depends on. | |
| 148 | potentially_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. | |
| 151 | outdated: 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. | |
| 155 | outdated_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. | |
| 161 | outdated_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. | |
| 166 | retryable_failures: std.ArrayListUnmanaged(InternPool.Depender) = .{}, | |
| 151 | 167 | |
| 152 | 168 | stage1_flags: packed struct { |
| 153 | 169 | have_winmain: bool = false, |
| ... | ... | @@ -364,21 +380,14 @@ pub const Decl = struct { |
| 364 | 380 | alignment: Alignment, |
| 365 | 381 | /// Populated when `has_tv`. |
| 366 | 382 | @"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. | |
| 371 | 386 | src_namespace: Namespace.Index, |
| 372 | 387 | |
| 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. | |
| 376 | 389 | src_scope: CaptureScope.Index, |
| 377 | 390 | |
| 378 | /// An integer that can be checked against the corresponding incrementing | |
| 379 | /// generation field of Module. This is used to determine whether `complete` status | |
| 380 | /// represents pre- or post- re-analysis. | |
| 381 | generation: u32, | |
| 382 | 391 | /// The AST node index of this declaration. |
| 383 | 392 | /// Must be recomputed when the corresponding source file is modified. |
| 384 | 393 | src_node: Ast.Node.Index, |
| ... | ... | @@ -404,31 +413,20 @@ pub const Decl = struct { |
| 404 | 413 | /// The file corresponding to this Decl had a parse error or ZIR error. |
| 405 | 414 | /// There will be a corresponding ErrorMsg in Module.failed_files. |
| 406 | 415 | 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. | |
| 409 | 418 | dependency_failure, |
| 410 | 419 | /// Semantic analysis failure. |
| 411 | 420 | /// There will be a corresponding ErrorMsg in Module.failed_decls. |
| 412 | 421 | sema_failure, |
| 413 | 422 | /// There will be a corresponding ErrorMsg in Module.failed_decls. |
| 414 | /// This indicates the failure was something like running out of disk space, | |
| 415 | /// and attempting semantic analysis again may succeed. | |
| 416 | sema_failure_retryable, | |
| 417 | /// There will be a corresponding ErrorMsg in Module.failed_decls. | |
| 418 | liveness_failure, | |
| 419 | /// There will be a corresponding ErrorMsg in Module.failed_decls. | |
| 420 | 423 | 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. | |
| 428 | 429 | complete, |
| 429 | /// A Module update is in progress, and this Decl has been flagged as being known | |
| 430 | /// to require re-analysis. | |
| 431 | outdated, | |
| 432 | 430 | }, |
| 433 | 431 | /// Whether `typed_value`, `align`, `linksection` and `addrspace` are populated. |
| 434 | 432 | has_tv: bool, |
| ... | ... | @@ -680,14 +678,6 @@ pub const Decl = struct { |
| 680 | 678 | return mod.namespacePtr(decl.src_namespace).file_scope; |
| 681 | 679 | } |
| 682 | 680 | |
| 683 | pub fn removeDependant(decl: *Decl, other: Decl.Index) void { | |
| 684 | assert(decl.dependants.swapRemove(other)); | |
| 685 | } | |
| 686 | ||
| 687 | pub fn removeDependency(decl: *Decl, other: Decl.Index) void { | |
| 688 | assert(decl.dependencies.swapRemove(other)); | |
| 689 | } | |
| 690 | ||
| 691 | 681 | pub fn getExternDecl(decl: Decl, mod: *Module) OptionalIndex { |
| 692 | 682 | assert(decl.has_tv); |
| 693 | 683 | return switch (mod.intern_pool.indexToKey(decl.val.toIntern())) { |
| ... | ... | @@ -734,8 +724,7 @@ pub const Namespace = struct { |
| 734 | 724 | file_scope: *File, |
| 735 | 725 | /// Will be a struct, enum, union, or opaque. |
| 736 | 726 | 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. | |
| 739 | 728 | /// Declaration order is preserved via entry order. |
| 740 | 729 | /// These are only declarations named directly by the AST; anonymous |
| 741 | 730 | /// declarations are not stored here. |
| ... | ... | @@ -838,14 +827,6 @@ pub const File = struct { |
| 838 | 827 | /// undefined until `zir_loaded == true`. |
| 839 | 828 | path_digest: Cache.BinDigest = undefined, |
| 840 | 829 | |
| 841 | /// Used by change detection algorithm, after astgen, contains the | |
| 842 | /// set of decls that existed in the previous ZIR but not in the new one. | |
| 843 | deleted_decls: ArrayListUnmanaged(Decl.Index) = .{}, | |
| 844 | /// Used by change detection algorithm, after astgen, contains the | |
| 845 | /// set of decls that existed both in the previous ZIR and in the new one, | |
| 846 | /// but their source code has been modified. | |
| 847 | outdated_decls: ArrayListUnmanaged(Decl.Index) = .{}, | |
| 848 | ||
| 849 | 830 | /// The most recent successful ZIR for this file, with no errors. |
| 850 | 831 | /// This is only populated when a previously successful ZIR |
| 851 | 832 | /// newly introduces compile errors during an update. When ZIR is |
| ... | ... | @@ -898,8 +879,6 @@ pub const File = struct { |
| 898 | 879 | gpa.free(file.sub_file_path); |
| 899 | 880 | file.unload(gpa); |
| 900 | 881 | } |
| 901 | file.deleted_decls.deinit(gpa); | |
| 902 | file.outdated_decls.deinit(gpa); | |
| 903 | 882 | file.references.deinit(gpa); |
| 904 | 883 | if (file.root_decl.unwrap()) |root_decl| { |
| 905 | 884 | mod.destroyDecl(root_decl); |
| ... | ... | @@ -2498,6 +2477,12 @@ pub fn deinit(zcu: *Zcu) void { |
| 2498 | 2477 | |
| 2499 | 2478 | zcu.global_error_set.deinit(gpa); |
| 2500 | 2479 | |
| 2480 | zcu.potentially_outdated.deinit(gpa); | |
| 2481 | zcu.outdated.deinit(gpa); | |
| 2482 | zcu.outdated_ready.deinit(gpa); | |
| 2483 | zcu.outdated_file_root.deinit(gpa); | |
| 2484 | zcu.retryable_failures.deinit(gpa); | |
| 2485 | ||
| 2501 | 2486 | zcu.test_functions.deinit(gpa); |
| 2502 | 2487 | |
| 2503 | 2488 | for (zcu.global_assembly.values()) |s| { |
| ... | ... | @@ -2856,27 +2841,20 @@ pub fn astGenFile(mod: *Module, file: *File) !void { |
| 2856 | 2841 | } |
| 2857 | 2842 | |
| 2858 | 2843 | if (file.prev_zir) |prev_zir| { |
| 2859 | // Iterate over all Namespace objects contained within this File, looking at the | |
| 2860 | // previous and new ZIR together and update the references to point | |
| 2861 | // to the new one. For example, Decl name, Decl zir_decl_index, and Namespace | |
| 2862 | // decl_table keys need to get updated to point to the new memory, even if the | |
| 2863 | // underlying source code is unchanged. | |
| 2864 | // We do not need to hold any locks at this time because all the Decl and Namespace | |
| 2865 | // objects being touched are specific to this File, and the only other concurrent | |
| 2866 | // tasks are touching other File objects. | |
| 2867 | 2844 | try updateZirRefs(mod, file, prev_zir.*); |
| 2868 | // At this point, `file.outdated_decls` and `file.deleted_decls` are populated, | |
| 2869 | // and semantic analysis will deal with them properly. | |
| 2870 | 2845 | // No need to keep previous ZIR. |
| 2871 | 2846 | prev_zir.deinit(gpa); |
| 2872 | 2847 | gpa.destroy(prev_zir); |
| 2873 | 2848 | 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, {}); | |
| 2880 | 2858 | } |
| 2881 | 2859 | } |
| 2882 | 2860 | |
| ... | ... | @@ -2950,25 +2928,347 @@ fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_file: std.fs.File) |
| 2950 | 2928 | return zir; |
| 2951 | 2929 | } |
| 2952 | 2930 | |
| 2931 | /// This is called from the AstGen thread pool, so must acquire | |
| 2932 | /// the Compilation mutex when acting on shared state. | |
| 2953 | 2933 | fn updateZirRefs(zcu: *Module, file: *File, old_zir: Zir) !void { |
| 2954 | 2934 | const gpa = zcu.gpa; |
| 2935 | const new_zir = file.zir; | |
| 2955 | 2936 | |
| 2956 | 2937 | var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{}; |
| 2957 | 2938 | defer inst_map.deinit(gpa); |
| 2958 | 2939 | |
| 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); | |
| 2960 | 2944 | |
| 2961 | 2945 | // TODO: this should be done after all AstGen workers complete, to avoid |
| 2962 | 2946 | // iterating over this full set for every updated file. |
| 2963 | for (zcu.intern_pool.tracked_insts.keys()) |*ti| { | |
| 2947 | for (zcu.intern_pool.tracked_insts.keys(), 0..) |*ti, idx_raw| { | |
| 2948 | const ti_idx: InternPool.TrackedInst.Index = @enumFromInt(idx_raw); | |
| 2964 | 2949 | if (!std.mem.eql(u8, &ti.path_digest, &file.path_digest)) continue; |
| 2950 | const old_inst = ti.inst; | |
| 2965 | 2951 | 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 }); | |
| 2967 | 2957 | continue; |
| 2968 | 2958 | }; |
| 2959 | ||
| 2960 | if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: { | |
| 2961 | if (new_zir.getAssociatedSrcHash(ti.inst)) |new_hash| { | |
| 2962 | if (std.zig.srcHashEql(old_hash, new_hash)) { | |
| 2963 | break :hash_changed; | |
| 2964 | } | |
| 2965 | log.debug("hash for (%{d} -> %{d}) changed: {} -> {}", .{ | |
| 2966 | old_inst, | |
| 2967 | ti.inst, | |
| 2968 | std.fmt.fmtSliceHexLower(&old_hash), | |
| 2969 | std.fmt.fmtSliceHexLower(&new_hash), | |
| 2970 | }); | |
| 2971 | } | |
| 2972 | // The source hash associated with this instruction changed - invalidate relevant dependencies. | |
| 2973 | zcu.comp.mutex.lock(); | |
| 2974 | defer zcu.comp.mutex.unlock(); | |
| 2975 | try zcu.markDependeeOutdated(.{ .src_hash = ti_idx }); | |
| 2976 | } | |
| 2977 | ||
| 2978 | // If this is a `struct_decl` etc, we must invalidate any outdated namespace dependencies. | |
| 2979 | const has_namespace = switch (old_tag[@intFromEnum(old_inst)]) { | |
| 2980 | .extended => switch (old_data[@intFromEnum(old_inst)].extended.opcode) { | |
| 2981 | .struct_decl, .union_decl, .opaque_decl, .enum_decl => true, | |
| 2982 | else => false, | |
| 2983 | }, | |
| 2984 | else => false, | |
| 2985 | }; | |
| 2986 | if (!has_namespace) continue; | |
| 2987 | ||
| 2988 | var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{}; | |
| 2989 | defer old_names.deinit(zcu.gpa); | |
| 2990 | { | |
| 2991 | var it = old_zir.declIterator(old_inst); | |
| 2992 | while (it.next()) |decl_inst| { | |
| 2993 | const decl_name = old_zir.getDeclaration(decl_inst)[0].name; | |
| 2994 | switch (decl_name) { | |
| 2995 | .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue, | |
| 2996 | _ => if (decl_name.isNamedTest(old_zir)) continue, | |
| 2997 | } | |
| 2998 | const name_zir = decl_name.toString(old_zir).?; | |
| 2999 | const name_ip = try zcu.intern_pool.getOrPutString( | |
| 3000 | zcu.gpa, | |
| 3001 | old_zir.nullTerminatedString(name_zir), | |
| 3002 | ); | |
| 3003 | try old_names.put(zcu.gpa, name_ip, {}); | |
| 3004 | } | |
| 3005 | } | |
| 3006 | var any_change = false; | |
| 3007 | { | |
| 3008 | var it = new_zir.declIterator(ti.inst); | |
| 3009 | while (it.next()) |decl_inst| { | |
| 3010 | const decl_name = old_zir.getDeclaration(decl_inst)[0].name; | |
| 3011 | switch (decl_name) { | |
| 3012 | .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue, | |
| 3013 | _ => if (decl_name.isNamedTest(old_zir)) continue, | |
| 3014 | } | |
| 3015 | const name_zir = decl_name.toString(old_zir).?; | |
| 3016 | const name_ip = try zcu.intern_pool.getOrPutString( | |
| 3017 | zcu.gpa, | |
| 3018 | old_zir.nullTerminatedString(name_zir), | |
| 3019 | ); | |
| 3020 | if (!old_names.swapRemove(name_ip)) continue; | |
| 3021 | // Name added | |
| 3022 | any_change = true; | |
| 3023 | zcu.comp.mutex.lock(); | |
| 3024 | defer zcu.comp.mutex.unlock(); | |
| 3025 | try zcu.markDependeeOutdated(.{ .namespace_name = .{ | |
| 3026 | .namespace = ti_idx, | |
| 3027 | .name = name_ip, | |
| 3028 | } }); | |
| 3029 | } | |
| 3030 | } | |
| 3031 | // The only elements remaining in `old_names` now are any names which were removed. | |
| 3032 | for (old_names.keys()) |name_ip| { | |
| 3033 | any_change = true; | |
| 3034 | zcu.comp.mutex.lock(); | |
| 3035 | defer zcu.comp.mutex.unlock(); | |
| 3036 | try zcu.markDependeeOutdated(.{ .namespace_name = .{ | |
| 3037 | .namespace = ti_idx, | |
| 3038 | .name = name_ip, | |
| 3039 | } }); | |
| 3040 | } | |
| 3041 | ||
| 3042 | if (any_change) { | |
| 3043 | zcu.comp.mutex.lock(); | |
| 3044 | defer zcu.comp.mutex.unlock(); | |
| 3045 | try zcu.markDependeeOutdated(.{ .namespace = ti_idx }); | |
| 3046 | } | |
| 2969 | 3047 | } |
| 2970 | 3048 | } |
| 2971 | 3049 | |
| 3050 | pub 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 | ||
| 3080 | fn 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. | |
| 3113 | fn 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 | ||
| 3141 | pub 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. | |
| 3251 | pub 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 | ||
| 2972 | 3272 | pub fn mapOldZirToNew( |
| 2973 | 3273 | gpa: Allocator, |
| 2974 | 3274 | old_zir: Zir, |
| ... | ... | @@ -3096,7 +3396,7 @@ pub fn mapOldZirToNew( |
| 3096 | 3396 | } |
| 3097 | 3397 | } |
| 3098 | 3398 | |
| 3099 | /// This ensures that the Decl will have a Type and Value populated. | |
| 3399 | /// This ensures that the Decl will have an up-to-date Type and Value populated. | |
| 3100 | 3400 | /// However the resolution status of the Type may not be fully resolved. |
| 3101 | 3401 | /// For example an inferred error set is not resolved until after `analyzeFnBody`. |
| 3102 | 3402 | /// is called. |
| ... | ... | @@ -3106,40 +3406,57 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 3106 | 3406 | |
| 3107 | 3407 | const decl = mod.declPtr(decl_index); |
| 3108 | 3408 | |
| 3109 | const subsequent_analysis = switch (decl.analysis) { | |
| 3409 | // Determine whether or not this Decl is outdated, i.e. requires re-analysis | |
| 3410 | // even if `complete`. If a Decl is PO, we pessismistically assume that it | |
| 3411 | // *does* require re-analysis, to ensure that the Decl is definitely | |
| 3412 | // up-to-date when this function returns. | |
| 3413 | ||
| 3414 | // If analysis occurs in a poor order, this could result in over-analysis. | |
| 3415 | // We do our best to avoid this by the other dependency logic in this file | |
| 3416 | // which tries to limit re-analysis to Decls whose previously listed | |
| 3417 | // dependencies are all up-to-date. | |
| 3418 | ||
| 3419 | const decl_as_depender = InternPool.Depender.wrap(.{ .decl = decl_index }); | |
| 3420 | const was_outdated = mod.outdated.swapRemove(decl_as_depender) or | |
| 3421 | mod.potentially_outdated.swapRemove(decl_as_depender); | |
| 3422 | ||
| 3423 | if (was_outdated) { | |
| 3424 | _ = mod.outdated_ready.swapRemove(decl_as_depender); | |
| 3425 | } | |
| 3426 | ||
| 3427 | switch (decl.analysis) { | |
| 3110 | 3428 | .in_progress => unreachable, |
| 3111 | 3429 | |
| 3112 | .file_failure, | |
| 3430 | .file_failure => return error.AnalysisFail, | |
| 3431 | ||
| 3113 | 3432 | .sema_failure, |
| 3114 | .sema_failure_retryable, | |
| 3115 | .liveness_failure, | |
| 3116 | .codegen_failure, | |
| 3117 | 3433 | .dependency_failure, |
| 3118 | .codegen_failure_retryable, | |
| 3119 | => return error.AnalysisFail, | |
| 3120 | ||
| 3121 | .complete => return, | |
| 3434 | .codegen_failure, | |
| 3435 | => if (!was_outdated) return error.AnalysisFail, | |
| 3122 | 3436 | |
| 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, | |
| 3128 | 3438 | |
| 3129 | break :blk true; | |
| 3130 | }, | |
| 3439 | .unreferenced => {}, | |
| 3440 | } | |
| 3131 | 3441 | |
| 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 | } | |
| 3134 | 3448 | |
| 3135 | 3449 | var decl_prog_node = mod.sema_prog_node.start("", 0); |
| 3136 | 3450 | decl_prog_node.activate(); |
| 3137 | 3451 | defer decl_prog_node.end(); |
| 3138 | 3452 | |
| 3139 | const type_changed = blk: { | |
| 3453 | const sema_result: SemaDeclResult = blk: { | |
| 3140 | 3454 | if (decl.zir_decl_index == .none and !mod.declIsRoot(decl_index)) { |
| 3141 | 3455 | // 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 | }; | |
| 3143 | 3460 | } |
| 3144 | 3461 | |
| 3145 | 3462 | break :blk mod.semaDecl(decl_index) catch |err| switch (err) { |
| ... | ... | @@ -3155,8 +3472,9 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 3155 | 3472 | error.NeededSourceLocation => unreachable, |
| 3156 | 3473 | error.GenericPoison => unreachable, |
| 3157 | 3474 | else => |e| { |
| 3158 | decl.analysis = .sema_failure_retryable; | |
| 3475 | decl.analysis = .sema_failure; | |
| 3159 | 3476 | try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1); |
| 3477 | try mod.retryable_failures.append(mod.gpa, InternPool.Depender.wrap(.{ .decl = decl_index })); | |
| 3160 | 3478 | mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( |
| 3161 | 3479 | mod.gpa, |
| 3162 | 3480 | decl.srcLoc(mod), |
| ... | ... | @@ -3168,9 +3486,18 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 3168 | 3486 | }; |
| 3169 | 3487 | }; |
| 3170 | 3488 | |
| 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 | } | |
| 3174 | 3501 | } |
| 3175 | 3502 | } |
| 3176 | 3503 | |
| ... | ... | @@ -3186,119 +3513,129 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError |
| 3186 | 3513 | switch (decl.analysis) { |
| 3187 | 3514 | .unreferenced => unreachable, |
| 3188 | 3515 | .in_progress => unreachable, |
| 3189 | .outdated => unreachable, | |
| 3516 | ||
| 3517 | .codegen_failure => unreachable, // functions do not perform constant value generation | |
| 3190 | 3518 | |
| 3191 | 3519 | .file_failure, |
| 3192 | 3520 | .sema_failure, |
| 3193 | .liveness_failure, | |
| 3194 | .codegen_failure, | |
| 3195 | 3521 | .dependency_failure, |
| 3196 | .sema_failure_retryable, | |
| 3197 | 3522 | => return error.AnalysisFail, |
| 3198 | 3523 | |
| 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 | } | |
| 3207 | 3526 | |
| 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); | |
| 3209 | 3530 | |
| 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 | } | |
| 3213 | 3534 | |
| 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 | } | |
| 3227 | 3545 | |
| 3228 | const comp = zcu.comp; | |
| 3546 | const gpa = zcu.gpa; | |
| 3229 | 3547 | |
| 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(); | |
| 3232 | 3551 | |
| 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; | |
| 3235 | 3559 | } |
| 3560 | return error.AnalysisFail; | |
| 3561 | }, | |
| 3562 | error.OutOfMemory => return error.OutOfMemory, | |
| 3563 | }; | |
| 3564 | defer air.deinit(gpa); | |
| 3236 | 3565 | |
| 3237 | var liveness = try Liveness.analyze(gpa, air, ip); | |
| 3238 | defer liveness.deinit(gpa); | |
| 3566 | const comp = zcu.comp; | |
| 3239 | 3567 | |
| 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); | |
| 3246 | 3570 | |
| 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 | } | |
| 3274 | 3574 | |
| 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 | }; | |
| 3302 | 3639 | } |
| 3303 | 3640 | } |
| 3304 | 3641 | |
| ... | ... | @@ -3318,18 +3655,14 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index) |
| 3318 | 3655 | switch (decl.analysis) { |
| 3319 | 3656 | .unreferenced => unreachable, |
| 3320 | 3657 | .in_progress => unreachable, |
| 3321 | .outdated => unreachable, | |
| 3322 | 3658 | |
| 3323 | 3659 | .file_failure, |
| 3324 | 3660 | .sema_failure, |
| 3325 | .liveness_failure, | |
| 3326 | 3661 | .codegen_failure, |
| 3327 | 3662 | .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. | |
| 3333 | 3666 | => return, |
| 3334 | 3667 | |
| 3335 | 3668 | .complete => {}, |
| ... | ... | @@ -3337,14 +3670,21 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index) |
| 3337 | 3670 | |
| 3338 | 3671 | assert(decl.has_tv); |
| 3339 | 3672 | |
| 3673 | const func_as_depender = InternPool.Depender.wrap(.{ .func = func_index }); | |
| 3674 | const is_outdated = mod.outdated.contains(func_as_depender) or | |
| 3675 | mod.potentially_outdated.contains(func_as_depender); | |
| 3676 | ||
| 3340 | 3677 | switch (func.analysis(ip).state) { |
| 3341 | 3678 | .none => {}, |
| 3342 | 3679 | .queued => return, |
| 3343 | 3680 | // As above, we don't need to forward errors here. |
| 3344 | .sema_failure, .dependency_failure => return, | |
| 3681 | .sema_failure, | |
| 3682 | .dependency_failure, | |
| 3683 | .codegen_failure, | |
| 3684 | .success, | |
| 3685 | => if (!is_outdated) return, | |
| 3345 | 3686 | .in_progress => return, |
| 3346 | 3687 | .inline_only => unreachable, // don't queue work for this |
| 3347 | .success => return, | |
| 3348 | 3688 | } |
| 3349 | 3689 | |
| 3350 | 3690 | // Decl itself is safely analyzed, and body analysis is not yet queued |
| ... | ... | @@ -3404,7 +3744,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 3404 | 3744 | new_decl.@"linksection" = .none; |
| 3405 | 3745 | new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive. |
| 3406 | 3746 | new_decl.analysis = .in_progress; |
| 3407 | new_decl.generation = mod.generation; | |
| 3408 | 3747 | |
| 3409 | 3748 | if (file.status != .success_zir) { |
| 3410 | 3749 | new_decl.analysis = .file_failure; |
| ... | ... | @@ -3483,12 +3822,19 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 3483 | 3822 | }, |
| 3484 | 3823 | .incremental => {}, |
| 3485 | 3824 | } |
| 3825 | ||
| 3826 | // Since this is our first time analyzing this file, there can be no dependencies on | |
| 3827 | // its root Decl. Thus, we do not need to invalidate any dependencies. | |
| 3486 | 3828 | } |
| 3487 | 3829 | |
| 3488 | /// Returns `true` if the Decl type changed. | |
| 3489 | /// Returns `true` if this is the first time analyzing the Decl. | |
| 3490 | /// Returns `false` otherwise. | |
| 3491 | fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { | |
| 3830 | const 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 | ||
| 3837 | fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { | |
| 3492 | 3838 | const tracy = trace(@src()); |
| 3493 | 3839 | defer tracy.end(); |
| 3494 | 3840 | |
| ... | ... | @@ -3499,6 +3845,15 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 3499 | 3845 | return error.AnalysisFail; |
| 3500 | 3846 | } |
| 3501 | 3847 | |
| 3848 | if (mod.declIsRoot(decl_index)) { | |
| 3849 | // This comes from an `analyze_decl` job on an incremental update where | |
| 3850 | // this file changed. | |
| 3851 | @panic("TODO: update root Decl of modified file"); | |
| 3852 | } else if (decl.owns_tv) { | |
| 3853 | // We are re-analyzing an owner Decl (for a function or a namespace type). | |
| 3854 | @panic("TODO: update owner Decl"); | |
| 3855 | } | |
| 3856 | ||
| 3502 | 3857 | const gpa = mod.gpa; |
| 3503 | 3858 | const zir = decl.getFileScope(mod).zir; |
| 3504 | 3859 | |
| ... | ... | @@ -3535,6 +3890,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 3535 | 3890 | break :blk .none; |
| 3536 | 3891 | }; |
| 3537 | 3892 | |
| 3893 | mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .decl = decl_index })); | |
| 3894 | ||
| 3538 | 3895 | decl.analysis = .in_progress; |
| 3539 | 3896 | |
| 3540 | 3897 | var analysis_arena = std.heap.ArenaAllocator.init(gpa); |
| ... | ... | @@ -3564,7 +3921,12 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 3564 | 3921 | }; |
| 3565 | 3922 | defer sema.deinit(); |
| 3566 | 3923 | |
| 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 | ) }); | |
| 3568 | 3930 | |
| 3569 | 3931 | var block_scope: Sema.Block = .{ |
| 3570 | 3932 | .parent = null, |
| ... | ... | @@ -3620,9 +3982,12 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 3620 | 3982 | decl.has_tv = true; |
| 3621 | 3983 | decl.owns_tv = false; |
| 3622 | 3984 | decl.analysis = .complete; |
| 3623 | decl.generation = mod.generation; | |
| 3624 | 3985 | |
| 3625 | return true; | |
| 3986 | // TODO: usingnamespace cannot currently participate in incremental compilation | |
| 3987 | return .{ | |
| 3988 | .invalidate_decl_val = true, | |
| 3989 | .invalidate_decl_ref = true, | |
| 3990 | }; | |
| 3626 | 3991 | } |
| 3627 | 3992 | |
| 3628 | 3993 | switch (ip.indexToKey(decl_tv.val.toIntern())) { |
| ... | ... | @@ -3647,7 +4012,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 3647 | 4012 | decl.has_tv = true; |
| 3648 | 4013 | decl.owns_tv = owns_tv; |
| 3649 | 4014 | decl.analysis = .complete; |
| 3650 | decl.generation = mod.generation; | |
| 3651 | 4015 | |
| 3652 | 4016 | const is_inline = decl.ty.fnCallingConvention(mod) == .Inline; |
| 3653 | 4017 | if (decl.is_exported) { |
| ... | ... | @@ -3658,15 +4022,16 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 3658 | 4022 | // The scope needs to have the decl in it. |
| 3659 | 4023 | try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index); |
| 3660 | 4024 | } |
| 3661 | return type_changed or is_inline != prev_is_inline; | |
| 4025 | // TODO: align, linksection, addrspace? | |
| 4026 | const changed = type_changed or is_inline != prev_is_inline; | |
| 4027 | return .{ | |
| 4028 | .invalidate_decl_val = changed, | |
| 4029 | .invalidate_decl_ref = changed, | |
| 4030 | }; | |
| 3662 | 4031 | } |
| 3663 | 4032 | }, |
| 3664 | 4033 | else => {}, |
| 3665 | 4034 | } |
| 3666 | var type_changed = true; | |
| 3667 | if (decl.has_tv) { | |
| 3668 | type_changed = !decl.ty.eql(decl_tv.ty, mod); | |
| 3669 | } | |
| 3670 | 4035 | |
| 3671 | 4036 | decl.owns_tv = false; |
| 3672 | 4037 | var queue_linker_work = false; |
| ... | ... | @@ -3694,6 +4059,14 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 3694 | 4059 | }, |
| 3695 | 4060 | } |
| 3696 | 4061 | |
| 4062 | const old_has_tv = decl.has_tv; | |
| 4063 | // The following values are ignored if `!old_has_tv` | |
| 4064 | const old_ty = decl.ty; | |
| 4065 | const old_val = decl.val; | |
| 4066 | const old_align = decl.alignment; | |
| 4067 | const old_linksection = decl.@"linksection"; | |
| 4068 | const old_addrspace = decl.@"addrspace"; | |
| 4069 | ||
| 3697 | 4070 | decl.ty = decl_tv.ty; |
| 3698 | 4071 | decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod))); |
| 3699 | 4072 | decl.alignment = blk: { |
| ... | ... | @@ -3735,7 +4108,17 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 3735 | 4108 | }; |
| 3736 | 4109 | decl.has_tv = true; |
| 3737 | 4110 | decl.analysis = .complete; |
| 3738 | decl.generation = mod.generation; | |
| 4111 | ||
| 4112 | const result: SemaDeclResult = if (old_has_tv) .{ | |
| 4113 | .invalidate_decl_val = !decl.ty.eql(old_ty, mod) or !decl.val.eql(old_val, decl.ty, mod), | |
| 4114 | .invalidate_decl_ref = !decl.ty.eql(old_ty, mod) or | |
| 4115 | decl.alignment != old_align or | |
| 4116 | decl.@"linksection" != old_linksection or | |
| 4117 | decl.@"addrspace" != old_addrspace, | |
| 4118 | } else .{ | |
| 4119 | .invalidate_decl_val = true, | |
| 4120 | .invalidate_decl_ref = true, | |
| 4121 | }; | |
| 3739 | 4122 | |
| 3740 | 4123 | const has_runtime_bits = is_extern or |
| 3741 | 4124 | (queue_linker_work and try sema.typeHasRuntimeBits(decl.ty)); |
| ... | ... | @@ -3748,7 +4131,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 3748 | 4131 | |
| 3749 | 4132 | try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index }); |
| 3750 | 4133 | |
| 3751 | if (type_changed and mod.emit_h != null) { | |
| 4134 | if (result.invalidate_decl_ref and mod.emit_h != null) { | |
| 3752 | 4135 | try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index }); |
| 3753 | 4136 | } |
| 3754 | 4137 | } |
| ... | ... | @@ -3759,7 +4142,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 3759 | 4142 | try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index); |
| 3760 | 4143 | } |
| 3761 | 4144 | |
| 3762 | return type_changed; | |
| 4145 | return result; | |
| 3763 | 4146 | } |
| 3764 | 4147 | |
| 3765 | 4148 | pub const ImportFileResult = struct { |
| ... | ... | @@ -4362,6 +4745,8 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato |
| 4362 | 4745 | const decl_index = func.owner_decl; |
| 4363 | 4746 | const decl = mod.declPtr(decl_index); |
| 4364 | 4747 | |
| 4748 | mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.Depender.wrap(.{ .func = func_index })); | |
| 4749 | ||
| 4365 | 4750 | var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); |
| 4366 | 4751 | defer comptime_mutable_decls.deinit(); |
| 4367 | 4752 | |
| ... | ... | @@ -4633,7 +5018,6 @@ pub fn allocateNewDecl( |
| 4633 | 5018 | .analysis = .unreferenced, |
| 4634 | 5019 | .zir_decl_index = .none, |
| 4635 | 5020 | .src_scope = src_scope, |
| 4636 | .generation = 0, | |
| 4637 | 5021 | .is_pub = false, |
| 4638 | 5022 | .is_exported = false, |
| 4639 | 5023 | .alive = false, |
| ... | ... | @@ -4711,7 +5095,6 @@ pub fn initNewAnonDecl( |
| 4711 | 5095 | new_decl.@"linksection" = .none; |
| 4712 | 5096 | new_decl.has_tv = true; |
| 4713 | 5097 | new_decl.analysis = .complete; |
| 4714 | new_decl.generation = mod.generation; | |
| 4715 | 5098 | } |
| 4716 | 5099 | |
| 4717 | 5100 | pub fn errNoteNonLazy( |
| ... | ... | @@ -5373,7 +5756,8 @@ pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void { |
| 5373 | 5756 | "unable to codegen: {s}", |
| 5374 | 5757 | .{@errorName(err)}, |
| 5375 | 5758 | )); |
| 5376 | decl.analysis = .codegen_failure_retryable; | |
| 5759 | decl.analysis = .codegen_failure; | |
| 5760 | try zcu.retryable_failures.append(zcu.gpa, InternPool.Depender.wrap(.{ .decl = decl_index })); | |
| 5377 | 5761 | }, |
| 5378 | 5762 | }; |
| 5379 | 5763 | } else if (zcu.llvm_object) |llvm_object| { |
src/Sema.zig+94-22| ... | ... | @@ -2583,7 +2583,6 @@ fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Module.ErrorMsg) |
| 2583 | 2583 | ip.funcAnalysis(sema.owner_func_index).state = .sema_failure; |
| 2584 | 2584 | } else { |
| 2585 | 2585 | sema.owner_decl.analysis = .sema_failure; |
| 2586 | sema.owner_decl.generation = mod.generation; | |
| 2587 | 2586 | } |
| 2588 | 2587 | if (sema.func_index != .none) { |
| 2589 | 2588 | ip.funcAnalysis(sema.func_index).state = .sema_failure; |
| ... | ... | @@ -2718,7 +2717,7 @@ pub fn getStructType( |
| 2718 | 2717 | assert(extended.opcode == .struct_decl); |
| 2719 | 2718 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); |
| 2720 | 2719 | |
| 2721 | var extra_index: usize = extended.operand; | |
| 2720 | var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len; | |
| 2722 | 2721 | extra_index += @intFromBool(small.has_src_node); |
| 2723 | 2722 | const fields_len = if (small.has_fields_len) blk: { |
| 2724 | 2723 | const fields_len = sema.code.extra[extra_index]; |
| ... | ... | @@ -2748,7 +2747,7 @@ pub fn getStructType( |
| 2748 | 2747 | const ty = try ip.getStructType(gpa, .{ |
| 2749 | 2748 | .decl = decl, |
| 2750 | 2749 | .namespace = namespace.toOptional(), |
| 2751 | .zir_index = tracked_inst, | |
| 2750 | .zir_index = tracked_inst.toOptional(), | |
| 2752 | 2751 | .layout = small.layout, |
| 2753 | 2752 | .known_non_opv = small.known_non_opv, |
| 2754 | 2753 | .is_tuple = small.is_tuple, |
| ... | ... | @@ -2773,7 +2772,7 @@ fn zirStructDecl( |
| 2773 | 2772 | const ip = &mod.intern_pool; |
| 2774 | 2773 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); |
| 2775 | 2774 | const src: LazySrcLoc = if (small.has_src_node) blk: { |
| 2776 | const node_offset: i32 = @bitCast(sema.code.extra[extended.operand]); | |
| 2775 | const node_offset: i32 = @bitCast(sema.code.extra[extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len]); | |
| 2777 | 2776 | break :blk LazySrcLoc.nodeOffset(node_offset); |
| 2778 | 2777 | } else sema.src; |
| 2779 | 2778 | |
| ... | ... | @@ -2789,6 +2788,14 @@ fn zirStructDecl( |
| 2789 | 2788 | new_decl.owns_tv = true; |
| 2790 | 2789 | errdefer mod.abortAnonDecl(new_decl_index); |
| 2791 | 2790 | |
| 2791 | if (sema.mod.comp.debug_incremental) { | |
| 2792 | try ip.addDependency( | |
| 2793 | sema.gpa, | |
| 2794 | InternPool.Depender.wrap(.{ .decl = new_decl_index }), | |
| 2795 | .{ .src_hash = try ip.trackZir(sema.gpa, block.getFileScope(mod), inst) }, | |
| 2796 | ); | |
| 2797 | } | |
| 2798 | ||
| 2792 | 2799 | const new_namespace_index = try mod.createNamespace(.{ |
| 2793 | 2800 | .parent = block.namespace.toOptional(), |
| 2794 | 2801 | .ty = undefined, |
| ... | ... | @@ -2927,7 +2934,7 @@ fn zirEnumDecl( |
| 2927 | 2934 | const mod = sema.mod; |
| 2928 | 2935 | const gpa = sema.gpa; |
| 2929 | 2936 | const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small); |
| 2930 | var extra_index: usize = extended.operand; | |
| 2937 | var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.EnumDecl).Struct.fields.len; | |
| 2931 | 2938 | |
| 2932 | 2939 | const src: LazySrcLoc = if (small.has_src_node) blk: { |
| 2933 | 2940 | const node_offset: i32 = @bitCast(sema.code.extra[extra_index]); |
| ... | ... | @@ -2973,6 +2980,14 @@ fn zirEnumDecl( |
| 2973 | 2980 | new_decl.owns_tv = true; |
| 2974 | 2981 | errdefer if (!done) mod.abortAnonDecl(new_decl_index); |
| 2975 | 2982 | |
| 2983 | if (sema.mod.comp.debug_incremental) { | |
| 2984 | try mod.intern_pool.addDependency( | |
| 2985 | sema.gpa, | |
| 2986 | InternPool.Depender.wrap(.{ .decl = new_decl_index }), | |
| 2987 | .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) }, | |
| 2988 | ); | |
| 2989 | } | |
| 2990 | ||
| 2976 | 2991 | const new_namespace_index = try mod.createNamespace(.{ |
| 2977 | 2992 | .parent = block.namespace.toOptional(), |
| 2978 | 2993 | .ty = undefined, |
| ... | ... | @@ -3008,6 +3023,7 @@ fn zirEnumDecl( |
| 3008 | 3023 | .auto |
| 3009 | 3024 | else |
| 3010 | 3025 | .explicit, |
| 3026 | .zir_index = (try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst)).toOptional(), | |
| 3011 | 3027 | }); |
| 3012 | 3028 | if (sema.builtin_type_target_index != .none) { |
| 3013 | 3029 | mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, incomplete_enum.index); |
| ... | ... | @@ -3191,7 +3207,7 @@ fn zirUnionDecl( |
| 3191 | 3207 | const mod = sema.mod; |
| 3192 | 3208 | const gpa = sema.gpa; |
| 3193 | 3209 | const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small); |
| 3194 | var extra_index: usize = extended.operand; | |
| 3210 | var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.UnionDecl).Struct.fields.len; | |
| 3195 | 3211 | |
| 3196 | 3212 | const src: LazySrcLoc = if (small.has_src_node) blk: { |
| 3197 | 3213 | const node_offset: i32 = @bitCast(sema.code.extra[extra_index]); |
| ... | ... | @@ -3225,6 +3241,14 @@ fn zirUnionDecl( |
| 3225 | 3241 | new_decl.owns_tv = true; |
| 3226 | 3242 | errdefer mod.abortAnonDecl(new_decl_index); |
| 3227 | 3243 | |
| 3244 | if (sema.mod.comp.debug_incremental) { | |
| 3245 | try mod.intern_pool.addDependency( | |
| 3246 | sema.gpa, | |
| 3247 | InternPool.Depender.wrap(.{ .decl = new_decl_index }), | |
| 3248 | .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) }, | |
| 3249 | ); | |
| 3250 | } | |
| 3251 | ||
| 3228 | 3252 | const new_namespace_index = try mod.createNamespace(.{ |
| 3229 | 3253 | .parent = block.namespace.toOptional(), |
| 3230 | 3254 | .ty = undefined, |
| ... | ... | @@ -3254,7 +3278,7 @@ fn zirUnionDecl( |
| 3254 | 3278 | }, |
| 3255 | 3279 | .decl = new_decl_index, |
| 3256 | 3280 | .namespace = new_namespace_index, |
| 3257 | .zir_index = try mod.intern_pool.trackZir(gpa, block.getFileScope(mod), inst), | |
| 3281 | .zir_index = (try mod.intern_pool.trackZir(gpa, block.getFileScope(mod), inst)).toOptional(), | |
| 3258 | 3282 | .fields_len = fields_len, |
| 3259 | 3283 | .enum_tag_ty = .none, |
| 3260 | 3284 | .field_types = &.{}, |
| ... | ... | @@ -3318,6 +3342,14 @@ fn zirOpaqueDecl( |
| 3318 | 3342 | new_decl.owns_tv = true; |
| 3319 | 3343 | errdefer mod.abortAnonDecl(new_decl_index); |
| 3320 | 3344 | |
| 3345 | if (sema.mod.comp.debug_incremental) { | |
| 3346 | try mod.intern_pool.addDependency( | |
| 3347 | sema.gpa, | |
| 3348 | InternPool.Depender.wrap(.{ .decl = new_decl_index }), | |
| 3349 | .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) }, | |
| 3350 | ); | |
| 3351 | } | |
| 3352 | ||
| 3321 | 3353 | const new_namespace_index = try mod.createNamespace(.{ |
| 3322 | 3354 | .parent = block.namespace.toOptional(), |
| 3323 | 3355 | .ty = undefined, |
| ... | ... | @@ -3329,6 +3361,7 @@ fn zirOpaqueDecl( |
| 3329 | 3361 | const opaque_ty = try mod.intern(.{ .opaque_type = .{ |
| 3330 | 3362 | .decl = new_decl_index, |
| 3331 | 3363 | .namespace = new_namespace_index, |
| 3364 | .zir_index = (try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst)).toOptional(), | |
| 3332 | 3365 | } }); |
| 3333 | 3366 | // TODO: figure out InternPool removals for incremental compilation |
| 3334 | 3367 | //errdefer mod.intern_pool.remove(opaque_ty); |
| ... | ... | @@ -7890,6 +7923,8 @@ fn instantiateGenericCall( |
| 7890 | 7923 | const generic_owner_func = mod.intern_pool.indexToKey(generic_owner).func; |
| 7891 | 7924 | const generic_owner_ty_info = mod.typeToFunc(Type.fromInterned(generic_owner_func.ty)).?; |
| 7892 | 7925 | |
| 7926 | try sema.declareDependency(.{ .src_hash = generic_owner_func.zir_body_inst }); | |
| 7927 | ||
| 7893 | 7928 | // Even though there may already be a generic instantiation corresponding |
| 7894 | 7929 | // to this callsite, we must evaluate the expressions of the generic |
| 7895 | 7930 | // function signature with the values of the callsite plugged in. |
| ... | ... | @@ -9440,7 +9475,6 @@ fn funcCommon( |
| 9440 | 9475 | .inferred_error_set = inferred_error_set, |
| 9441 | 9476 | .generic_owner = sema.generic_owner, |
| 9442 | 9477 | .comptime_args = sema.comptime_args, |
| 9443 | .generation = mod.generation, | |
| 9444 | 9478 | }); |
| 9445 | 9479 | return finishFunc( |
| 9446 | 9480 | sema, |
| ... | ... | @@ -13598,6 +13632,12 @@ fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 13598 | 13632 | }); |
| 13599 | 13633 | |
| 13600 | 13634 | try sema.checkNamespaceType(block, lhs_src, container_type); |
| 13635 | if (container_type.typeDeclInst(mod)) |type_decl_inst| { | |
| 13636 | try sema.declareDependency(.{ .namespace_name = .{ | |
| 13637 | .namespace = type_decl_inst, | |
| 13638 | .name = decl_name, | |
| 13639 | } }); | |
| 13640 | } | |
| 13601 | 13641 | |
| 13602 | 13642 | const namespace = container_type.getNamespaceIndex(mod).unwrap() orelse |
| 13603 | 13643 | return .bool_false; |
| ... | ... | @@ -17451,6 +17491,10 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 17451 | 17491 | const type_info_ty = try sema.getBuiltinType("Type"); |
| 17452 | 17492 | const type_info_tag_ty = type_info_ty.unionTagType(mod).?; |
| 17453 | 17493 | |
| 17494 | if (ty.typeDeclInst(mod)) |type_decl_inst| { | |
| 17495 | try sema.declareDependency(.{ .namespace = type_decl_inst }); | |
| 17496 | } | |
| 17497 | ||
| 17454 | 17498 | switch (ty.zigTypeTag(mod)) { |
| 17455 | 17499 | .Type, |
| 17456 | 17500 | .Void, |
| ... | ... | @@ -21318,6 +21362,7 @@ fn zirReify( |
| 21318 | 21362 | else |
| 21319 | 21363 | .explicit, |
| 21320 | 21364 | .tag_ty = int_tag_ty.toIntern(), |
| 21365 | .zir_index = .none, | |
| 21321 | 21366 | }); |
| 21322 | 21367 | // TODO: figure out InternPool removals for incremental compilation |
| 21323 | 21368 | //errdefer ip.remove(incomplete_enum.index); |
| ... | ... | @@ -21415,6 +21460,7 @@ fn zirReify( |
| 21415 | 21460 | const opaque_ty = try mod.intern(.{ .opaque_type = .{ |
| 21416 | 21461 | .decl = new_decl_index, |
| 21417 | 21462 | .namespace = new_namespace_index, |
| 21463 | .zir_index = .none, | |
| 21418 | 21464 | } }); |
| 21419 | 21465 | // TODO: figure out InternPool removals for incremental compilation |
| 21420 | 21466 | //errdefer ip.remove(opaque_ty); |
| ... | ... | @@ -21633,7 +21679,7 @@ fn zirReify( |
| 21633 | 21679 | .namespace = new_namespace_index, |
| 21634 | 21680 | .enum_tag_ty = enum_tag_ty, |
| 21635 | 21681 | .fields_len = fields_len, |
| 21636 | .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst), // TODO: should reified types be handled differently? | |
| 21682 | .zir_index = .none, | |
| 21637 | 21683 | .flags = .{ |
| 21638 | 21684 | .layout = layout, |
| 21639 | 21685 | .status = .have_field_types, |
| ... | ... | @@ -21801,7 +21847,7 @@ fn reifyStruct( |
| 21801 | 21847 | const ty = try ip.getStructType(gpa, .{ |
| 21802 | 21848 | .decl = new_decl_index, |
| 21803 | 21849 | .namespace = .none, |
| 21804 | .zir_index = try mod.intern_pool.trackZir(gpa, block.getFileScope(mod), inst), // TODO: should reified types be handled differently? | |
| 21850 | .zir_index = .none, | |
| 21805 | 21851 | .layout = layout, |
| 21806 | 21852 | .known_non_opv = false, |
| 21807 | 21853 | .fields_len = fields_len, |
| ... | ... | @@ -25922,7 +25968,6 @@ fn zirBuiltinExtern( |
| 25922 | 25968 | new_decl.has_tv = true; |
| 25923 | 25969 | new_decl.owns_tv = true; |
| 25924 | 25970 | new_decl.analysis = .complete; |
| 25925 | new_decl.generation = mod.generation; | |
| 25926 | 25971 | |
| 25927 | 25972 | try sema.ensureDeclAnalyzed(new_decl_index); |
| 25928 | 25973 | |
| ... | ... | @@ -26421,6 +26466,7 @@ fn prepareSimplePanic(sema: *Sema, block: *Block) !void { |
| 26421 | 26466 | // owns the function. |
| 26422 | 26467 | try sema.ensureDeclAnalyzed(decl_index); |
| 26423 | 26468 | const tv = try mod.declPtr(decl_index).typedValue(); |
| 26469 | try sema.declareDependency(.{ .decl_val = decl_index }); | |
| 26424 | 26470 | assert(tv.ty.zigTypeTag(mod) == .Fn); |
| 26425 | 26471 | assert(try sema.fnHasRuntimeBits(tv.ty)); |
| 26426 | 26472 | const func_index = tv.val.toIntern(); |
| ... | ... | @@ -26842,6 +26888,13 @@ fn fieldVal( |
| 26842 | 26888 | const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?; |
| 26843 | 26889 | const child_type = val.toType(); |
| 26844 | 26890 | |
| 26891 | if (child_type.typeDeclInst(mod)) |type_decl_inst| { | |
| 26892 | try sema.declareDependency(.{ .namespace_name = .{ | |
| 26893 | .namespace = type_decl_inst, | |
| 26894 | .name = field_name, | |
| 26895 | } }); | |
| 26896 | } | |
| 26897 | ||
| 26845 | 26898 | switch (try child_type.zigTypeTagOrPoison(mod)) { |
| 26846 | 26899 | .ErrorSet => { |
| 26847 | 26900 | switch (ip.indexToKey(child_type.toIntern())) { |
| ... | ... | @@ -27065,6 +27118,13 @@ fn fieldPtr( |
| 27065 | 27118 | const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?; |
| 27066 | 27119 | const child_type = val.toType(); |
| 27067 | 27120 | |
| 27121 | if (child_type.typeDeclInst(mod)) |type_decl_inst| { | |
| 27122 | try sema.declareDependency(.{ .namespace_name = .{ | |
| 27123 | .namespace = type_decl_inst, | |
| 27124 | .name = field_name, | |
| 27125 | } }); | |
| 27126 | } | |
| 27127 | ||
| 27068 | 27128 | switch (child_type.zigTypeTag(mod)) { |
| 27069 | 27129 | .ErrorSet => { |
| 27070 | 27130 | switch (ip.indexToKey(child_type.toIntern())) { |
| ... | ... | @@ -31134,6 +31194,7 @@ fn beginComptimePtrLoad( |
| 31134 | 31194 | const is_mutable = ptr.addr == .mut_decl; |
| 31135 | 31195 | const decl = mod.declPtr(decl_index); |
| 31136 | 31196 | const decl_tv = try decl.typedValue(); |
| 31197 | try sema.declareDependency(.{ .decl_val = decl_index }); | |
| 31137 | 31198 | if (decl.val.getVariable(mod) != null) return error.RuntimeLoad; |
| 31138 | 31199 | |
| 31139 | 31200 | const layout_defined = decl.ty.hasWellDefinedLayout(mod); |
| ... | ... | @@ -32387,6 +32448,8 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn |
| 32387 | 32448 | |
| 32388 | 32449 | const decl = mod.declPtr(decl_index); |
| 32389 | 32450 | const decl_tv = try decl.typedValue(); |
| 32451 | // TODO: if this is a `decl_ref` of a non-variable decl, only depend on decl type | |
| 32452 | try sema.declareDependency(.{ .decl_val = decl_index }); | |
| 32390 | 32453 | const ptr_ty = try sema.ptrType(.{ |
| 32391 | 32454 | .child = decl_tv.ty.toIntern(), |
| 32392 | 32455 | .flags = .{ |
| ... | ... | @@ -35683,13 +35746,13 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp |
| 35683 | 35746 | break :blk accumulator; |
| 35684 | 35747 | }; |
| 35685 | 35748 | |
| 35686 | const zir_index = struct_type.zir_index.resolve(ip); | |
| 35749 | const zir_index = struct_type.zir_index.unwrap().?.resolve(ip); | |
| 35687 | 35750 | const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended; |
| 35688 | 35751 | assert(extended.opcode == .struct_decl); |
| 35689 | 35752 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); |
| 35690 | 35753 | |
| 35691 | 35754 | if (small.has_backing_int) { |
| 35692 | var extra_index: usize = extended.operand; | |
| 35755 | var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len; | |
| 35693 | 35756 | extra_index += @intFromBool(small.has_src_node); |
| 35694 | 35757 | extra_index += @intFromBool(small.has_fields_len); |
| 35695 | 35758 | extra_index += @intFromBool(small.has_decls_len); |
| ... | ... | @@ -36162,10 +36225,8 @@ pub fn resolveTypeFieldsStruct( |
| 36162 | 36225 | .file_failure, |
| 36163 | 36226 | .dependency_failure, |
| 36164 | 36227 | .sema_failure, |
| 36165 | .sema_failure_retryable, | |
| 36166 | 36228 | => { |
| 36167 | 36229 | sema.owner_decl.analysis = .dependency_failure; |
| 36168 | sema.owner_decl.generation = mod.generation; | |
| 36169 | 36230 | return error.AnalysisFail; |
| 36170 | 36231 | }, |
| 36171 | 36232 | else => {}, |
| ... | ... | @@ -36221,10 +36282,8 @@ pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key. |
| 36221 | 36282 | .file_failure, |
| 36222 | 36283 | .dependency_failure, |
| 36223 | 36284 | .sema_failure, |
| 36224 | .sema_failure_retryable, | |
| 36225 | 36285 | => { |
| 36226 | 36286 | sema.owner_decl.analysis = .dependency_failure; |
| 36227 | sema.owner_decl.generation = mod.generation; | |
| 36228 | 36287 | return error.AnalysisFail; |
| 36229 | 36288 | }, |
| 36230 | 36289 | else => {}, |
| ... | ... | @@ -36404,7 +36463,7 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct { |
| 36404 | 36463 | const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended; |
| 36405 | 36464 | assert(extended.opcode == .struct_decl); |
| 36406 | 36465 | const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small); |
| 36407 | var extra_index: usize = extended.operand; | |
| 36466 | var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len; | |
| 36408 | 36467 | |
| 36409 | 36468 | extra_index += @intFromBool(small.has_src_node); |
| 36410 | 36469 | |
| ... | ... | @@ -36448,7 +36507,7 @@ fn semaStructFields( |
| 36448 | 36507 | const decl = mod.declPtr(decl_index); |
| 36449 | 36508 | const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace; |
| 36450 | 36509 | const zir = mod.namespacePtr(namespace_index).file_scope.zir; |
| 36451 | const zir_index = struct_type.zir_index.resolve(ip); | |
| 36510 | const zir_index = struct_type.zir_index.unwrap().?.resolve(ip); | |
| 36452 | 36511 | |
| 36453 | 36512 | const fields_len, const small, var extra_index = structZirInfo(zir, zir_index); |
| 36454 | 36513 | |
| ... | ... | @@ -36719,7 +36778,7 @@ fn semaStructFieldInits( |
| 36719 | 36778 | const decl = mod.declPtr(decl_index); |
| 36720 | 36779 | const namespace_index = struct_type.namespace.unwrap() orelse decl.src_namespace; |
| 36721 | 36780 | const zir = mod.namespacePtr(namespace_index).file_scope.zir; |
| 36722 | const zir_index = struct_type.zir_index.resolve(ip); | |
| 36781 | const zir_index = struct_type.zir_index.unwrap().?.resolve(ip); | |
| 36723 | 36782 | const fields_len, const small, var extra_index = structZirInfo(zir, zir_index); |
| 36724 | 36783 | |
| 36725 | 36784 | var comptime_mutable_decls = std.ArrayList(InternPool.DeclIndex).init(gpa); |
| ... | ... | @@ -36868,11 +36927,11 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un |
| 36868 | 36927 | const ip = &mod.intern_pool; |
| 36869 | 36928 | const decl_index = union_type.decl; |
| 36870 | 36929 | const zir = mod.namespacePtr(union_type.namespace).file_scope.zir; |
| 36871 | const zir_index = union_type.zir_index.resolve(ip); | |
| 36930 | const zir_index = union_type.zir_index.unwrap().?.resolve(ip); | |
| 36872 | 36931 | const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended; |
| 36873 | 36932 | assert(extended.opcode == .union_decl); |
| 36874 | 36933 | const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small); |
| 36875 | var extra_index: usize = extended.operand; | |
| 36934 | var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.UnionDecl).Struct.fields.len; | |
| 36876 | 36935 | |
| 36877 | 36936 | const src = LazySrcLoc.nodeOffset(0); |
| 36878 | 36937 | extra_index += @intFromBool(small.has_src_node); |
| ... | ... | @@ -37312,6 +37371,7 @@ fn generateUnionTagTypeNumbered( |
| 37312 | 37371 | .names = enum_field_names, |
| 37313 | 37372 | .values = enum_field_vals, |
| 37314 | 37373 | .tag_mode = .explicit, |
| 37374 | .zir_index = .none, | |
| 37315 | 37375 | }); |
| 37316 | 37376 | |
| 37317 | 37377 | new_decl.ty = Type.type; |
| ... | ... | @@ -37362,6 +37422,7 @@ fn generateUnionTagTypeSimple( |
| 37362 | 37422 | .names = enum_field_names, |
| 37363 | 37423 | .values = &.{}, |
| 37364 | 37424 | .tag_mode = .auto, |
| 37425 | .zir_index = .none, | |
| 37365 | 37426 | }); |
| 37366 | 37427 | |
| 37367 | 37428 | const new_decl = mod.declPtr(new_decl_index); |
| ... | ... | @@ -38876,3 +38937,14 @@ fn ptrType(sema: *Sema, info: InternPool.Key.PtrType) CompileError!Type { |
| 38876 | 38937 | } |
| 38877 | 38938 | return sema.mod.ptrType(info); |
| 38878 | 38939 | } |
| 38940 | ||
| 38941 | pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void { | |
| 38942 | if (!sema.mod.comp.debug_incremental) return; | |
| 38943 | const depender = InternPool.Depender.wrap( | |
| 38944 | if (sema.owner_func_index != .none) | |
| 38945 | .{ .func = sema.owner_func_index } | |
| 38946 | else | |
| 38947 | .{ .decl = sema.owner_decl_index }, | |
| 38948 | ); | |
| 38949 | try sema.mod.intern_pool.addDependency(sema.gpa, depender, dependee); | |
| 38950 | } |
src/Zir.zig+131-3| ... | ... | @@ -2497,6 +2497,7 @@ pub const Inst = struct { |
| 2497 | 2497 | /// } |
| 2498 | 2498 | /// 2. body: Index // for each body_len |
| 2499 | 2499 | /// 3. src_locs: SrcLocs // if body_len != 0 |
| 2500 | /// 4. proto_hash: std.zig.SrcHash // if body_len != 0; hash of function prototype | |
| 2500 | 2501 | pub const Func = struct { |
| 2501 | 2502 | /// If this is 0 it means a void return type. |
| 2502 | 2503 | /// If this is 1 it means return_type is a simple Ref |
| ... | ... | @@ -2558,6 +2559,7 @@ pub const Inst = struct { |
| 2558 | 2559 | /// - each bit starting with LSB corresponds to parameter indexes |
| 2559 | 2560 | /// 17. body: Index // for each body_len |
| 2560 | 2561 | /// 18. src_locs: Func.SrcLocs // if body_len != 0 |
| 2562 | /// 19. proto_hash: std.zig.SrcHash // if body_len != 0; hash of function prototype | |
| 2561 | 2563 | pub const FuncFancy = struct { |
| 2562 | 2564 | /// Points to the block that contains the param instructions for this function. |
| 2563 | 2565 | /// If this is a `declaration`, it refers to the declaration's value body. |
| ... | ... | @@ -3040,6 +3042,12 @@ pub const Inst = struct { |
| 3040 | 3042 | /// init_body_inst: Inst, // for each init_body_len |
| 3041 | 3043 | /// } |
| 3042 | 3044 | pub const StructDecl = struct { |
| 3045 | // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`. | |
| 3046 | // This hash contains the source of all fields, and any specified attributes (`extern`, backing type, etc). | |
| 3047 | fields_hash_0: u32, | |
| 3048 | fields_hash_1: u32, | |
| 3049 | fields_hash_2: u32, | |
| 3050 | fields_hash_3: u32, | |
| 3043 | 3051 | pub const Small = packed struct { |
| 3044 | 3052 | has_src_node: bool, |
| 3045 | 3053 | has_fields_len: bool, |
| ... | ... | @@ -3102,6 +3110,12 @@ pub const Inst = struct { |
| 3102 | 3110 | /// value: Ref, // if corresponding bit is set |
| 3103 | 3111 | /// } |
| 3104 | 3112 | pub const EnumDecl = struct { |
| 3113 | // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`. | |
| 3114 | // This hash contains the source of all fields, and the backing type if specified. | |
| 3115 | fields_hash_0: u32, | |
| 3116 | fields_hash_1: u32, | |
| 3117 | fields_hash_2: u32, | |
| 3118 | fields_hash_3: u32, | |
| 3105 | 3119 | pub const Small = packed struct { |
| 3106 | 3120 | has_src_node: bool, |
| 3107 | 3121 | has_tag_type: bool, |
| ... | ... | @@ -3137,6 +3151,12 @@ pub const Inst = struct { |
| 3137 | 3151 | /// tag_value: Ref, // if corresponding bit is set |
| 3138 | 3152 | /// } |
| 3139 | 3153 | pub const UnionDecl = struct { |
| 3154 | // These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`. | |
| 3155 | // This hash contains the source of all fields, and any specified attributes (`extern` etc). | |
| 3156 | fields_hash_0: u32, | |
| 3157 | fields_hash_1: u32, | |
| 3158 | fields_hash_2: u32, | |
| 3159 | fields_hash_3: u32, | |
| 3140 | 3160 | pub const Small = packed struct { |
| 3141 | 3161 | has_src_node: bool, |
| 3142 | 3162 | has_tag_type: bool, |
| ... | ... | @@ -3455,7 +3475,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator { |
| 3455 | 3475 | switch (extended.opcode) { |
| 3456 | 3476 | .struct_decl => { |
| 3457 | 3477 | const small: Inst.StructDecl.Small = @bitCast(extended.small); |
| 3458 | var extra_index: u32 = extended.operand; | |
| 3478 | var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.StructDecl).Struct.fields.len); | |
| 3459 | 3479 | extra_index += @intFromBool(small.has_src_node); |
| 3460 | 3480 | extra_index += @intFromBool(small.has_fields_len); |
| 3461 | 3481 | const decls_len = if (small.has_decls_len) decls_len: { |
| ... | ... | @@ -3482,7 +3502,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator { |
| 3482 | 3502 | }, |
| 3483 | 3503 | .enum_decl => { |
| 3484 | 3504 | const small: Inst.EnumDecl.Small = @bitCast(extended.small); |
| 3485 | var extra_index: u32 = extended.operand; | |
| 3505 | var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.EnumDecl).Struct.fields.len); | |
| 3486 | 3506 | extra_index += @intFromBool(small.has_src_node); |
| 3487 | 3507 | extra_index += @intFromBool(small.has_tag_type); |
| 3488 | 3508 | extra_index += @intFromBool(small.has_body_len); |
| ... | ... | @@ -3501,7 +3521,7 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator { |
| 3501 | 3521 | }, |
| 3502 | 3522 | .union_decl => { |
| 3503 | 3523 | const small: Inst.UnionDecl.Small = @bitCast(extended.small); |
| 3504 | var extra_index: u32 = extended.operand; | |
| 3524 | var extra_index: u32 = @intCast(extended.operand + @typeInfo(Inst.UnionDecl).Struct.fields.len); | |
| 3505 | 3525 | extra_index += @intFromBool(small.has_src_node); |
| 3506 | 3526 | extra_index += @intFromBool(small.has_tag_type); |
| 3507 | 3527 | extra_index += @intFromBool(small.has_body_len); |
| ... | ... | @@ -3938,3 +3958,111 @@ pub fn getDeclaration(zir: Zir, inst: Zir.Inst.Index) struct { Inst.Declaration, |
| 3938 | 3958 | @intCast(extra.end), |
| 3939 | 3959 | }; |
| 3940 | 3960 | } |
| 3961 | ||
| 3962 | pub fn getAssociatedSrcHash(zir: Zir, inst: Zir.Inst.Index) ?std.zig.SrcHash { | |
| 3963 | const tag = zir.instructions.items(.tag); | |
| 3964 | const data = zir.instructions.items(.data); | |
| 3965 | switch (tag[@intFromEnum(inst)]) { | |
| 3966 | .declaration => { | |
| 3967 | const pl_node = data[@intFromEnum(inst)].pl_node; | |
| 3968 | const extra = zir.extraData(Inst.Declaration, pl_node.payload_index); | |
| 3969 | return @bitCast([4]u32{ | |
| 3970 | extra.data.src_hash_0, | |
| 3971 | extra.data.src_hash_1, | |
| 3972 | extra.data.src_hash_2, | |
| 3973 | extra.data.src_hash_3, | |
| 3974 | }); | |
| 3975 | }, | |
| 3976 | .func, .func_inferred => { | |
| 3977 | const pl_node = data[@intFromEnum(inst)].pl_node; | |
| 3978 | const extra = zir.extraData(Inst.Func, pl_node.payload_index); | |
| 3979 | if (extra.data.body_len == 0) { | |
| 3980 | // Function type or extern fn - no associated hash | |
| 3981 | return null; | |
| 3982 | } | |
| 3983 | const extra_index = extra.end + | |
| 3984 | 1 + | |
| 3985 | extra.data.body_len + | |
| 3986 | @typeInfo(Inst.Func.SrcLocs).Struct.fields.len; | |
| 3987 | return @bitCast([4]u32{ | |
| 3988 | zir.extra[extra_index + 0], | |
| 3989 | zir.extra[extra_index + 1], | |
| 3990 | zir.extra[extra_index + 2], | |
| 3991 | zir.extra[extra_index + 3], | |
| 3992 | }); | |
| 3993 | }, | |
| 3994 | .func_fancy => { | |
| 3995 | const pl_node = data[@intFromEnum(inst)].pl_node; | |
| 3996 | const extra = zir.extraData(Inst.FuncFancy, pl_node.payload_index); | |
| 3997 | if (extra.data.body_len == 0) { | |
| 3998 | // Function type or extern fn - no associated hash | |
| 3999 | return null; | |
| 4000 | } | |
| 4001 | const bits = extra.data.bits; | |
| 4002 | var extra_index = extra.end; | |
| 4003 | extra_index += @intFromBool(bits.has_lib_name); | |
| 4004 | if (bits.has_align_body) { | |
| 4005 | const body_len = zir.extra[extra_index]; | |
| 4006 | extra_index += 1 + body_len; | |
| 4007 | } else extra_index += @intFromBool(bits.has_align_ref); | |
| 4008 | if (bits.has_addrspace_body) { | |
| 4009 | const body_len = zir.extra[extra_index]; | |
| 4010 | extra_index += 1 + body_len; | |
| 4011 | } else extra_index += @intFromBool(bits.has_addrspace_ref); | |
| 4012 | if (bits.has_section_body) { | |
| 4013 | const body_len = zir.extra[extra_index]; | |
| 4014 | extra_index += 1 + body_len; | |
| 4015 | } else extra_index += @intFromBool(bits.has_section_ref); | |
| 4016 | if (bits.has_cc_body) { | |
| 4017 | const body_len = zir.extra[extra_index]; | |
| 4018 | extra_index += 1 + body_len; | |
| 4019 | } else extra_index += @intFromBool(bits.has_cc_ref); | |
| 4020 | if (bits.has_ret_ty_body) { | |
| 4021 | const body_len = zir.extra[extra_index]; | |
| 4022 | extra_index += 1 + body_len; | |
| 4023 | } else extra_index += @intFromBool(bits.has_ret_ty_ref); | |
| 4024 | extra_index += @intFromBool(bits.has_any_noalias); | |
| 4025 | extra_index += extra.data.body_len; | |
| 4026 | extra_index += @typeInfo(Zir.Inst.Func.SrcLocs).Struct.fields.len; | |
| 4027 | return @bitCast([4]u32{ | |
| 4028 | zir.extra[extra_index + 0], | |
| 4029 | zir.extra[extra_index + 1], | |
| 4030 | zir.extra[extra_index + 2], | |
| 4031 | zir.extra[extra_index + 3], | |
| 4032 | }); | |
| 4033 | }, | |
| 4034 | .extended => {}, | |
| 4035 | else => return null, | |
| 4036 | } | |
| 4037 | const extended = data[@intFromEnum(inst)].extended; | |
| 4038 | switch (extended.opcode) { | |
| 4039 | .struct_decl => { | |
| 4040 | const extra = zir.extraData(Inst.StructDecl, extended.operand).data; | |
| 4041 | return @bitCast([4]u32{ | |
| 4042 | extra.fields_hash_0, | |
| 4043 | extra.fields_hash_1, | |
| 4044 | extra.fields_hash_2, | |
| 4045 | extra.fields_hash_3, | |
| 4046 | }); | |
| 4047 | }, | |
| 4048 | .union_decl => { | |
| 4049 | const extra = zir.extraData(Inst.UnionDecl, extended.operand).data; | |
| 4050 | return @bitCast([4]u32{ | |
| 4051 | extra.fields_hash_0, | |
| 4052 | extra.fields_hash_1, | |
| 4053 | extra.fields_hash_2, | |
| 4054 | extra.fields_hash_3, | |
| 4055 | }); | |
| 4056 | }, | |
| 4057 | .enum_decl => { | |
| 4058 | const extra = zir.extraData(Inst.EnumDecl, extended.operand).data; | |
| 4059 | return @bitCast([4]u32{ | |
| 4060 | extra.fields_hash_0, | |
| 4061 | extra.fields_hash_1, | |
| 4062 | extra.fields_hash_2, | |
| 4063 | extra.fields_hash_3, | |
| 4064 | }); | |
| 4065 | }, | |
| 4066 | else => return null, | |
| 4067 | } | |
| 4068 | } |
src/main.zig+1| ... | ... | @@ -3255,6 +3255,7 @@ fn buildOutputType( |
| 3255 | 3255 | .cache_mode = cache_mode, |
| 3256 | 3256 | .subsystem = subsystem, |
| 3257 | 3257 | .debug_compile_errors = debug_compile_errors, |
| 3258 | .debug_incremental = debug_incremental, | |
| 3258 | 3259 | .enable_link_snapshots = enable_link_snapshots, |
| 3259 | 3260 | .install_name = install_name, |
| 3260 | 3261 | .entitlements = entitlements, |
src/print_zir.zig+34-3| ... | ... | @@ -1401,7 +1401,17 @@ const Writer = struct { |
| 1401 | 1401 | fn writeStructDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { |
| 1402 | 1402 | const small = @as(Zir.Inst.StructDecl.Small, @bitCast(extended.small)); |
| 1403 | 1403 | |
| 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; | |
| 1405 | 1415 | |
| 1406 | 1416 | const src_node: ?i32 = if (small.has_src_node) blk: { |
| 1407 | 1417 | const src_node = @as(i32, @bitCast(self.code.extra[extra_index])); |
| ... | ... | @@ -1591,7 +1601,17 @@ const Writer = struct { |
| 1591 | 1601 | fn writeUnionDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { |
| 1592 | 1602 | const small = @as(Zir.Inst.UnionDecl.Small, @bitCast(extended.small)); |
| 1593 | 1603 | |
| 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; | |
| 1595 | 1615 | |
| 1596 | 1616 | const src_node: ?i32 = if (small.has_src_node) blk: { |
| 1597 | 1617 | const src_node = @as(i32, @bitCast(self.code.extra[extra_index])); |
| ... | ... | @@ -1733,7 +1753,18 @@ const Writer = struct { |
| 1733 | 1753 | |
| 1734 | 1754 | fn writeEnumDecl(self: *Writer, stream: anytype, extended: Zir.Inst.Extended.InstData) !void { |
| 1735 | 1755 | const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small)); |
| 1736 | var extra_index: usize = extended.operand; | |
| 1756 | ||
| 1757 | const extra = self.code.extraData(Zir.Inst.EnumDecl, extended.operand); | |
| 1758 | const fields_hash: std.zig.SrcHash = @bitCast([4]u32{ | |
| 1759 | extra.data.fields_hash_0, | |
| 1760 | extra.data.fields_hash_1, | |
| 1761 | extra.data.fields_hash_2, | |
| 1762 | extra.data.fields_hash_3, | |
| 1763 | }); | |
| 1764 | ||
| 1765 | try stream.print("hash({}) ", .{std.fmt.fmtSliceHexLower(&fields_hash)}); | |
| 1766 | ||
| 1767 | var extra_index: usize = extra.end; | |
| 1737 | 1768 | |
| 1738 | 1769 | const src_node: ?i32 = if (small.has_src_node) blk: { |
| 1739 | 1770 | const src_node = @as(i32, @bitCast(self.code.extra[extra_index])); |
src/type.zig+12| ... | ... | @@ -4,6 +4,7 @@ const Value = @import("Value.zig"); |
| 4 | 4 | const assert = std.debug.assert; |
| 5 | 5 | const Target = std.Target; |
| 6 | 6 | const Module = @import("Module.zig"); |
| 7 | const Zcu = Module; | |
| 7 | 8 | const log = std.log.scoped(.Type); |
| 8 | 9 | const target_util = @import("target.zig"); |
| 9 | 10 | const TypedValue = @import("TypedValue.zig"); |
| ... | ... | @@ -3228,6 +3229,17 @@ pub const Type = struct { |
| 3228 | 3229 | }; |
| 3229 | 3230 | } |
| 3230 | 3231 | |
| 3232 | pub fn typeDeclInst(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index { | |
| 3233 | return switch (zcu.intern_pool.indexToKey(ty.toIntern())) { | |
| 3234 | inline .struct_type, | |
| 3235 | .union_type, | |
| 3236 | .enum_type, | |
| 3237 | .opaque_type, | |
| 3238 | => |info| info.zir_index.unwrap(), | |
| 3239 | else => null, | |
| 3240 | }; | |
| 3241 | } | |
| 3242 | ||
| 3231 | 3243 | pub const @"u1": Type = .{ .ip_index = .u1_type }; |
| 3232 | 3244 | pub const @"u8": Type = .{ .ip_index = .u8_type }; |
| 3233 | 3245 | pub const @"u16": Type = .{ .ip_index = .u16_type }; |