authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-01-01 20:16:48+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-01-05 02:20:56+00:00
log065e10c95ccca509afecfecc849da9114e0000b2
treebd1c4bee8e3da377fa1da9254b442900c538a45d
parent136c5a916ed7e421461ac5839cc0e4c289b80f16
signaturelock-open Commit is signed but in an unrecognized format.

link: new incremental line number update API


14 files changed, 90 insertions(+), 71 deletions(-)

change_line_number created+16
...@@ -0,0 +1,16 @@
1#target=x86_64-linux-selfhosted
2#update=initial version
3#file=main.zig
4const std = @import("std");
5pub fn main() !void {
6 try std.io.getStdOut().writeAll("foo\n");
7}
8#expect_stdout="foo\n"
9#update=change line number
10#file=main.zig
11const std = @import("std");
12
13pub fn main() !void {
14 try std.io.getStdOut().writeAll("foo\n");
15}
16#expect_stdout="foo\n"
src/Compilation.zig+4
...@@ -348,6 +348,7 @@ const Job = union(enum) {...@@ -348,6 +348,7 @@ const Job = union(enum) {
348 /// Corresponds to the task in `link.Task`.348 /// Corresponds to the task in `link.Task`.
349 /// Only needed for backends that haven't yet been updated to not race against Sema.349 /// Only needed for backends that haven't yet been updated to not race against Sema.
350 codegen_type: InternPool.Index,350 codegen_type: InternPool.Index,
351 update_line_number: InternPool.TrackedInst.Index,
351 /// The `AnalUnit`, which is *not* a `func`, must be semantically analyzed.352 /// The `AnalUnit`, which is *not* a `func`, must be semantically analyzed.
352 /// This may be its first time being analyzed, or it may be outdated.353 /// This may be its first time being analyzed, or it may be outdated.
353 /// If the unit is a function, a `codegen_func` job will then be queued.354 /// If the unit is a function, a `codegen_func` job will then be queued.
...@@ -3718,6 +3719,9 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre...@@ -3718,6 +3719,9 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
3718 .codegen_type => |ty| {3719 .codegen_type => |ty| {
3719 comp.dispatchCodegenTask(tid, .{ .codegen_type = ty });3720 comp.dispatchCodegenTask(tid, .{ .codegen_type = ty });
3720 },3721 },
3722 .update_line_number => |ti| {
3723 comp.dispatchCodegenTask(tid, .{ .update_line_number = ti });
3724 },
3721 .analyze_func => |func| {3725 .analyze_func => |func| {
3722 const named_frame = tracy.namedFrame("analyze_func");3726 const named_frame = tracy.namedFrame("analyze_func");
3723 defer named_frame.end();3727 defer named_frame.end();
src/Zcu/PerThread.zig+25-6
...@@ -379,6 +379,7 @@ fn cleanupUpdatedFiles(gpa: Allocator, updated_files: *std.AutoArrayHashMapUnman...@@ -379,6 +379,7 @@ fn cleanupUpdatedFiles(gpa: Allocator, updated_files: *std.AutoArrayHashMapUnman
379pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {379pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
380 assert(pt.tid == .main);380 assert(pt.tid == .main);
381 const zcu = pt.zcu;381 const zcu = pt.zcu;
382 const comp = zcu.comp;
382 const ip = &zcu.intern_pool;383 const ip = &zcu.intern_pool;
383 const gpa = zcu.gpa;384 const gpa = zcu.gpa;
384385
...@@ -435,8 +436,19 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {...@@ -435,8 +436,19 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
435436
436 const old_zir = file.prev_zir.?.*;437 const old_zir = file.prev_zir.?.*;
437 const new_zir = file.zir;438 const new_zir = file.zir;
438 const old_tag = old_zir.instructions.items(.tag);439 const old_tag = old_zir.instructions.items(.tag)[@intFromEnum(old_inst)];
439 const old_data = old_zir.instructions.items(.data);440 const old_data = old_zir.instructions.items(.data)[@intFromEnum(old_inst)];
441
442 switch (old_tag) {
443 .declaration => {
444 const old_line = old_zir.getDeclaration(old_inst).src_line;
445 const new_line = new_zir.getDeclaration(new_inst).src_line;
446 if (old_line != new_line) {
447 try comp.queueJob(.{ .update_line_number = tracked_inst_index });
448 }
449 },
450 else => {},
451 }
440452
441 if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: {453 if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: {
442 if (new_zir.getAssociatedSrcHash(new_inst)) |new_hash| {454 if (new_zir.getAssociatedSrcHash(new_inst)) |new_hash| {
...@@ -455,8 +467,8 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {...@@ -455,8 +467,8 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
455 }467 }
456468
457 // If this is a `struct_decl` etc, we must invalidate any outdated namespace dependencies.469 // If this is a `struct_decl` etc, we must invalidate any outdated namespace dependencies.
458 const has_namespace = switch (old_tag[@intFromEnum(old_inst)]) {470 const has_namespace = switch (old_tag) {
459 .extended => switch (old_data[@intFromEnum(old_inst)].extended.opcode) {471 .extended => switch (old_data.extended.opcode) {
460 .struct_decl, .union_decl, .opaque_decl, .enum_decl => true,472 .struct_decl, .union_decl, .opaque_decl, .enum_decl => true,
461 else => false,473 else => false,
462 },474 },
...@@ -2517,8 +2529,6 @@ const ScanDeclIter = struct {...@@ -2517,8 +2529,6 @@ const ScanDeclIter = struct {
2517 );2529 );
2518 try comp.queueJob(.{ .analyze_comptime_unit = unit });2530 try comp.queueJob(.{ .analyze_comptime_unit = unit });
2519 }2531 }
2520
2521 // TODO: we used to do line number updates here, but this is an inappropriate place for this logic to live.
2522 }2532 }
2523};2533};
25242534
...@@ -3152,6 +3162,15 @@ pub fn linkerUpdateContainerType(pt: Zcu.PerThread, ty: InternPool.Index) !void...@@ -3152,6 +3162,15 @@ pub fn linkerUpdateContainerType(pt: Zcu.PerThread, ty: InternPool.Index) !void
3152 }3162 }
3153}3163}
31543164
3165pub fn linkerUpdateLineNumber(pt: Zcu.PerThread, ti: InternPool.TrackedInst.Index) !void {
3166 if (pt.zcu.comp.bin_file) |lf| {
3167 lf.updateLineNumber(pt, ti) catch |err| switch (err) {
3168 error.OutOfMemory => return error.OutOfMemory,
3169 else => |e| log.err("update line number failed: {s}", .{@errorName(e)}),
3170 };
3171 }
3172}
3173
3155pub fn reportRetryableAstGenError(3174pub fn reportRetryableAstGenError(
3156 pt: Zcu.PerThread,3175 pt: Zcu.PerThread,
3157 src: Zcu.AstGenSrc,3176 src: Zcu.AstGenSrc,
src/link.zig+21-6
...@@ -727,16 +727,22 @@ pub const File = struct {...@@ -727,16 +727,22 @@ pub const File = struct {
727 }727 }
728 }728 }
729729
730 pub fn updateNavLineNumber(730 /// On an incremental update, fixup the line number of all `Nav`s at the given `TrackedInst`, because
731 base: *File,731 /// its line number has changed. The ZIR instruction `ti_id` has tag `.declaration`.
732 pt: Zcu.PerThread,732 pub fn updateLineNumber(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) UpdateNavError!void {
733 nav_index: InternPool.Nav.Index,733 {
734 ) UpdateNavError!void {734 const ti = ti_id.resolveFull(&pt.zcu.intern_pool).?;
735 const file = pt.zcu.fileByIndex(ti.file);
736 assert(file.zir_loaded);
737 const inst = file.zir.instructions.get(@intFromEnum(ti.inst));
738 assert(inst.tag == .declaration);
739 }
740
735 switch (base.tag) {741 switch (base.tag) {
736 .spirv, .nvptx => {},742 .spirv, .nvptx => {},
737 inline else => |tag| {743 inline else => |tag| {
738 dev.check(tag.devFeature());744 dev.check(tag.devFeature());
739 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateNavineNumber(pt, nav_index);745 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateLineNumber(pt, ti_id);
740 },746 },
741 }747 }
742 }748 }
...@@ -1407,6 +1413,8 @@ pub const Task = union(enum) {...@@ -1407,6 +1413,8 @@ pub const Task = union(enum) {
1407 codegen_func: CodegenFunc,1413 codegen_func: CodegenFunc,
1408 codegen_type: InternPool.Index,1414 codegen_type: InternPool.Index,
14091415
1416 update_line_number: InternPool.TrackedInst.Index,
1417
1410 pub const CodegenFunc = struct {1418 pub const CodegenFunc = struct {
1411 /// This will either be a non-generic `func_decl` or a `func_instance`.1419 /// This will either be a non-generic `func_decl` or a `func_instance`.
1412 func: InternPool.Index,1420 func: InternPool.Index,
...@@ -1558,6 +1566,13 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {...@@ -1558,6 +1566,13 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {
1558 error.OutOfMemory => diags.setAllocFailure(),1566 error.OutOfMemory => diags.setAllocFailure(),
1559 };1567 };
1560 },1568 },
1569 .update_line_number => |ti| {
1570 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
1571 defer pt.deactivate();
1572 pt.linkerUpdateLineNumber(ti) catch |err| switch (err) {
1573 error.OutOfMemory => diags.setAllocFailure(),
1574 };
1575 },
1561 }1576 }
1562}1577}
15631578
src/link/C.zig+2-2
...@@ -379,12 +379,12 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !...@@ -379,12 +379,12 @@ pub fn updateNav(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !
379 gop.value_ptr.fwd_decl = try self.addString(object.dg.fwd_decl.items);379 gop.value_ptr.fwd_decl = try self.addString(object.dg.fwd_decl.items);
380}380}
381381
382pub fn updateNavLineNumber(self: *C, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void {382pub fn updateLineNumber(self: *C, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {
383 // The C backend does not have the ability to fix line numbers without re-generating383 // The C backend does not have the ability to fix line numbers without re-generating
384 // the entire Decl.384 // the entire Decl.
385 _ = self;385 _ = self;
386 _ = pt;386 _ = pt;
387 _ = nav_index;387 _ = ti_id;
388}388}
389389
390pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void {390pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) !void {
src/link/Coff.zig+3-3
...@@ -2484,11 +2484,11 @@ pub fn getGlobalSymbol(coff: *Coff, name: []const u8, lib_name_name: ?[]const u8...@@ -2484,11 +2484,11 @@ pub fn getGlobalSymbol(coff: *Coff, name: []const u8, lib_name_name: ?[]const u8
2484 return global_index;2484 return global_index;
2485}2485}
24862486
2487pub fn updateDeclLineNumber(coff: *Coff, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void {2487pub fn updateLineNumber(coff: *Coff, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {
2488 _ = coff;2488 _ = coff;
2489 _ = pt;2489 _ = pt;
2490 _ = decl_index;2490 _ = ti_id;
2491 log.debug("TODO implement updateDeclLineNumber", .{});2491 log.debug("TODO implement updateLineNumber", .{});
2492}2492}
24932493
2494/// TODO: note if we need to rewrite base relocations by dirtying any of the entries in the global table2494/// TODO: note if we need to rewrite base relocations by dirtying any of the entries in the global table
src/link/Dwarf.zig+5-15
...@@ -4156,21 +4156,11 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP...@@ -4156,21 +4156,11 @@ pub fn updateContainerType(dwarf: *Dwarf, pt: Zcu.PerThread, type_index: InternP
4156 }4156 }
4157}4157}
41584158
4159pub fn updateNavLineNumber(dwarf: *Dwarf, zcu: *Zcu, nav_index: InternPool.Nav.Index) UpdateError!void {4159pub fn updateLineNumber(dwarf: *Dwarf, zcu: *Zcu, ti_id: InternPool.TrackedInst.Index) UpdateError!void {
4160 const ip = &zcu.intern_pool;4160 _ = dwarf;
41614161 _ = zcu;
4162 const zir_index = ip.getCau(ip.getNav(nav_index).analysis_owner.unwrap() orelse return).zir_index;4162 _ = ti_id;
4163 const inst_info = zir_index.resolveFull(ip).?;4163 @panic("TODO: Dwarf.updateLineNumber");
4164 assert(inst_info.inst != .main_struct_inst);
4165 const file = zcu.fileByIndex(inst_info.file);
4166
4167 const line = file.zir.getDeclaration(inst_info.inst).src_line;
4168 var line_buf: [4]u8 = undefined;
4169 std.mem.writeInt(u32, &line_buf, line, dwarf.endian);
4170
4171 const unit = dwarf.debug_line.section.getUnit(dwarf.mods.get(file.mod).?);
4172 const entry = unit.getEntry(dwarf.navs.get(nav_index).?);
4173 try dwarf.getFile().?.pwriteAll(&line, dwarf.debug_line.section.off + unit.off + unit.header_len + entry.off + DebugInfo.declEntryLineOff(dwarf));
4174}4164}
41754165
4176pub fn freeNav(dwarf: *Dwarf, nav_index: InternPool.Nav.Index) void {4166pub fn freeNav(dwarf: *Dwarf, nav_index: InternPool.Nav.Index) void {
src/link/Elf.zig+2-2
...@@ -2372,9 +2372,9 @@ pub fn updateExports(...@@ -2372,9 +2372,9 @@ pub fn updateExports(
2372 return self.zigObjectPtr().?.updateExports(self, pt, exported, export_indices);2372 return self.zigObjectPtr().?.updateExports(self, pt, exported, export_indices);
2373}2373}
23742374
2375pub fn updateNavLineNumber(self: *Elf, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !void {2375pub fn updateLineNumber(self: *Elf, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {
2376 if (self.llvm_object) |_| return;2376 if (self.llvm_object) |_| return;
2377 return self.zigObjectPtr().?.updateNavLineNumber(pt, nav);2377 return self.zigObjectPtr().?.updateLineNumber(pt, ti_id);
2378}2378}
23792379
2380pub fn deleteExport(2380pub fn deleteExport(
src/link/Elf/ZigObject.zig+2-15
...@@ -1863,22 +1863,9 @@ pub fn updateExports(...@@ -1863,22 +1863,9 @@ pub fn updateExports(
1863 }1863 }
1864}1864}
18651865
1866/// Must be called only after a successful call to `updateNav`.1866pub fn updateLineNumber(self: *ZigObject, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {
1867pub fn updateNavLineNumber(
1868 self: *ZigObject,
1869 pt: Zcu.PerThread,
1870 nav_index: InternPool.Nav.Index,
1871) !void {
1872 const tracy = trace(@src());
1873 defer tracy.end();
1874
1875 const ip = &pt.zcu.intern_pool;
1876 const nav = ip.getNav(nav_index);
1877
1878 log.debug("updateNavLineNumber {}({d})", .{ nav.fqn.fmt(ip), nav_index });
1879
1880 if (self.dwarf) |*dwarf| {1867 if (self.dwarf) |*dwarf| {
1881 try dwarf.updateNavLineNumber(pt.zcu, nav_index);1868 try dwarf.updateLineNumber(pt.zcu, ti_id);
1882 }1869 }
1883}1870}
18841871
src/link/MachO.zig+2-2
...@@ -3014,9 +3014,9 @@ pub fn updateNav(self: *MachO, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !vo...@@ -3014,9 +3014,9 @@ pub fn updateNav(self: *MachO, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !vo
3014 return self.getZigObject().?.updateNav(self, pt, nav);3014 return self.getZigObject().?.updateNav(self, pt, nav);
3015}3015}
30163016
3017pub fn updateNavLineNumber(self: *MachO, pt: Zcu.PerThread, nav: InternPool.NavIndex) !void {3017pub fn updateLineNumber(self: *MachO, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {
3018 if (self.llvm_object) |_| return;3018 if (self.llvm_object) |_| return;
3019 return self.getZigObject().?.updateNavLineNumber(pt, nav);3019 return self.getZigObject().?.updateLineNumber(pt, ti_id);
3020}3020}
30213021
3022pub fn updateExports(3022pub fn updateExports(
src/link/MachO/ZigObject.zig+2-7
...@@ -1432,14 +1432,9 @@ fn updateLazySymbol(...@@ -1432,14 +1432,9 @@ fn updateLazySymbol(
1432 try macho_file.base.file.?.pwriteAll(code, file_offset);1432 try macho_file.base.file.?.pwriteAll(code, file_offset);
1433}1433}
14341434
1435/// Must be called only after a successful call to `updateNav`.1435pub fn updateLineNumber(self: *ZigObject, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {
1436pub fn updateNavLineNumber(
1437 self: *ZigObject,
1438 pt: Zcu.PerThread,
1439 nav_index: InternPool.Nav.Index,
1440) !void {
1441 if (self.dwarf) |*dwarf| {1436 if (self.dwarf) |*dwarf| {
1442 try dwarf.updateNavLineNumber(pt.zcu, nav_index);1437 try dwarf.updateLineNumber(pt.zcu, ti_id);
1443 }1438 }
1444}1439}
14451440
src/link/Plan9.zig+2-3
...@@ -1354,11 +1354,10 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {...@@ -1354,11 +1354,10 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
1354 }1354 }
1355}1355}
13561356
1357/// Must be called only after a successful call to `updateDecl`.1357pub fn updateLineNumber(self: *Plan9, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {
1358pub fn updateDeclLineNumber(self: *Plan9, pt: Zcu.PerThread, decl_index: InternPool.DeclIndex) !void {
1359 _ = self;1358 _ = self;
1360 _ = pt;1359 _ = pt;
1361 _ = decl_index;1360 _ = ti_id;
1362}1361}
13631362
1364pub fn getNavVAddr(1363pub fn getNavVAddr(
src/link/Wasm.zig+2-2
...@@ -1574,9 +1574,9 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !voi...@@ -1574,9 +1574,9 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !voi
1574 try wasm.zig_object.?.updateNav(wasm, pt, nav);1574 try wasm.zig_object.?.updateNav(wasm, pt, nav);
1575}1575}
15761576
1577pub fn updateNavLineNumber(wasm: *Wasm, pt: Zcu.PerThread, nav: InternPool.Nav.Index) !void {1577pub fn updateLineNumber(wasm: *Wasm, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {
1578 if (wasm.llvm_object) |_| return;1578 if (wasm.llvm_object) |_| return;
1579 try wasm.zig_object.?.updateNavLineNumber(pt, nav);1579 try wasm.zig_object.?.updateLineNumber(pt, ti_id);
1580}1580}
15811581
1582/// From a given symbol location, returns its `wasm.GlobalType`.1582/// From a given symbol location, returns its `wasm.GlobalType`.
src/link/Wasm/ZigObject.zig+2-8
...@@ -1074,15 +1074,9 @@ pub fn createDebugSectionForIndex(zig_object: *ZigObject, wasm: *Wasm, index: *?...@@ -1074,15 +1074,9 @@ pub fn createDebugSectionForIndex(zig_object: *ZigObject, wasm: *Wasm, index: *?
1074 return atom_index;1074 return atom_index;
1075}1075}
10761076
1077pub fn updateDeclLineNumber(1077pub fn updateLineNumber(zig_object: *ZigObject, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {
1078 zig_object: *ZigObject,
1079 pt: Zcu.PerThread,
1080 decl_index: InternPool.DeclIndex,
1081) !void {
1082 if (zig_object.dwarf) |*dw| {1078 if (zig_object.dwarf) |*dw| {
1083 const decl = pt.zcu.declPtr(decl_index);1079 try dw.updateLineNumber(pt.zcu, ti_id);
1084 log.debug("updateDeclLineNumber {}{*}", .{ decl.fqn.fmt(&pt.zcu.intern_pool), decl });
1085 try dw.updateDeclLineNumber(pt.zcu, decl_index);
1086 }1080 }
1087}1081}
10881082