aboutsummaryrefslogtreecommitdiff
path: root/src/link.zig
diff options
context:
space:
mode:
authormlugg <mlugg@mlugg.co.uk>2025-05-28 00:31:16 +0100
committermlugg <mlugg@mlugg.co.uk>2025-06-12 13:55:39 +0100
commit424e6ac54b0f8bbfb43f24e28c71ac72169f3719 (patch)
treef979f0e580e4ebff81eac779da8cb4889d57f1b1 /src/link.zig
parent4a02e080d127cc577d40f8ea5d68122ba8ac4243 (diff)
downloadzig-424e6ac54b0f8bbfb43f24e28c71ac72169f3719.tar.gz
zig-424e6ac54b0f8bbfb43f24e28c71ac72169f3719.zip
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.
Diffstat (limited to 'src/link.zig')
-rw-r--r--src/link.zig110
1 files changed, 77 insertions, 33 deletions
diff --git a/src/link.zig b/src/link.zig
index 688210c355..7673b44e47 100644
--- a/src/link.zig
+++ b/src/link.zig
@@ -704,7 +704,7 @@ pub const File = struct {
}
/// May be called before or after updateExports for any given Nav.
- pub fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateNavError!void {
+ fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateNavError!void {
const nav = pt.zcu.intern_pool.getNav(nav_index);
assert(nav.status == .fully_resolved);
switch (base.tag) {
@@ -721,7 +721,7 @@ pub const File = struct {
TypeFailureReported,
};
- pub fn updateContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index) UpdateContainerTypeError!void {
+ fn updateContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index) UpdateContainerTypeError!void {
switch (base.tag) {
else => {},
inline .elf => |tag| {
@@ -732,6 +732,7 @@ pub const File = struct {
}
/// May be called before or after updateExports for any given Decl.
+ /// TODO: currently `pub` because `Zcu.PerThread` is calling this.
pub fn updateFunc(
base: *File,
pt: Zcu.PerThread,
@@ -755,7 +756,7 @@ pub const File = struct {
/// On an incremental update, fixup the line number of all `Nav`s at the given `TrackedInst`, because
/// its line number has changed. The ZIR instruction `ti_id` has tag `.declaration`.
- pub fn updateLineNumber(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) UpdateLineNumberError!void {
+ fn updateLineNumber(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) UpdateLineNumberError!void {
{
const ti = ti_id.resolveFull(&pt.zcu.intern_pool).?;
const file = pt.zcu.fileByIndex(ti.file);
@@ -1435,10 +1436,10 @@ pub const Task = union(enum) {
load_input: Input,
/// Write the constant value for a Decl to the output file.
- codegen_nav: InternPool.Nav.Index,
+ link_nav: InternPool.Nav.Index,
/// Write the machine code for a function to the output file.
- codegen_func: CodegenFunc,
- codegen_type: InternPool.Index,
+ link_func: CodegenFunc,
+ link_type: InternPool.Index,
update_line_number: InternPool.TrackedInst.Index,
@@ -1585,47 +1586,90 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {
},
};
},
- .codegen_nav => |nav_index| {
- if (comp.remaining_prelink_tasks == 0) {
- const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
- defer pt.deactivate();
- pt.linkerUpdateNav(nav_index) catch |err| switch (err) {
- error.OutOfMemory => diags.setAllocFailure(),
- };
- } else {
+ .link_nav => |nav_index| {
+ if (comp.remaining_prelink_tasks != 0) {
comp.link_task_queue_postponed.appendAssumeCapacity(task);
+ return;
}
- },
- .codegen_func => |func| {
- if (comp.remaining_prelink_tasks == 0) {
- const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
- defer pt.deactivate();
- var air = func.air;
- defer air.deinit(comp.gpa);
- pt.linkerUpdateFunc(func.func, &air) catch |err| switch (err) {
+ const zcu = comp.zcu.?;
+ const pt: Zcu.PerThread = .activate(zcu, @enumFromInt(tid));
+ defer pt.deactivate();
+ if (!Air.valFullyResolved(zcu.navValue(nav_index), zcu)) {
+ // Type resolution failed in a way which affects this `Nav`. This is a transitive
+ // failure, but it doesn't need recording, because this `Nav` semantically depends
+ // on the failed type, so when it is changed the `Nav` will be updated.
+ return;
+ }
+ if (comp.bin_file) |lf| {
+ lf.updateNav(pt, nav_index) catch |err| switch (err) {
+ error.OutOfMemory => diags.setAllocFailure(),
+ error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)),
+ error.Overflow, error.RelocationNotByteAligned => {
+ zcu.failed_codegen.ensureUnusedCapacity(zcu.gpa, 1) catch return diags.setAllocFailure();
+ const msg = Zcu.ErrorMsg.create(
+ zcu.gpa,
+ zcu.navSrcLoc(nav_index),
+ "unable to codegen: {s}",
+ .{@errorName(err)},
+ ) catch return diags.setAllocFailure();
+ zcu.failed_codegen.putAssumeCapacityNoClobber(nav_index, msg);
+ // Not a retryable failure.
+ },
+ };
+ } else if (zcu.llvm_object) |llvm_object| {
+ llvm_object.updateNav(pt, nav_index) catch |err| switch (err) {
error.OutOfMemory => diags.setAllocFailure(),
};
- } else {
+ }
+ },
+ .link_func => |func| {
+ if (comp.remaining_prelink_tasks != 0) {
comp.link_task_queue_postponed.appendAssumeCapacity(task);
+ return;
}
+ const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
+ defer pt.deactivate();
+ var air = func.air;
+ defer air.deinit(comp.gpa);
+ pt.linkerUpdateFunc(func.func, &air) catch |err| switch (err) {
+ error.OutOfMemory => diags.setAllocFailure(),
+ };
},
- .codegen_type => |ty| {
- if (comp.remaining_prelink_tasks == 0) {
- const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
- defer pt.deactivate();
- pt.linkerUpdateContainerType(ty) catch |err| switch (err) {
+ .link_type => |ty| {
+ if (comp.remaining_prelink_tasks != 0) {
+ comp.link_task_queue_postponed.appendAssumeCapacity(task);
+ return;
+ }
+ const zcu = comp.zcu.?;
+ const pt: Zcu.PerThread = .activate(zcu, @enumFromInt(tid));
+ defer pt.deactivate();
+ if (zcu.failed_types.fetchSwapRemove(ty)) |*entry| entry.value.deinit(zcu.gpa);
+ if (!Air.typeFullyResolved(.fromInterned(ty), zcu)) {
+ // Type resolution failed in a way which affects this type. This is a transitive
+ // failure, but it doesn't need recording, because this type semantically depends
+ // on the failed type, so when that is changed, this type will be updated.
+ return;
+ }
+ if (comp.bin_file) |lf| {
+ lf.updateContainerType(pt, ty) catch |err| switch (err) {
error.OutOfMemory => diags.setAllocFailure(),
+ error.TypeFailureReported => assert(zcu.failed_types.contains(ty)),
};
- } else {
- comp.link_task_queue_postponed.appendAssumeCapacity(task);
}
},
.update_line_number => |ti| {
+ if (comp.remaining_prelink_tasks != 0) {
+ comp.link_task_queue_postponed.appendAssumeCapacity(task);
+ return;
+ }
const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
defer pt.deactivate();
- pt.linkerUpdateLineNumber(ti) catch |err| switch (err) {
- error.OutOfMemory => diags.setAllocFailure(),
- };
+ if (comp.bin_file) |lf| {
+ lf.updateLineNumber(pt, ti) catch |err| switch (err) {
+ error.OutOfMemory => diags.setAllocFailure(),
+ else => |e| log.err("update line number failed: {s}", .{@errorName(e)}),
+ };
+ }
},
}
}