authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-05-28 00:31:16+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-06-12 13:55:39+01:00
log424e6ac54b0f8bbfb43f24e28c71ac72169f3719
treef979f0e580e4ebff81eac779da8cb4889d57f1b1
parent4a02e080d127cc577d40f8ea5d68122ba8ac4243
signaturelock-open Commit is signed but in an unrecognized format.

compiler: minor refactors to ZCU linking

* The `codegen_nav`, `codegen_func`, `codegen_type` tasks are renamed to `link_nav`, `link_func`, and `link_type`, to more accurately reflect their purpose of sending data to the *linker*. Currently, `link_func` remains responsible for codegen; this will change in an upcoming commit. * Don't go on a pointless detour through `PerThread` when linking ZCU functions/`Nav`s; so, the `linkerUpdateNav` etc logic now lives in `link.zig`. Currently, `linkerUpdateFunc` is an exception, because it has broader responsibilities including codegen, but this will be solved in an upcoming commit.

5 files changed, 109 insertions(+), 129 deletions(-)

src/Compilation.zig+15-14
...@@ -848,17 +848,18 @@ pub const RcIncludes = enum {...@@ -848,17 +848,18 @@ pub const RcIncludes = enum {
848const Job = union(enum) {848const Job = union(enum) {
849 /// Corresponds to the task in `link.Task`.849 /// Corresponds to the task in `link.Task`.
850 /// Only needed for backends that haven't yet been updated to not race against Sema.850 /// Only needed for backends that haven't yet been updated to not race against Sema.
851 codegen_nav: InternPool.Nav.Index,851 link_nav: InternPool.Nav.Index,
852 /// Corresponds to the task in `link.Task`.852 /// Corresponds to the task in `link.Task`.
853 /// TODO: this is currently also responsible for performing codegen.
853 /// Only needed for backends that haven't yet been updated to not race against Sema.854 /// Only needed for backends that haven't yet been updated to not race against Sema.
854 codegen_func: link.Task.CodegenFunc,855 link_func: link.Task.CodegenFunc,
855 /// Corresponds to the task in `link.Task`.856 /// Corresponds to the task in `link.Task`.
856 /// Only needed for backends that haven't yet been updated to not race against Sema.857 /// Only needed for backends that haven't yet been updated to not race against Sema.
857 codegen_type: InternPool.Index,858 link_type: InternPool.Index,
858 update_line_number: InternPool.TrackedInst.Index,859 update_line_number: InternPool.TrackedInst.Index,
859 /// The `AnalUnit`, which is *not* a `func`, must be semantically analyzed.860 /// The `AnalUnit`, which is *not* a `func`, must be semantically analyzed.
860 /// This may be its first time being analyzed, or it may be outdated.861 /// This may be its first time being analyzed, or it may be outdated.
861 /// If the unit is a function, a `codegen_func` job will then be queued.862 /// If the unit is a test function, an `analyze_func` job will then be queued.
862 analyze_comptime_unit: InternPool.AnalUnit,863 analyze_comptime_unit: InternPool.AnalUnit,
863 /// This function must be semantically analyzed.864 /// This function must be semantically analyzed.
864 /// This may be its first time being analyzed, or it may be outdated.865 /// This may be its first time being analyzed, or it may be outdated.
...@@ -879,13 +880,13 @@ const Job = union(enum) {...@@ -879,13 +880,13 @@ const Job = union(enum) {
879 return switch (tag) {880 return switch (tag) {
880 // Prioritize functions so that codegen can get to work on them on a881 // Prioritize functions so that codegen can get to work on them on a
881 // separate thread, while Sema goes back to its own work.882 // separate thread, while Sema goes back to its own work.
882 .resolve_type_fully, .analyze_func, .codegen_func => 0,883 .resolve_type_fully, .analyze_func, .link_func => 0,
883 else => 1,884 else => 1,
884 };885 };
885 }886 }
886 comptime {887 comptime {
887 // Job dependencies888 // Job dependencies
888 assert(stage(.resolve_type_fully) <= stage(.codegen_func));889 assert(stage(.resolve_type_fully) <= stage(.link_func));
889 }890 }
890};891};
891892
...@@ -4552,7 +4553,7 @@ pub fn queueJobs(comp: *Compilation, jobs: []const Job) !void {...@@ -4552,7 +4553,7 @@ pub fn queueJobs(comp: *Compilation, jobs: []const Job) !void {
45524553
4553fn processOneJob(tid: usize, comp: *Compilation, job: Job) JobError!void {4554fn processOneJob(tid: usize, comp: *Compilation, job: Job) JobError!void {
4554 switch (job) {4555 switch (job) {
4555 .codegen_nav => |nav_index| {4556 .link_nav => |nav_index| {
4556 const zcu = comp.zcu.?;4557 const zcu = comp.zcu.?;
4557 const nav = zcu.intern_pool.getNav(nav_index);4558 const nav = zcu.intern_pool.getNav(nav_index);
4558 if (nav.analysis != null) {4559 if (nav.analysis != null) {
...@@ -4562,16 +4563,16 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job) JobError!void {...@@ -4562,16 +4563,16 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job) JobError!void {
4562 }4563 }
4563 }4564 }
4564 assert(nav.status == .fully_resolved);4565 assert(nav.status == .fully_resolved);
4565 comp.dispatchCodegenTask(tid, .{ .codegen_nav = nav_index });4566 comp.dispatchLinkTask(tid, .{ .link_nav = nav_index });
4566 },4567 },
4567 .codegen_func => |func| {4568 .link_func => |func| {
4568 comp.dispatchCodegenTask(tid, .{ .codegen_func = func });4569 comp.dispatchLinkTask(tid, .{ .link_func = func });
4569 },4570 },
4570 .codegen_type => |ty| {4571 .link_type => |ty| {
4571 comp.dispatchCodegenTask(tid, .{ .codegen_type = ty });4572 comp.dispatchLinkTask(tid, .{ .link_type = ty });
4572 },4573 },
4573 .update_line_number => |ti| {4574 .update_line_number => |ti| {
4574 comp.dispatchCodegenTask(tid, .{ .update_line_number = ti });4575 comp.dispatchLinkTask(tid, .{ .update_line_number = ti });
4575 },4576 },
4576 .analyze_func => |func| {4577 .analyze_func => |func| {
4577 const named_frame = tracy.namedFrame("analyze_func");4578 const named_frame = tracy.namedFrame("analyze_func");
...@@ -4665,7 +4666,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job) JobError!void {...@@ -4665,7 +4666,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job) JobError!void {
46654666
4666/// The reason for the double-queue here is that the first queue ensures any4667/// The reason for the double-queue here is that the first queue ensures any
4667/// resolve_type_fully tasks are complete before this dispatch function is called.4668/// resolve_type_fully tasks are complete before this dispatch function is called.
4668fn dispatchCodegenTask(comp: *Compilation, tid: usize, link_task: link.Task) void {4669fn dispatchLinkTask(comp: *Compilation, tid: usize, link_task: link.Task) void {
4669 if (comp.separateCodegenThreadOk()) {4670 if (comp.separateCodegenThreadOk()) {
4670 comp.queueLinkTasks(&.{link_task});4671 comp.queueLinkTasks(&.{link_task});
4671 } else {4672 } else {
src/Sema.zig+8-8
...@@ -2991,7 +2991,7 @@ fn zirStructDecl(...@@ -2991,7 +2991,7 @@ fn zirStructDecl(
2991 if (zcu.comp.config.use_llvm) break :codegen_type;2991 if (zcu.comp.config.use_llvm) break :codegen_type;
2992 if (block.ownerModule().strip) break :codegen_type;2992 if (block.ownerModule().strip) break :codegen_type;
2993 // This job depends on any resolve_type_fully jobs queued up before it.2993 // This job depends on any resolve_type_fully jobs queued up before it.
2994 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });2994 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
2995 }2995 }
2996 try sema.declareDependency(.{ .interned = wip_ty.index });2996 try sema.declareDependency(.{ .interned = wip_ty.index });
2997 try sema.addTypeReferenceEntry(src, wip_ty.index);2997 try sema.addTypeReferenceEntry(src, wip_ty.index);
...@@ -3250,7 +3250,7 @@ fn zirEnumDecl(...@@ -3250,7 +3250,7 @@ fn zirEnumDecl(
3250 if (zcu.comp.config.use_llvm) break :codegen_type;3250 if (zcu.comp.config.use_llvm) break :codegen_type;
3251 if (block.ownerModule().strip) break :codegen_type;3251 if (block.ownerModule().strip) break :codegen_type;
3252 // This job depends on any resolve_type_fully jobs queued up before it.3252 // This job depends on any resolve_type_fully jobs queued up before it.
3253 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });3253 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
3254 }3254 }
3255 return Air.internedToRef(wip_ty.index);3255 return Air.internedToRef(wip_ty.index);
3256}3256}
...@@ -3368,7 +3368,7 @@ fn zirUnionDecl(...@@ -3368,7 +3368,7 @@ fn zirUnionDecl(
3368 if (zcu.comp.config.use_llvm) break :codegen_type;3368 if (zcu.comp.config.use_llvm) break :codegen_type;
3369 if (block.ownerModule().strip) break :codegen_type;3369 if (block.ownerModule().strip) break :codegen_type;
3370 // This job depends on any resolve_type_fully jobs queued up before it.3370 // This job depends on any resolve_type_fully jobs queued up before it.
3371 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });3371 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
3372 }3372 }
3373 try sema.declareDependency(.{ .interned = wip_ty.index });3373 try sema.declareDependency(.{ .interned = wip_ty.index });
3374 try sema.addTypeReferenceEntry(src, wip_ty.index);3374 try sema.addTypeReferenceEntry(src, wip_ty.index);
...@@ -3455,7 +3455,7 @@ fn zirOpaqueDecl(...@@ -3455,7 +3455,7 @@ fn zirOpaqueDecl(
3455 if (zcu.comp.config.use_llvm) break :codegen_type;3455 if (zcu.comp.config.use_llvm) break :codegen_type;
3456 if (block.ownerModule().strip) break :codegen_type;3456 if (block.ownerModule().strip) break :codegen_type;
3457 // This job depends on any resolve_type_fully jobs queued up before it.3457 // This job depends on any resolve_type_fully jobs queued up before it.
3458 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });3458 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
3459 }3459 }
3460 try sema.addTypeReferenceEntry(src, wip_ty.index);3460 try sema.addTypeReferenceEntry(src, wip_ty.index);
3461 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);3461 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
...@@ -20086,7 +20086,7 @@ fn structInitAnon(...@@ -20086,7 +20086,7 @@ fn structInitAnon(
20086 codegen_type: {20086 codegen_type: {
20087 if (zcu.comp.config.use_llvm) break :codegen_type;20087 if (zcu.comp.config.use_llvm) break :codegen_type;
20088 if (block.ownerModule().strip) break :codegen_type;20088 if (block.ownerModule().strip) break :codegen_type;
20089 try zcu.comp.queueJob(.{ .codegen_type = wip.index });20089 try zcu.comp.queueJob(.{ .link_type = wip.index });
20090 }20090 }
20091 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);20091 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
20092 break :ty wip.finish(ip, new_namespace_index);20092 break :ty wip.finish(ip, new_namespace_index);
...@@ -21396,7 +21396,7 @@ fn reifyEnum(...@@ -21396,7 +21396,7 @@ fn reifyEnum(
21396 if (zcu.comp.config.use_llvm) break :codegen_type;21396 if (zcu.comp.config.use_llvm) break :codegen_type;
21397 if (block.ownerModule().strip) break :codegen_type;21397 if (block.ownerModule().strip) break :codegen_type;
21398 // This job depends on any resolve_type_fully jobs queued up before it.21398 // This job depends on any resolve_type_fully jobs queued up before it.
21399 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });21399 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
21400 }21400 }
21401 return Air.internedToRef(wip_ty.index);21401 return Air.internedToRef(wip_ty.index);
21402}21402}
...@@ -21650,7 +21650,7 @@ fn reifyUnion(...@@ -21650,7 +21650,7 @@ fn reifyUnion(
21650 if (zcu.comp.config.use_llvm) break :codegen_type;21650 if (zcu.comp.config.use_llvm) break :codegen_type;
21651 if (block.ownerModule().strip) break :codegen_type;21651 if (block.ownerModule().strip) break :codegen_type;
21652 // This job depends on any resolve_type_fully jobs queued up before it.21652 // This job depends on any resolve_type_fully jobs queued up before it.
21653 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });21653 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
21654 }21654 }
21655 try sema.declareDependency(.{ .interned = wip_ty.index });21655 try sema.declareDependency(.{ .interned = wip_ty.index });
21656 try sema.addTypeReferenceEntry(src, wip_ty.index);21656 try sema.addTypeReferenceEntry(src, wip_ty.index);
...@@ -22004,7 +22004,7 @@ fn reifyStruct(...@@ -22004,7 +22004,7 @@ fn reifyStruct(
22004 if (zcu.comp.config.use_llvm) break :codegen_type;22004 if (zcu.comp.config.use_llvm) break :codegen_type;
22005 if (block.ownerModule().strip) break :codegen_type;22005 if (block.ownerModule().strip) break :codegen_type;
22006 // This job depends on any resolve_type_fully jobs queued up before it.22006 // This job depends on any resolve_type_fully jobs queued up before it.
22007 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });22007 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
22008 }22008 }
22009 try sema.declareDependency(.{ .interned = wip_ty.index });22009 try sema.declareDependency(.{ .interned = wip_ty.index });
22010 try sema.addTypeReferenceEntry(src, wip_ty.index);22010 try sema.addTypeReferenceEntry(src, wip_ty.index);
src/Sema/LowerZon.zig+1-1
...@@ -194,7 +194,7 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter...@@ -194,7 +194,7 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter
194 codegen_type: {194 codegen_type: {
195 if (pt.zcu.comp.config.use_llvm) break :codegen_type;195 if (pt.zcu.comp.config.use_llvm) break :codegen_type;
196 if (self.block.ownerModule().strip) break :codegen_type;196 if (self.block.ownerModule().strip) break :codegen_type;
197 try pt.zcu.comp.queueJob(.{ .codegen_type = wip.index });197 try pt.zcu.comp.queueJob(.{ .link_type = wip.index });
198 }198 }
199 break :ty wip.finish(ip, new_namespace_index);199 break :ty wip.finish(ip, new_namespace_index);
200 },200 },
src/Zcu/PerThread.zig+8-73
...@@ -1320,7 +1320,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1320,7 +1320,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1320 }1320 }
13211321
1322 // This job depends on any resolve_type_fully jobs queued up before it.1322 // This job depends on any resolve_type_fully jobs queued up before it.
1323 try zcu.comp.queueJob(.{ .codegen_nav = nav_id });1323 try zcu.comp.queueJob(.{ .link_nav = nav_id });
1324 }1324 }
13251325
1326 switch (old_nav.status) {1326 switch (old_nav.status) {
...@@ -1716,7 +1716,7 @@ fn analyzeFuncBody(...@@ -1716,7 +1716,7 @@ fn analyzeFuncBody(
1716 }1716 }
17171717
1718 // This job depends on any resolve_type_fully jobs queued up before it.1718 // This job depends on any resolve_type_fully jobs queued up before it.
1719 try comp.queueJob(.{ .codegen_func = .{1719 try comp.queueJob(.{ .link_func = .{
1720 .func = func_index,1720 .func = func_index,
1721 .air = air,1721 .air = air,
1722 } });1722 } });
...@@ -1880,7 +1880,7 @@ fn createFileRootStruct(...@@ -1880,7 +1880,7 @@ fn createFileRootStruct(
1880 if (zcu.comp.config.use_llvm) break :codegen_type;1880 if (zcu.comp.config.use_llvm) break :codegen_type;
1881 if (file.mod.?.strip) break :codegen_type;1881 if (file.mod.?.strip) break :codegen_type;
1882 // This job depends on any resolve_type_fully jobs queued up before it.1882 // This job depends on any resolve_type_fully jobs queued up before it.
1883 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });1883 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
1884 }1884 }
1885 zcu.setFileRootType(file_index, wip_ty.index);1885 zcu.setFileRootType(file_index, wip_ty.index);
1886 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);1886 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
...@@ -3457,73 +3457,8 @@ pub fn populateTestFunctions(...@@ -3457,73 +3457,8 @@ pub fn populateTestFunctions(
3457 zcu.codegen_prog_node = std.Progress.Node.none;3457 zcu.codegen_prog_node = std.Progress.Node.none;
3458 }3458 }
34593459
3460 try pt.linkerUpdateNav(nav_index);3460 // The linker thread is not running, so we actually need to dispatch this task directly.
3461 }3461 @import("../link.zig").doTask(zcu.comp, @intFromEnum(pt.tid), .{ .link_nav = nav_index });
3462}
3463
3464pub fn linkerUpdateNav(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) error{OutOfMemory}!void {
3465 const zcu = pt.zcu;
3466 const comp = zcu.comp;
3467 const gpa = zcu.gpa;
3468 const ip = &zcu.intern_pool;
3469
3470 const nav = zcu.intern_pool.getNav(nav_index);
3471 const codegen_prog_node = zcu.codegen_prog_node.start(nav.fqn.toSlice(ip), 0);
3472 defer codegen_prog_node.end();
3473
3474 if (!Air.valFullyResolved(zcu.navValue(nav_index), zcu)) {
3475 // The value of this nav failed to resolve. This is a transitive failure.
3476 // TODO: do we need to mark this failure anywhere? I don't think so, since compilation
3477 // will fail due to the type error anyway.
3478 } else if (comp.bin_file) |lf| {
3479 lf.updateNav(pt, nav_index) catch |err| switch (err) {
3480 error.OutOfMemory => return error.OutOfMemory,
3481 error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)),
3482 error.Overflow, error.RelocationNotByteAligned => {
3483 try zcu.failed_codegen.putNoClobber(gpa, nav_index, try Zcu.ErrorMsg.create(
3484 gpa,
3485 zcu.navSrcLoc(nav_index),
3486 "unable to codegen: {s}",
3487 .{@errorName(err)},
3488 ));
3489 // Not a retryable failure.
3490 },
3491 };
3492 } else if (zcu.llvm_object) |llvm_object| {
3493 llvm_object.updateNav(pt, nav_index) catch |err| switch (err) {
3494 error.OutOfMemory => return error.OutOfMemory,
3495 };
3496 }
3497}
3498
3499pub fn linkerUpdateContainerType(pt: Zcu.PerThread, ty: InternPool.Index) error{OutOfMemory}!void {
3500 const zcu = pt.zcu;
3501 const gpa = zcu.gpa;
3502 const comp = zcu.comp;
3503 const ip = &zcu.intern_pool;
3504
3505 const codegen_prog_node = zcu.codegen_prog_node.start(Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), 0);
3506 defer codegen_prog_node.end();
3507
3508 if (zcu.failed_types.fetchSwapRemove(ty)) |*entry| entry.value.deinit(gpa);
3509
3510 if (!Air.typeFullyResolved(Type.fromInterned(ty), zcu)) {
3511 // This type failed to resolve. This is a transitive failure.
3512 return;
3513 }
3514
3515 if (comp.bin_file) |lf| lf.updateContainerType(pt, ty) catch |err| switch (err) {
3516 error.OutOfMemory => return error.OutOfMemory,
3517 error.TypeFailureReported => assert(zcu.failed_types.contains(ty)),
3518 };
3519}
3520
3521pub fn linkerUpdateLineNumber(pt: Zcu.PerThread, ti: InternPool.TrackedInst.Index) !void {
3522 if (pt.zcu.comp.bin_file) |lf| {
3523 lf.updateLineNumber(pt, ti) catch |err| switch (err) {
3524 error.OutOfMemory => return error.OutOfMemory,
3525 else => |e| log.err("update line number failed: {s}", .{@errorName(e)}),
3526 };
3527 }3462 }
3528}3463}
35293464
...@@ -3984,7 +3919,7 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error!...@@ -3984,7 +3919,7 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error!
3984 const result = try pt.zcu.intern_pool.getExtern(pt.zcu.gpa, pt.tid, key);3919 const result = try pt.zcu.intern_pool.getExtern(pt.zcu.gpa, pt.tid, key);
3985 if (result.new_nav.unwrap()) |nav| {3920 if (result.new_nav.unwrap()) |nav| {
3986 // This job depends on any resolve_type_fully jobs queued up before it.3921 // This job depends on any resolve_type_fully jobs queued up before it.
3987 try pt.zcu.comp.queueJob(.{ .codegen_nav = nav });3922 try pt.zcu.comp.queueJob(.{ .link_nav = nav });
3988 if (pt.zcu.comp.debugIncremental()) try pt.zcu.incremental_debug_state.newNav(pt.zcu, nav);3923 if (pt.zcu.comp.debugIncremental()) try pt.zcu.incremental_debug_state.newNav(pt.zcu, nav);
3989 }3924 }
3990 return result.index;3925 return result.index;
...@@ -4132,7 +4067,7 @@ fn recreateStructType(...@@ -4132,7 +4067,7 @@ fn recreateStructType(
4132 if (zcu.comp.config.use_llvm) break :codegen_type;4067 if (zcu.comp.config.use_llvm) break :codegen_type;
4133 if (file.mod.?.strip) break :codegen_type;4068 if (file.mod.?.strip) break :codegen_type;
4134 // This job depends on any resolve_type_fully jobs queued up before it.4069 // This job depends on any resolve_type_fully jobs queued up before it.
4135 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });4070 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
4136 }4071 }
41374072
4138 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);4073 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
...@@ -4225,7 +4160,7 @@ fn recreateUnionType(...@@ -4225,7 +4160,7 @@ fn recreateUnionType(
4225 if (zcu.comp.config.use_llvm) break :codegen_type;4160 if (zcu.comp.config.use_llvm) break :codegen_type;
4226 if (file.mod.?.strip) break :codegen_type;4161 if (file.mod.?.strip) break :codegen_type;
4227 // This job depends on any resolve_type_fully jobs queued up before it.4162 // This job depends on any resolve_type_fully jobs queued up before it.
4228 try zcu.comp.queueJob(.{ .codegen_type = wip_ty.index });4163 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
4229 }4164 }
42304165
4231 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);4166 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
src/link.zig+77-33
...@@ -704,7 +704,7 @@ pub const File = struct {...@@ -704,7 +704,7 @@ pub const File = struct {
704 }704 }
705705
706 /// May be called before or after updateExports for any given Nav.706 /// May be called before or after updateExports for any given Nav.
707 pub fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateNavError!void {707 fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateNavError!void {
708 const nav = pt.zcu.intern_pool.getNav(nav_index);708 const nav = pt.zcu.intern_pool.getNav(nav_index);
709 assert(nav.status == .fully_resolved);709 assert(nav.status == .fully_resolved);
710 switch (base.tag) {710 switch (base.tag) {
...@@ -721,7 +721,7 @@ pub const File = struct {...@@ -721,7 +721,7 @@ pub const File = struct {
721 TypeFailureReported,721 TypeFailureReported,
722 };722 };
723723
724 pub fn updateContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index) UpdateContainerTypeError!void {724 fn updateContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index) UpdateContainerTypeError!void {
725 switch (base.tag) {725 switch (base.tag) {
726 else => {},726 else => {},
727 inline .elf => |tag| {727 inline .elf => |tag| {
...@@ -732,6 +732,7 @@ pub const File = struct {...@@ -732,6 +732,7 @@ pub const File = struct {
732 }732 }
733733
734 /// May be called before or after updateExports for any given Decl.734 /// May be called before or after updateExports for any given Decl.
735 /// TODO: currently `pub` because `Zcu.PerThread` is calling this.
735 pub fn updateFunc(736 pub fn updateFunc(
736 base: *File,737 base: *File,
737 pt: Zcu.PerThread,738 pt: Zcu.PerThread,
...@@ -755,7 +756,7 @@ pub const File = struct {...@@ -755,7 +756,7 @@ pub const File = struct {
755756
756 /// On an incremental update, fixup the line number of all `Nav`s at the given `TrackedInst`, because757 /// On an incremental update, fixup the line number of all `Nav`s at the given `TrackedInst`, because
757 /// its line number has changed. The ZIR instruction `ti_id` has tag `.declaration`.758 /// its line number has changed. The ZIR instruction `ti_id` has tag `.declaration`.
758 pub fn updateLineNumber(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) UpdateLineNumberError!void {759 fn updateLineNumber(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) UpdateLineNumberError!void {
759 {760 {
760 const ti = ti_id.resolveFull(&pt.zcu.intern_pool).?;761 const ti = ti_id.resolveFull(&pt.zcu.intern_pool).?;
761 const file = pt.zcu.fileByIndex(ti.file);762 const file = pt.zcu.fileByIndex(ti.file);
...@@ -1435,10 +1436,10 @@ pub const Task = union(enum) {...@@ -1435,10 +1436,10 @@ pub const Task = union(enum) {
1435 load_input: Input,1436 load_input: Input,
14361437
1437 /// Write the constant value for a Decl to the output file.1438 /// Write the constant value for a Decl to the output file.
1438 codegen_nav: InternPool.Nav.Index,1439 link_nav: InternPool.Nav.Index,
1439 /// Write the machine code for a function to the output file.1440 /// Write the machine code for a function to the output file.
1440 codegen_func: CodegenFunc,1441 link_func: CodegenFunc,
1441 codegen_type: InternPool.Index,1442 link_type: InternPool.Index,
14421443
1443 update_line_number: InternPool.TrackedInst.Index,1444 update_line_number: InternPool.TrackedInst.Index,
14441445
...@@ -1585,47 +1586,90 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {...@@ -1585,47 +1586,90 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {
1585 },1586 },
1586 };1587 };
1587 },1588 },
1588 .codegen_nav => |nav_index| {1589 .link_nav => |nav_index| {
1589 if (comp.remaining_prelink_tasks == 0) {1590 if (comp.remaining_prelink_tasks != 0) {
1590 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
1591 defer pt.deactivate();
1592 pt.linkerUpdateNav(nav_index) catch |err| switch (err) {
1593 error.OutOfMemory => diags.setAllocFailure(),
1594 };
1595 } else {
1596 comp.link_task_queue_postponed.appendAssumeCapacity(task);1591 comp.link_task_queue_postponed.appendAssumeCapacity(task);
1592 return;
1597 }1593 }
1598 },1594 const zcu = comp.zcu.?;
1599 .codegen_func => |func| {1595 const pt: Zcu.PerThread = .activate(zcu, @enumFromInt(tid));
1600 if (comp.remaining_prelink_tasks == 0) {1596 defer pt.deactivate();
1601 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));1597 if (!Air.valFullyResolved(zcu.navValue(nav_index), zcu)) {
1602 defer pt.deactivate();1598 // Type resolution failed in a way which affects this `Nav`. This is a transitive
1603 var air = func.air;1599 // failure, but it doesn't need recording, because this `Nav` semantically depends
1604 defer air.deinit(comp.gpa);1600 // on the failed type, so when it is changed the `Nav` will be updated.
1605 pt.linkerUpdateFunc(func.func, &air) catch |err| switch (err) {1601 return;
1602 }
1603 if (comp.bin_file) |lf| {
1604 lf.updateNav(pt, nav_index) catch |err| switch (err) {
1605 error.OutOfMemory => diags.setAllocFailure(),
1606 error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)),
1607 error.Overflow, error.RelocationNotByteAligned => {
1608 zcu.failed_codegen.ensureUnusedCapacity(zcu.gpa, 1) catch return diags.setAllocFailure();
1609 const msg = Zcu.ErrorMsg.create(
1610 zcu.gpa,
1611 zcu.navSrcLoc(nav_index),
1612 "unable to codegen: {s}",
1613 .{@errorName(err)},
1614 ) catch return diags.setAllocFailure();
1615 zcu.failed_codegen.putAssumeCapacityNoClobber(nav_index, msg);
1616 // Not a retryable failure.
1617 },
1618 };
1619 } else if (zcu.llvm_object) |llvm_object| {
1620 llvm_object.updateNav(pt, nav_index) catch |err| switch (err) {
1606 error.OutOfMemory => diags.setAllocFailure(),1621 error.OutOfMemory => diags.setAllocFailure(),
1607 };1622 };
1608 } else {1623 }
1624 },
1625 .link_func => |func| {
1626 if (comp.remaining_prelink_tasks != 0) {
1609 comp.link_task_queue_postponed.appendAssumeCapacity(task);1627 comp.link_task_queue_postponed.appendAssumeCapacity(task);
1628 return;
1610 }1629 }
1630 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
1631 defer pt.deactivate();
1632 var air = func.air;
1633 defer air.deinit(comp.gpa);
1634 pt.linkerUpdateFunc(func.func, &air) catch |err| switch (err) {
1635 error.OutOfMemory => diags.setAllocFailure(),
1636 };
1611 },1637 },
1612 .codegen_type => |ty| {1638 .link_type => |ty| {
1613 if (comp.remaining_prelink_tasks == 0) {1639 if (comp.remaining_prelink_tasks != 0) {
1614 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));1640 comp.link_task_queue_postponed.appendAssumeCapacity(task);
1615 defer pt.deactivate();1641 return;
1616 pt.linkerUpdateContainerType(ty) catch |err| switch (err) {1642 }
1643 const zcu = comp.zcu.?;
1644 const pt: Zcu.PerThread = .activate(zcu, @enumFromInt(tid));
1645 defer pt.deactivate();
1646 if (zcu.failed_types.fetchSwapRemove(ty)) |*entry| entry.value.deinit(zcu.gpa);
1647 if (!Air.typeFullyResolved(.fromInterned(ty), zcu)) {
1648 // Type resolution failed in a way which affects this type. This is a transitive
1649 // failure, but it doesn't need recording, because this type semantically depends
1650 // on the failed type, so when that is changed, this type will be updated.
1651 return;
1652 }
1653 if (comp.bin_file) |lf| {
1654 lf.updateContainerType(pt, ty) catch |err| switch (err) {
1617 error.OutOfMemory => diags.setAllocFailure(),1655 error.OutOfMemory => diags.setAllocFailure(),
1656 error.TypeFailureReported => assert(zcu.failed_types.contains(ty)),
1618 };1657 };
1619 } else {
1620 comp.link_task_queue_postponed.appendAssumeCapacity(task);
1621 }1658 }
1622 },1659 },
1623 .update_line_number => |ti| {1660 .update_line_number => |ti| {
1661 if (comp.remaining_prelink_tasks != 0) {
1662 comp.link_task_queue_postponed.appendAssumeCapacity(task);
1663 return;
1664 }
1624 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));1665 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
1625 defer pt.deactivate();1666 defer pt.deactivate();
1626 pt.linkerUpdateLineNumber(ti) catch |err| switch (err) {1667 if (comp.bin_file) |lf| {
1627 error.OutOfMemory => diags.setAllocFailure(),1668 lf.updateLineNumber(pt, ti) catch |err| switch (err) {
1628 };1669 error.OutOfMemory => diags.setAllocFailure(),
1670 else => |e| log.err("update line number failed: {s}", .{@errorName(e)}),
1671 };
1672 }
1629 },1673 },
1630 }1674 }
1631}1675}