authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-16 10:47:42-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-07-16 10:47:42-07:00
loga58ceb3d554a9565a6cc0443f6384149ae2b3145
treeaf66e289a0ae028be92389722979ed270b42ee42
parenta9d544575d5bd2a939b09b8f088bee5d8ff7b0d9
parent7dbd2a6bb549afa6dc3c95df46f40bf144db23a6
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #20646 from ziglang/fix-updateZirRefs

frontend: fix updateZirRefs

8 files changed, 194 insertions(+), 164 deletions(-)

lib/std/zig/Zir.zig+6-4
...@@ -1,5 +1,7 @@...@@ -1,5 +1,7 @@
1//! Zig Intermediate Representation. Astgen.zig converts AST nodes to these1//! Zig Intermediate Representation.
2//! untyped IR instructions. Next, Sema.zig processes these into AIR.2//!
3//! Astgen.zig converts AST nodes to these untyped IR instructions. Next,
4//! Sema.zig processes these into AIR.
3//! The minimum amount of information needed to represent a list of ZIR instructions.5//! The minimum amount of information needed to represent a list of ZIR instructions.
4//! Once this structure is completed, it can be used to generate AIR, followed by6//! Once this structure is completed, it can be used to generate AIR, followed by
5//! machine code, without any memory access into the AST tree token list, node list,7//! machine code, without any memory access into the AST tree token list, node list,
...@@ -4024,8 +4026,8 @@ pub fn getAssociatedSrcHash(zir: Zir, inst: Zir.Inst.Index) ?std.zig.SrcHash {...@@ -4024,8 +4026,8 @@ pub fn getAssociatedSrcHash(zir: Zir, inst: Zir.Inst.Index) ?std.zig.SrcHash {
4024 const data = zir.instructions.items(.data);4026 const data = zir.instructions.items(.data);
4025 switch (tag[@intFromEnum(inst)]) {4027 switch (tag[@intFromEnum(inst)]) {
4026 .declaration => {4028 .declaration => {
4027 const pl_node = data[@intFromEnum(inst)].pl_node;4029 const declaration = data[@intFromEnum(inst)].declaration;
4028 const extra = zir.extraData(Inst.Declaration, pl_node.payload_index);4030 const extra = zir.extraData(Inst.Declaration, declaration.payload_index);
4029 return @bitCast([4]u32{4031 return @bitCast([4]u32{
4030 extra.data.src_hash_0,4032 extra.data.src_hash_0,
4031 extra.data.src_hash_1,4033 extra.data.src_hash_1,
src/Air.zig+1-2
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1//! Analyzed Intermediate Representation.1//! Analyzed Intermediate Representation.
2//!
2//! This data is produced by Sema and consumed by codegen.3//! This data is produced by Sema and consumed by codegen.
3//! Unlike ZIR where there is one instance for an entire source file, each function4//! Unlike ZIR where there is one instance for an entire source file, each function
4//! gets its own `Air` instance.5//! gets its own `Air` instance.
...@@ -12,8 +13,6 @@ const Value = @import("Value.zig");...@@ -12,8 +13,6 @@ const Value = @import("Value.zig");
12const Type = @import("Type.zig");13const Type = @import("Type.zig");
13const InternPool = @import("InternPool.zig");14const InternPool = @import("InternPool.zig");
14const Zcu = @import("Zcu.zig");15const Zcu = @import("Zcu.zig");
15/// Deprecated.
16const Module = Zcu;
1716
18instructions: std.MultiArrayList(Inst).Slice,17instructions: std.MultiArrayList(Inst).Slice,
19/// The meaning of this data is determined by `Inst.Tag` value.18/// The meaning of this data is determined by `Inst.Tag` value.
src/Compilation.zig+7-2
...@@ -3595,7 +3595,12 @@ fn performAllTheWorkInner(...@@ -3595,7 +3595,12 @@ fn performAllTheWorkInner(
3595 }3595 }
35963596
3597 if (comp.module) |zcu| {3597 if (comp.module) |zcu| {
3598 const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = .main };3598 const pt: Zcu.PerThread = .{ .zcu = zcu, .tid = .main };
3599 if (comp.incremental) {
3600 const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0);
3601 defer update_zir_refs_node.end();
3602 try pt.updateZirRefs();
3603 }
3599 try reportMultiModuleErrors(pt);3604 try reportMultiModuleErrors(pt);
3600 try zcu.flushRetryableFailures();3605 try zcu.flushRetryableFailures();
3601 zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);3606 zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
...@@ -4306,7 +4311,7 @@ fn workerAstGenFile(...@@ -4306,7 +4311,7 @@ fn workerAstGenFile(
4306 defer child_prog_node.end();4311 defer child_prog_node.end();
43074312
4308 const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = @enumFromInt(tid) };4313 const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = @enumFromInt(tid) };
4309 pt.astGenFile(file, file_index, path_digest, root_decl) catch |err| switch (err) {4314 pt.astGenFile(file, path_digest, root_decl) catch |err| switch (err) {
4310 error.AnalysisFail => return,4315 error.AnalysisFail => return,
4311 else => {4316 else => {
4312 file.status = .retryable_failure;4317 file.status = .retryable_failure;
src/InternPool.zig+6-4
...@@ -283,10 +283,12 @@ pub const DependencyIterator = struct {...@@ -283,10 +283,12 @@ pub const DependencyIterator = struct {
283 ip: *const InternPool,283 ip: *const InternPool,
284 next_entry: DepEntry.Index.Optional,284 next_entry: DepEntry.Index.Optional,
285 pub fn next(it: *DependencyIterator) ?AnalUnit {285 pub fn next(it: *DependencyIterator) ?AnalUnit {
286 const idx = it.next_entry.unwrap() orelse return null;286 while (true) {
287 const entry = it.ip.dep_entries.items[@intFromEnum(idx)];287 const idx = it.next_entry.unwrap() orelse return null;
288 it.next_entry = entry.next;288 const entry = it.ip.dep_entries.items[@intFromEnum(idx)];
289 return entry.depender.unwrap().?;289 it.next_entry = entry.next;
290 if (entry.depender.unwrap()) |depender| return depender;
291 }
290 }292 }
291};293};
292294
src/Sema.zig+1-1
...@@ -6065,7 +6065,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -6065,7 +6065,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
60656065
6066 const path_digest = zcu.filePathDigest(result.file_index);6066 const path_digest = zcu.filePathDigest(result.file_index);
6067 const root_decl = zcu.fileRootDecl(result.file_index);6067 const root_decl = zcu.fileRootDecl(result.file_index);
6068 pt.astGenFile(result.file, result.file_index, path_digest, root_decl) catch |err|6068 pt.astGenFile(result.file, path_digest, root_decl) catch |err|
6069 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});6069 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
60706070
6071 try pt.ensureFileAnalyzed(result.file_index);6071 try pt.ensureFileAnalyzed(result.file_index);
src/Zcu.zig+29-28
...@@ -1,5 +1,8 @@...@@ -1,5 +1,8 @@
1//! Compilation of all Zig source code is represented by one `Module`.1//! Zig Compilation Unit
2//! Each `Compilation` has exactly one or zero `Module`, depending on whether2//!
3//! Compilation of all Zig source code is represented by one `Zcu`.
4//!
5//! Each `Compilation` has exactly one or zero `Zcu`, depending on whether
3//! there is or is not any zig source code, respectively.6//! there is or is not any zig source code, respectively.
47
5const std = @import("std");8const std = @import("std");
...@@ -13,8 +16,6 @@ const BigIntMutable = std.math.big.int.Mutable;...@@ -13,8 +16,6 @@ const BigIntMutable = std.math.big.int.Mutable;
13const Target = std.Target;16const Target = std.Target;
14const Ast = std.zig.Ast;17const Ast = std.zig.Ast;
1518
16/// Deprecated, use `Zcu`.
17const Module = Zcu;
18const Zcu = @This();19const Zcu = @This();
19const Compilation = @import("Compilation.zig");20const Compilation = @import("Compilation.zig");
20const Cache = std.Build.Cache;21const Cache = std.Build.Cache;
...@@ -2393,7 +2394,7 @@ pub const CompileError = error{...@@ -2393,7 +2394,7 @@ pub const CompileError = error{
2393 ComptimeBreak,2394 ComptimeBreak,
2394};2395};
23952396
2396pub fn init(mod: *Module, thread_count: usize) !void {2397pub fn init(mod: *Zcu, thread_count: usize) !void {
2397 const gpa = mod.gpa;2398 const gpa = mod.gpa;
2398 try mod.intern_pool.init(gpa, thread_count);2399 try mod.intern_pool.init(gpa, thread_count);
2399}2400}
...@@ -2487,20 +2488,20 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2487,20 +2488,20 @@ pub fn deinit(zcu: *Zcu) void {
2487 zcu.intern_pool.deinit(gpa);2488 zcu.intern_pool.deinit(gpa);
2488}2489}
24892490
2490pub fn declPtr(mod: *Module, index: Decl.Index) *Decl {2491pub fn declPtr(mod: *Zcu, index: Decl.Index) *Decl {
2491 return mod.intern_pool.declPtr(index);2492 return mod.intern_pool.declPtr(index);
2492}2493}
24932494
2494pub fn namespacePtr(mod: *Module, index: Namespace.Index) *Namespace {2495pub fn namespacePtr(mod: *Zcu, index: Namespace.Index) *Namespace {
2495 return mod.intern_pool.namespacePtr(index);2496 return mod.intern_pool.namespacePtr(index);
2496}2497}
24972498
2498pub fn namespacePtrUnwrap(mod: *Module, index: Namespace.OptionalIndex) ?*Namespace {2499pub fn namespacePtrUnwrap(mod: *Zcu, index: Namespace.OptionalIndex) ?*Namespace {
2499 return mod.namespacePtr(index.unwrap() orelse return null);2500 return mod.namespacePtr(index.unwrap() orelse return null);
2500}2501}
25012502
2502/// Returns true if and only if the Decl is the top level struct associated with a File.2503/// Returns true if and only if the Decl is the top level struct associated with a File.
2503pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool {2504pub fn declIsRoot(mod: *Zcu, decl_index: Decl.Index) bool {
2504 const decl = mod.declPtr(decl_index);2505 const decl = mod.declPtr(decl_index);
2505 const namespace = mod.namespacePtr(decl.src_namespace);2506 const namespace = mod.namespacePtr(decl.src_namespace);
2506 if (namespace.parent != .none) return false;2507 if (namespace.parent != .none) return false;
...@@ -2940,7 +2941,7 @@ pub fn mapOldZirToNew(...@@ -2940,7 +2941,7 @@ pub fn mapOldZirToNew(
2940/// analyzed, and for ensuring it can exist at runtime (see2941/// analyzed, and for ensuring it can exist at runtime (see
2941/// `sema.fnHasRuntimeBits`). This function does *not* guarantee that the body2942/// `sema.fnHasRuntimeBits`). This function does *not* guarantee that the body
2942/// will be analyzed when it returns: for that, see `ensureFuncBodyAnalyzed`.2943/// will be analyzed when it returns: for that, see `ensureFuncBodyAnalyzed`.
2943pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index) !void {2944pub fn ensureFuncBodyAnalysisQueued(mod: *Zcu, func_index: InternPool.Index) !void {
2944 const ip = &mod.intern_pool;2945 const ip = &mod.intern_pool;
2945 const func = mod.funcInfo(func_index);2946 const func = mod.funcInfo(func_index);
2946 const decl_index = func.owner_decl;2947 const decl_index = func.owner_decl;
...@@ -3102,13 +3103,13 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit...@@ -3102,13 +3103,13 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit
3102 gop.value_ptr.* = @intCast(ref_idx);3103 gop.value_ptr.* = @intCast(ref_idx);
3103}3104}
31043105
3105pub fn errorSetBits(mod: *Module) u16 {3106pub fn errorSetBits(mod: *Zcu) u16 {
3106 if (mod.error_limit == 0) return 0;3107 if (mod.error_limit == 0) return 0;
3107 return std.math.log2_int_ceil(ErrorInt, mod.error_limit + 1); // +1 for no error3108 return std.math.log2_int_ceil(ErrorInt, mod.error_limit + 1); // +1 for no error
3108}3109}
31093110
3110pub fn errNote(3111pub fn errNote(
3111 mod: *Module,3112 mod: *Zcu,
3112 src_loc: LazySrcLoc,3113 src_loc: LazySrcLoc,
3113 parent: *ErrorMsg,3114 parent: *ErrorMsg,
3114 comptime format: []const u8,3115 comptime format: []const u8,
...@@ -3138,7 +3139,7 @@ pub fn optimizeMode(zcu: *const Zcu) std.builtin.OptimizeMode {...@@ -3138,7 +3139,7 @@ pub fn optimizeMode(zcu: *const Zcu) std.builtin.OptimizeMode {
3138 return zcu.root_mod.optimize_mode;3139 return zcu.root_mod.optimize_mode;
3139}3140}
31403141
3141fn lockAndClearFileCompileError(mod: *Module, file: *File) void {3142fn lockAndClearFileCompileError(mod: *Zcu, file: *File) void {
3142 switch (file.status) {3143 switch (file.status) {
3143 .success_zir, .retryable_failure => {},3144 .success_zir, .retryable_failure => {},
3144 .never_loaded, .parse_failure, .astgen_failure => {3145 .never_loaded, .parse_failure, .astgen_failure => {
...@@ -3172,7 +3173,7 @@ pub fn handleUpdateExports(...@@ -3172,7 +3173,7 @@ pub fn handleUpdateExports(
3172 };3173 };
3173}3174}
31743175
3175pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u8) !void {3176pub fn addGlobalAssembly(mod: *Zcu, decl_index: Decl.Index, source: []const u8) !void {
3176 const gop = try mod.global_assembly.getOrPut(mod.gpa, decl_index);3177 const gop = try mod.global_assembly.getOrPut(mod.gpa, decl_index);
3177 if (gop.found_existing) {3178 if (gop.found_existing) {
3178 const new_value = try std.fmt.allocPrint(mod.gpa, "{s}\n{s}", .{ gop.value_ptr.*, source });3179 const new_value = try std.fmt.allocPrint(mod.gpa, "{s}\n{s}", .{ gop.value_ptr.*, source });
...@@ -3226,7 +3227,7 @@ pub const AtomicPtrAlignmentDiagnostics = struct {...@@ -3226,7 +3227,7 @@ pub const AtomicPtrAlignmentDiagnostics = struct {
3226// TODO this function does not take into account CPU features, which can affect3227// TODO this function does not take into account CPU features, which can affect
3227// this value. Audit this!3228// this value. Audit this!
3228pub fn atomicPtrAlignment(3229pub fn atomicPtrAlignment(
3229 mod: *Module,3230 mod: *Zcu,
3230 ty: Type,3231 ty: Type,
3231 diags: *AtomicPtrAlignmentDiagnostics,3232 diags: *AtomicPtrAlignmentDiagnostics,
3232) AtomicPtrAlignmentError!Alignment {3233) AtomicPtrAlignmentError!Alignment {
...@@ -3332,7 +3333,7 @@ pub fn atomicPtrAlignment(...@@ -3332,7 +3333,7 @@ pub fn atomicPtrAlignment(
3332 return error.BadType;3333 return error.BadType;
3333}3334}
33343335
3335pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File {3336pub fn declFileScope(mod: *Zcu, decl_index: Decl.Index) *File {
3336 return mod.declPtr(decl_index).getFileScope(mod);3337 return mod.declPtr(decl_index).getFileScope(mod);
3337}3338}
33383339
...@@ -3340,7 +3341,7 @@ pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File {...@@ -3340,7 +3341,7 @@ pub fn declFileScope(mod: *Module, decl_index: Decl.Index) *File {
3340/// * `@TypeOf(.{})`3341/// * `@TypeOf(.{})`
3341/// * A struct which has no fields (`struct {}`).3342/// * A struct which has no fields (`struct {}`).
3342/// * Not a struct.3343/// * Not a struct.
3343pub fn typeToStruct(mod: *Module, ty: Type) ?InternPool.LoadedStructType {3344pub fn typeToStruct(mod: *Zcu, ty: Type) ?InternPool.LoadedStructType {
3344 if (ty.ip_index == .none) return null;3345 if (ty.ip_index == .none) return null;
3345 const ip = &mod.intern_pool;3346 const ip = &mod.intern_pool;
3346 return switch (ip.indexToKey(ty.ip_index)) {3347 return switch (ip.indexToKey(ty.ip_index)) {
...@@ -3349,13 +3350,13 @@ pub fn typeToStruct(mod: *Module, ty: Type) ?InternPool.LoadedStructType {...@@ -3349,13 +3350,13 @@ pub fn typeToStruct(mod: *Module, ty: Type) ?InternPool.LoadedStructType {
3349 };3350 };
3350}3351}
33513352
3352pub fn typeToPackedStruct(mod: *Module, ty: Type) ?InternPool.LoadedStructType {3353pub fn typeToPackedStruct(mod: *Zcu, ty: Type) ?InternPool.LoadedStructType {
3353 const s = mod.typeToStruct(ty) orelse return null;3354 const s = mod.typeToStruct(ty) orelse return null;
3354 if (s.layout != .@"packed") return null;3355 if (s.layout != .@"packed") return null;
3355 return s;3356 return s;
3356}3357}
33573358
3358pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.LoadedUnionType {3359pub fn typeToUnion(mod: *Zcu, ty: Type) ?InternPool.LoadedUnionType {
3359 if (ty.ip_index == .none) return null;3360 if (ty.ip_index == .none) return null;
3360 const ip = &mod.intern_pool;3361 const ip = &mod.intern_pool;
3361 return switch (ip.indexToKey(ty.ip_index)) {3362 return switch (ip.indexToKey(ty.ip_index)) {
...@@ -3364,32 +3365,32 @@ pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.LoadedUnionType {...@@ -3364,32 +3365,32 @@ pub fn typeToUnion(mod: *Module, ty: Type) ?InternPool.LoadedUnionType {
3364 };3365 };
3365}3366}
33663367
3367pub fn typeToFunc(mod: *Module, ty: Type) ?InternPool.Key.FuncType {3368pub fn typeToFunc(mod: *Zcu, ty: Type) ?InternPool.Key.FuncType {
3368 if (ty.ip_index == .none) return null;3369 if (ty.ip_index == .none) return null;
3369 return mod.intern_pool.indexToFuncType(ty.toIntern());3370 return mod.intern_pool.indexToFuncType(ty.toIntern());
3370}3371}
33713372
3372pub fn funcOwnerDeclPtr(mod: *Module, func_index: InternPool.Index) *Decl {3373pub fn funcOwnerDeclPtr(mod: *Zcu, func_index: InternPool.Index) *Decl {
3373 return mod.declPtr(mod.funcOwnerDeclIndex(func_index));3374 return mod.declPtr(mod.funcOwnerDeclIndex(func_index));
3374}3375}
33753376
3376pub fn funcOwnerDeclIndex(mod: *Module, func_index: InternPool.Index) Decl.Index {3377pub fn funcOwnerDeclIndex(mod: *Zcu, func_index: InternPool.Index) Decl.Index {
3377 return mod.funcInfo(func_index).owner_decl;3378 return mod.funcInfo(func_index).owner_decl;
3378}3379}
33793380
3380pub fn iesFuncIndex(mod: *const Module, ies_index: InternPool.Index) InternPool.Index {3381pub fn iesFuncIndex(mod: *const Zcu, ies_index: InternPool.Index) InternPool.Index {
3381 return mod.intern_pool.iesFuncIndex(ies_index);3382 return mod.intern_pool.iesFuncIndex(ies_index);
3382}3383}
33833384
3384pub fn funcInfo(mod: *Module, func_index: InternPool.Index) InternPool.Key.Func {3385pub fn funcInfo(mod: *Zcu, func_index: InternPool.Index) InternPool.Key.Func {
3385 return mod.intern_pool.indexToKey(func_index).func;3386 return mod.intern_pool.indexToKey(func_index).func;
3386}3387}
33873388
3388pub fn toEnum(mod: *Module, comptime E: type, val: Value) E {3389pub fn toEnum(mod: *Zcu, comptime E: type, val: Value) E {
3389 return mod.intern_pool.toEnum(E, val.toIntern());3390 return mod.intern_pool.toEnum(E, val.toIntern());
3390}3391}
33913392
3392pub fn isAnytypeParam(mod: *Module, func: InternPool.Index, index: u32) bool {3393pub fn isAnytypeParam(mod: *Zcu, func: InternPool.Index, index: u32) bool {
3393 const file = mod.declPtr(func.owner_decl).getFileScope(mod);3394 const file = mod.declPtr(func.owner_decl).getFileScope(mod);
33943395
3395 const tags = file.zir.instructions.items(.tag);3396 const tags = file.zir.instructions.items(.tag);
...@@ -3404,7 +3405,7 @@ pub fn isAnytypeParam(mod: *Module, func: InternPool.Index, index: u32) bool {...@@ -3404,7 +3405,7 @@ pub fn isAnytypeParam(mod: *Module, func: InternPool.Index, index: u32) bool {
3404 };3405 };
3405}3406}
34063407
3407pub fn getParamName(mod: *Module, func_index: InternPool.Index, index: u32) [:0]const u8 {3408pub fn getParamName(mod: *Zcu, func_index: InternPool.Index, index: u32) [:0]const u8 {
3408 const func = mod.funcInfo(func_index);3409 const func = mod.funcInfo(func_index);
3409 const file = mod.declPtr(func.owner_decl).getFileScope(mod);3410 const file = mod.declPtr(func.owner_decl).getFileScope(mod);
34103411
...@@ -3441,7 +3442,7 @@ pub const UnionLayout = struct {...@@ -3441,7 +3442,7 @@ pub const UnionLayout = struct {
3441};3442};
34423443
3443/// Returns the index of the active field, given the current tag value3444/// Returns the index of the active field, given the current tag value
3444pub fn unionTagFieldIndex(mod: *Module, loaded_union: InternPool.LoadedUnionType, enum_tag: Value) ?u32 {3445pub fn unionTagFieldIndex(mod: *Zcu, loaded_union: InternPool.LoadedUnionType, enum_tag: Value) ?u32 {
3445 const ip = &mod.intern_pool;3446 const ip = &mod.intern_pool;
3446 if (enum_tag.toIntern() == .none) return null;3447 if (enum_tag.toIntern() == .none) return null;
3447 assert(ip.typeOf(enum_tag.toIntern()) == loaded_union.enum_tag_ty);3448 assert(ip.typeOf(enum_tag.toIntern()) == loaded_union.enum_tag_ty);
src/Zcu/PerThread.zig+141-123
...@@ -60,10 +60,6 @@ pub fn destroyFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) void {...@@ -60,10 +60,6 @@ pub fn destroyFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) void {
60pub fn astGenFile(60pub fn astGenFile(
61 pt: Zcu.PerThread,61 pt: Zcu.PerThread,
62 file: *Zcu.File,62 file: *Zcu.File,
63 /// This parameter is provided separately from `file` because it is not
64 /// safe to access `import_table` without a lock, and this index is needed
65 /// in the call to `updateZirRefs`.
66 file_index: Zcu.File.Index,
67 path_digest: Cache.BinDigest,63 path_digest: Cache.BinDigest,
68 opt_root_decl: Zcu.Decl.OptionalIndex,64 opt_root_decl: Zcu.Decl.OptionalIndex,
69) !void {65) !void {
...@@ -210,13 +206,18 @@ pub fn astGenFile(...@@ -210,13 +206,18 @@ pub fn astGenFile(
210206
211 pt.lockAndClearFileCompileError(file);207 pt.lockAndClearFileCompileError(file);
212208
213 // If the previous ZIR does not have compile errors, keep it around209 // Previous ZIR is kept for two reasons:
214 // in case parsing or new ZIR fails. In case of successful ZIR update210 //
215 // at the end of this function we will free it.211 // 1. In case an update to the file causes a Parse or AstGen failure, we
216 // We keep the previous ZIR loaded so that we can use it212 // need to compare two successful ZIR files in order to proceed with an
217 // for the update next time it does not have any compile errors. This avoids213 // incremental update. This avoids needlessly tossing out semantic
218 // needlessly tossing out semantic analysis work when an error is214 // analysis work when an error is temporarily introduced.
219 // temporarily introduced.215 //
216 // 2. In order to detect updates, we need to iterate over the intern pool
217 // values while comparing old ZIR to new ZIR. This is better done in a
218 // single-threaded context, so we need to keep both versions around
219 // until that point in the pipeline. Previous ZIR data is freed after
220 // that.
220 if (file.zir_loaded and !file.zir.hasCompileErrors()) {221 if (file.zir_loaded and !file.zir.hasCompileErrors()) {
221 assert(file.prev_zir == null);222 assert(file.prev_zir == null);
222 const prev_zir_ptr = try gpa.create(Zir);223 const prev_zir_ptr = try gpa.create(Zir);
...@@ -320,14 +321,6 @@ pub fn astGenFile(...@@ -320,14 +321,6 @@ pub fn astGenFile(
320 return error.AnalysisFail;321 return error.AnalysisFail;
321 }322 }
322323
323 if (file.prev_zir) |prev_zir| {
324 try pt.updateZirRefs(file, file_index, prev_zir.*);
325 // No need to keep previous ZIR.
326 prev_zir.deinit(gpa);
327 gpa.destroy(prev_zir);
328 file.prev_zir = null;
329 }
330
331 if (opt_root_decl.unwrap()) |root_decl| {324 if (opt_root_decl.unwrap()) |root_decl| {
332 // The root of this file must be re-analyzed, since the file has changed.325 // The root of this file must be re-analyzed, since the file has changed.
333 comp.mutex.lock();326 comp.mutex.lock();
...@@ -338,137 +331,162 @@ pub fn astGenFile(...@@ -338,137 +331,162 @@ pub fn astGenFile(
338 }331 }
339}332}
340333
341/// This is called from the AstGen thread pool, so must acquire334const UpdatedFile = struct {
342/// the Compilation mutex when acting on shared state.335 file_index: Zcu.File.Index,
343fn updateZirRefs(pt: Zcu.PerThread, file: *Zcu.File, file_index: Zcu.File.Index, old_zir: Zir) !void {336 file: *Zcu.File,
337 inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index),
338};
339
340fn cleanupUpdatedFiles(gpa: Allocator, updated_files: *std.ArrayListUnmanaged(UpdatedFile)) void {
341 for (updated_files.items) |*elem| elem.inst_map.deinit(gpa);
342 updated_files.deinit(gpa);
343}
344
345pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
346 assert(pt.tid == .main);
344 const zcu = pt.zcu;347 const zcu = pt.zcu;
345 const ip = &zcu.intern_pool;348 const ip = &zcu.intern_pool;
346 const gpa = zcu.gpa;349 const gpa = zcu.gpa;
347 const new_zir = file.zir;
348
349 var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};
350 defer inst_map.deinit(gpa);
351350
352 try Zcu.mapOldZirToNew(gpa, old_zir, new_zir, &inst_map);351 // We need to visit every updated File for every TrackedInst in InternPool.
352 var updated_files: std.ArrayListUnmanaged(UpdatedFile) = .{};
353 defer cleanupUpdatedFiles(gpa, &updated_files);
354 for (zcu.import_table.values()) |file_index| {
355 const file = zcu.fileByIndex(file_index);
356 const old_zir = file.prev_zir orelse continue;
357 const new_zir = file.zir;
358 try updated_files.append(gpa, .{
359 .file_index = file_index,
360 .file = file,
361 .inst_map = .{},
362 });
363 const inst_map = &updated_files.items[updated_files.items.len - 1].inst_map;
364 try Zcu.mapOldZirToNew(gpa, old_zir.*, new_zir, inst_map);
365 }
353366
354 const old_tag = old_zir.instructions.items(.tag);367 if (updated_files.items.len == 0)
355 const old_data = old_zir.instructions.items(.data);368 return;
356369
357 // TODO: this should be done after all AstGen workers complete, to avoid
358 // iterating over this full set for every updated file.
359 for (ip.locals, 0..) |*local, tid| {370 for (ip.locals, 0..) |*local, tid| {
360 local.mutate.tracked_insts.mutex.lock();
361 defer local.mutate.tracked_insts.mutex.unlock();
362 const tracked_insts_list = local.getMutableTrackedInsts(gpa);371 const tracked_insts_list = local.getMutableTrackedInsts(gpa);
363 for (tracked_insts_list.view().items(.@"0"), 0..) |*tracked_inst, tracked_inst_unwrapped_index| {372 for (tracked_insts_list.view().items(.@"0"), 0..) |*tracked_inst, tracked_inst_unwrapped_index| {
364 if (tracked_inst.file != file_index) continue;373 for (updated_files.items) |updated_file| {
365 const old_inst = tracked_inst.inst;374 const file_index = updated_file.file_index;
366 const tracked_inst_index = (InternPool.TrackedInst.Index.Unwrapped{375 if (tracked_inst.file != file_index) continue;
367 .tid = @enumFromInt(tid),376
368 .index = @intCast(tracked_inst_unwrapped_index),377 const file = updated_file.file;
369 }).wrap(ip);378 const old_zir = file.prev_zir.?.*;
370 tracked_inst.inst = inst_map.get(old_inst) orelse {379 const new_zir = file.zir;
371 // Tracking failed for this instruction. Invalidate associated `src_hash` deps.380 const old_tag = old_zir.instructions.items(.tag);
372 zcu.comp.mutex.lock();381 const old_data = old_zir.instructions.items(.data);
373 defer zcu.comp.mutex.unlock();382 const inst_map = &updated_file.inst_map;
374 log.debug("tracking failed for %{d}", .{old_inst});383
375 try zcu.markDependeeOutdated(.{ .src_hash = tracked_inst_index });384 const old_inst = tracked_inst.inst;
376 continue;385 const tracked_inst_index = (InternPool.TrackedInst.Index.Unwrapped{
377 };386 .tid = @enumFromInt(tid),
387 .index = @intCast(tracked_inst_unwrapped_index),
388 }).wrap(ip);
389 tracked_inst.inst = inst_map.get(old_inst) orelse {
390 // Tracking failed for this instruction. Invalidate associated `src_hash` deps.
391 log.debug("tracking failed for %{d}", .{old_inst});
392 try zcu.markDependeeOutdated(.{ .src_hash = tracked_inst_index });
393 continue;
394 };
378395
379 if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: {396 if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: {
380 if (new_zir.getAssociatedSrcHash(tracked_inst.inst)) |new_hash| {397 if (new_zir.getAssociatedSrcHash(tracked_inst.inst)) |new_hash| {
381 if (std.zig.srcHashEql(old_hash, new_hash)) {398 if (std.zig.srcHashEql(old_hash, new_hash)) {
382 break :hash_changed;399 break :hash_changed;
400 }
401 log.debug("hash for (%{d} -> %{d}) changed: {} -> {}", .{
402 old_inst,
403 tracked_inst.inst,
404 std.fmt.fmtSliceHexLower(&old_hash),
405 std.fmt.fmtSliceHexLower(&new_hash),
406 });
383 }407 }
384 log.debug("hash for (%{d} -> %{d}) changed: {} -> {}", .{408 // The source hash associated with this instruction changed - invalidate relevant dependencies.
385 old_inst,409 try zcu.markDependeeOutdated(.{ .src_hash = tracked_inst_index });
386 tracked_inst.inst,
387 std.fmt.fmtSliceHexLower(&old_hash),
388 std.fmt.fmtSliceHexLower(&new_hash),
389 });
390 }410 }
391 // The source hash associated with this instruction changed - invalidate relevant dependencies.
392 zcu.comp.mutex.lock();
393 defer zcu.comp.mutex.unlock();
394 try zcu.markDependeeOutdated(.{ .src_hash = tracked_inst_index });
395 }
396411
397 // If this is a `struct_decl` etc, we must invalidate any outdated namespace dependencies.412 // If this is a `struct_decl` etc, we must invalidate any outdated namespace dependencies.
398 const has_namespace = switch (old_tag[@intFromEnum(old_inst)]) {413 const has_namespace = switch (old_tag[@intFromEnum(old_inst)]) {
399 .extended => switch (old_data[@intFromEnum(old_inst)].extended.opcode) {414 .extended => switch (old_data[@intFromEnum(old_inst)].extended.opcode) {
400 .struct_decl, .union_decl, .opaque_decl, .enum_decl => true,415 .struct_decl, .union_decl, .opaque_decl, .enum_decl => true,
416 else => false,
417 },
401 else => false,418 else => false,
402 },419 };
403 else => false,420 if (!has_namespace) continue;
404 };421
405 if (!has_namespace) continue;422 var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
406423 defer old_names.deinit(zcu.gpa);
407 var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};424 {
408 defer old_names.deinit(zcu.gpa);425 var it = old_zir.declIterator(old_inst);
409 {426 while (it.next()) |decl_inst| {
410 var it = old_zir.declIterator(old_inst);427 const decl_name = old_zir.getDeclaration(decl_inst)[0].name;
411 while (it.next()) |decl_inst| {428 switch (decl_name) {
412 const decl_name = old_zir.getDeclaration(decl_inst)[0].name;429 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
413 switch (decl_name) {430 _ => if (decl_name.isNamedTest(old_zir)) continue,
414 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,431 }
415 _ => if (decl_name.isNamedTest(old_zir)) continue,432 const name_zir = decl_name.toString(old_zir).?;
433 const name_ip = try zcu.intern_pool.getOrPutString(
434 zcu.gpa,
435 pt.tid,
436 old_zir.nullTerminatedString(name_zir),
437 .no_embedded_nulls,
438 );
439 try old_names.put(zcu.gpa, name_ip, {});
416 }440 }
417 const name_zir = decl_name.toString(old_zir).?;
418 const name_ip = try zcu.intern_pool.getOrPutString(
419 zcu.gpa,
420 pt.tid,
421 old_zir.nullTerminatedString(name_zir),
422 .no_embedded_nulls,
423 );
424 try old_names.put(zcu.gpa, name_ip, {});
425 }441 }
426 }442 var any_change = false;
427 var any_change = false;443 {
428 {444 var it = new_zir.declIterator(tracked_inst.inst);
429 var it = new_zir.declIterator(tracked_inst.inst);445 while (it.next()) |decl_inst| {
430 while (it.next()) |decl_inst| {446 const decl_name = old_zir.getDeclaration(decl_inst)[0].name;
431 const decl_name = old_zir.getDeclaration(decl_inst)[0].name;447 switch (decl_name) {
432 switch (decl_name) {448 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
433 .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,449 _ => if (decl_name.isNamedTest(old_zir)) continue,
434 _ => if (decl_name.isNamedTest(old_zir)) continue,450 }
451 const name_zir = decl_name.toString(old_zir).?;
452 const name_ip = try zcu.intern_pool.getOrPutString(
453 zcu.gpa,
454 pt.tid,
455 old_zir.nullTerminatedString(name_zir),
456 .no_embedded_nulls,
457 );
458 if (!old_names.swapRemove(name_ip)) continue;
459 // Name added
460 any_change = true;
461 try zcu.markDependeeOutdated(.{ .namespace_name = .{
462 .namespace = tracked_inst_index,
463 .name = name_ip,
464 } });
435 }465 }
436 const name_zir = decl_name.toString(old_zir).?;466 }
437 const name_ip = try zcu.intern_pool.getOrPutString(467 // The only elements remaining in `old_names` now are any names which were removed.
438 zcu.gpa,468 for (old_names.keys()) |name_ip| {
439 pt.tid,
440 old_zir.nullTerminatedString(name_zir),
441 .no_embedded_nulls,
442 );
443 if (!old_names.swapRemove(name_ip)) continue;
444 // Name added
445 any_change = true;469 any_change = true;
446 zcu.comp.mutex.lock();
447 defer zcu.comp.mutex.unlock();
448 try zcu.markDependeeOutdated(.{ .namespace_name = .{470 try zcu.markDependeeOutdated(.{ .namespace_name = .{
449 .namespace = tracked_inst_index,471 .namespace = tracked_inst_index,
450 .name = name_ip,472 .name = name_ip,
451 } });473 } });
452 }474 }
453 }
454 // The only elements remaining in `old_names` now are any names which were removed.
455 for (old_names.keys()) |name_ip| {
456 any_change = true;
457 zcu.comp.mutex.lock();
458 defer zcu.comp.mutex.unlock();
459 try zcu.markDependeeOutdated(.{ .namespace_name = .{
460 .namespace = tracked_inst_index,
461 .name = name_ip,
462 } });
463 }
464475
465 if (any_change) {476 if (any_change) {
466 zcu.comp.mutex.lock();477 try zcu.markDependeeOutdated(.{ .namespace = tracked_inst_index });
467 defer zcu.comp.mutex.unlock();478 }
468 try zcu.markDependeeOutdated(.{ .namespace = tracked_inst_index });
469 }479 }
470 }480 }
471 }481 }
482
483 for (updated_files.items) |updated_file| {
484 const file = updated_file.file;
485 const prev_zir = file.prev_zir.?;
486 file.prev_zir = null;
487 prev_zir.deinit(gpa);
488 gpa.destroy(prev_zir);
489 }
472}490}
473491
474/// Like `ensureDeclAnalyzed`, but the Decl is a file's root Decl.492/// Like `ensureDeclAnalyzed`, but the Decl is a file's root Decl.
src/main.zig+3
...@@ -4230,6 +4230,9 @@ fn serveUpdateResults(s: *Server, comp: *Compilation) !void {...@@ -4230,6 +4230,9 @@ fn serveUpdateResults(s: *Server, comp: *Compilation) !void {
4230 });4230 });
4231 return;4231 return;
4232 }4232 }
4233
4234 // Serve empty error bundle to indicate the update is done.
4235 try s.serveErrorBundle(std.zig.ErrorBundle.empty);
4233}4236}
42344237
4235fn runOrTest(4238fn runOrTest(