authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-05-28 06:36:47+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2025-06-12 13:55:39+01:00
log3743c3e39c6bb645db7403fd446953d43ac7c7dc
treee9223b737051f606b7eec326e71e5977f4164dfc
parent424e6ac54b0f8bbfb43f24e28c71ac72169f3719
signaturelock-open Commit is signed but in an unrecognized format.

compiler: slightly untangle LLVM from the linkers

The main goal of this commit is to make it easier to decouple codegen from the linkers by being able to do LLVM codegen without going through the `link.File`; however, this ended up being a nice refactor anyway. Previously, every linker stored an optional `llvm.Object`, which was populated when using LLVM for the ZCU *and* linking an output binary; and `Zcu` also stored an optional `llvm.Object`, which was used only when we needed LLVM for the ZCU (e.g. for `-femit-llvm-bc`) but were not emitting a binary. This situation was incredibly silly. It meant there were N+1 places the LLVM object might be instead of just 1, and it meant that every linker had to start a bunch of methods by checking for an LLVM object, and just dispatching to the corresponding method on *it* instead if it was not `null`. Instead, we now always store the LLVM object on the `Zcu` -- which makes sense, because it corresponds to the object emitted by, well, the Zig Compilation Unit! The linkers now mostly don't make reference to LLVM. `Compilation` makes sure to emit the LLVM object if necessary before calling `flush`, so it is ready for the linker. Also, all of the `link.File` methods which act on the ZCU -- like `updateNav` -- now check for the LLVM object in `link.zig` instead of in every single individual linker implementation. Notably, the change to LLVM emit improves this rather ludicrous call chain in the `-fllvm -flld` case: * Compilation.flush * link.File.flush * link.Elf.flush * link.Elf.linkWithLLD * link.Elf.flushModule * link.emitLlvmObject * Compilation.emitLlvmObject * llvm.Object.emit Replacing it with this one: * Compilation.flush * llvm.Object.emit ...although we do currently still end up in `link.Elf.linkWithLLD` to do the actual linking. The logic for invoking LLD should probably also be unified at least somewhat; I haven't done that in this commit.

20 files changed, 227 insertions(+), 337 deletions(-)

src/Compilation.zig+31-41
......@@ -2188,14 +2188,10 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil
21882188 },
21892189 }
21902190
2191 // Handle the case of e.g. -fno-emit-bin -femit-llvm-ir.
2192 if (options.emit_bin == null and (comp.verbose_llvm_ir != null or
2193 comp.verbose_llvm_bc != null or
2194 (use_llvm and comp.emit_asm != null) or
2195 comp.emit_llvm_ir != null or
2196 comp.emit_llvm_bc != null))
2197 {
2198 if (opt_zcu) |zcu| zcu.llvm_object = try LlvmObject.create(arena, comp);
2191 if (use_llvm) {
2192 if (opt_zcu) |zcu| {
2193 zcu.llvm_object = try LlvmObject.create(arena, comp);
2194 }
21992195 }
22002196
22012197 break :comp comp;
......@@ -2945,6 +2941,33 @@ fn flush(
29452941 tid: Zcu.PerThread.Id,
29462942 prog_node: std.Progress.Node,
29472943) !void {
2944 if (comp.zcu) |zcu| {
2945 if (zcu.llvm_object) |llvm_object| {
2946 // Emit the ZCU object from LLVM now; it's required to flush the output file.
2947 // If there's an output file, it wants to decide where the LLVM object goes!
2948 const zcu_obj_emit_loc: ?EmitLoc = if (comp.bin_file) |lf| .{
2949 .directory = null,
2950 .basename = lf.zcu_object_sub_path.?,
2951 } else null;
2952 const sub_prog_node = prog_node.start("LLVM Emit Object", 0);
2953 defer sub_prog_node.end();
2954 try llvm_object.emit(.{
2955 .pre_ir_path = comp.verbose_llvm_ir,
2956 .pre_bc_path = comp.verbose_llvm_bc,
2957 .bin_path = try resolveEmitLoc(arena, default_artifact_directory, zcu_obj_emit_loc),
2958 .asm_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_asm),
2959 .post_ir_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_llvm_ir),
2960 .post_bc_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_llvm_bc),
2961
2962 .is_debug = comp.root_mod.optimize_mode == .Debug,
2963 .is_small = comp.root_mod.optimize_mode == .ReleaseSmall,
2964 .time_report = comp.time_report,
2965 .sanitize_thread = comp.config.any_sanitize_thread,
2966 .fuzz = comp.config.any_fuzz,
2967 .lto = comp.config.lto,
2968 });
2969 }
2970 }
29482971 if (comp.bin_file) |lf| {
29492972 // This is needed before reading the error flags.
29502973 lf.flush(arena, tid, prog_node) catch |err| switch (err) {
......@@ -2952,13 +2975,8 @@ fn flush(
29522975 error.OutOfMemory => return error.OutOfMemory,
29532976 };
29542977 }
2955
29562978 if (comp.zcu) |zcu| {
29572979 try link.File.C.flushEmitH(zcu);
2958
2959 if (zcu.llvm_object) |llvm_object| {
2960 try emitLlvmObject(comp, arena, default_artifact_directory, null, llvm_object, prog_node);
2961 }
29622980 }
29632981}
29642982
......@@ -3233,34 +3251,6 @@ fn emitOthers(comp: *Compilation) void {
32333251 }
32343252}
32353253
3236pub fn emitLlvmObject(
3237 comp: *Compilation,
3238 arena: Allocator,
3239 default_artifact_directory: Cache.Path,
3240 bin_emit_loc: ?EmitLoc,
3241 llvm_object: LlvmObject.Ptr,
3242 prog_node: std.Progress.Node,
3243) !void {
3244 const sub_prog_node = prog_node.start("LLVM Emit Object", 0);
3245 defer sub_prog_node.end();
3246
3247 try llvm_object.emit(.{
3248 .pre_ir_path = comp.verbose_llvm_ir,
3249 .pre_bc_path = comp.verbose_llvm_bc,
3250 .bin_path = try resolveEmitLoc(arena, default_artifact_directory, bin_emit_loc),
3251 .asm_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_asm),
3252 .post_ir_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_llvm_ir),
3253 .post_bc_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_llvm_bc),
3254
3255 .is_debug = comp.root_mod.optimize_mode == .Debug,
3256 .is_small = comp.root_mod.optimize_mode == .ReleaseSmall,
3257 .time_report = comp.time_report,
3258 .sanitize_thread = comp.config.any_sanitize_thread,
3259 .fuzz = comp.config.any_fuzz,
3260 .lto = comp.config.lto,
3261 });
3262}
3263
32643254fn resolveEmitLoc(
32653255 arena: Allocator,
32663256 default_artifact_directory: Cache.Path,
src/Zcu.zig+2-13
......@@ -56,9 +56,8 @@ comptime {
5656/// General-purpose allocator. Used for both temporary and long-term storage.
5757gpa: Allocator,
5858comp: *Compilation,
59/// Usually, the LlvmObject is managed by linker code, however, in the case
60/// that -fno-emit-bin is specified, the linker code never executes, so we
61/// store the LlvmObject here.
59/// If the ZCU is emitting an LLVM object (i.e. we are using the LLVM backend), then this is the
60/// `LlvmObject` we are emitting to.
6261llvm_object: ?LlvmObject.Ptr,
6362
6463/// Pointer to externally managed resource.
......@@ -267,16 +266,6 @@ resolved_references: ?std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) = n
267266/// Reset to `false` at the start of each update in `Compilation.update`.
268267skip_analysis_this_update: bool = false,
269268
270stage1_flags: packed struct {
271 have_winmain: bool = false,
272 have_wwinmain: bool = false,
273 have_winmain_crt_startup: bool = false,
274 have_wwinmain_crt_startup: bool = false,
275 have_dllmain_crt_startup: bool = false,
276 have_c_main: bool = false,
277 reserved: u2 = 0,
278} = .{},
279
280269test_functions: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty,
281270
282271global_assembly: std.AutoArrayHashMapUnmanaged(AnalUnit, []u8) = .empty,
src/Zcu/PerThread.zig+9-12
......@@ -1784,8 +1784,12 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: *A
17841784 };
17851785 }
17861786
1787 if (comp.bin_file) |lf| {
1788 lf.updateFunc(pt, func_index, air.*, liveness) catch |err| switch (err) {
1787 if (zcu.llvm_object) |llvm_object| {
1788 llvm_object.updateFunc(pt, func_index, air.*, liveness) catch |err| switch (err) {
1789 error.OutOfMemory => return error.OutOfMemory,
1790 };
1791 } else if (comp.bin_file) |lf| {
1792 lf.updateFunc(pt, func_index, air, liveness) catch |err| switch (err) {
17891793 error.OutOfMemory => return error.OutOfMemory,
17901794 error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)),
17911795 error.Overflow, error.RelocationNotByteAligned => {
......@@ -1798,10 +1802,6 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: *A
17981802 // Not a retryable failure.
17991803 },
18001804 };
1801 } else if (zcu.llvm_object) |llvm_object| {
1802 llvm_object.updateFunc(pt, func_index, air.*, liveness) catch |err| switch (err) {
1803 error.OutOfMemory => return error.OutOfMemory,
1804 };
18051805 }
18061806}
18071807
......@@ -1877,7 +1877,6 @@ fn createFileRootStruct(
18771877 try pt.scanNamespace(namespace_index, decls);
18781878 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
18791879 codegen_type: {
1880 if (zcu.comp.config.use_llvm) break :codegen_type;
18811880 if (file.mod.?.strip) break :codegen_type;
18821881 // This job depends on any resolve_type_fully jobs queued up before it.
18831882 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
......@@ -3309,10 +3308,10 @@ fn processExportsInner(
33093308 .uav => {},
33103309 }
33113310
3312 if (zcu.comp.bin_file) |lf| {
3313 try zcu.handleUpdateExports(export_indices, lf.updateExports(pt, exported, export_indices));
3314 } else if (zcu.llvm_object) |llvm_object| {
3311 if (zcu.llvm_object) |llvm_object| {
33153312 try zcu.handleUpdateExports(export_indices, llvm_object.updateExports(pt, exported, export_indices));
3313 } else if (zcu.comp.bin_file) |lf| {
3314 try zcu.handleUpdateExports(export_indices, lf.updateExports(pt, exported, export_indices));
33163315 }
33173316}
33183317
......@@ -4064,7 +4063,6 @@ fn recreateStructType(
40644063 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
40654064
40664065 codegen_type: {
4067 if (zcu.comp.config.use_llvm) break :codegen_type;
40684066 if (file.mod.?.strip) break :codegen_type;
40694067 // This job depends on any resolve_type_fully jobs queued up before it.
40704068 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
......@@ -4157,7 +4155,6 @@ fn recreateUnionType(
41574155 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
41584156
41594157 codegen_type: {
4160 if (zcu.comp.config.use_llvm) break :codegen_type;
41614158 if (file.mod.?.strip) break :codegen_type;
41624159 // This job depends on any resolve_type_fully jobs queued up before it.
41634160 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
src/codegen/llvm.zig+18
......@@ -1586,6 +1586,24 @@ pub const Object = struct {
15861586 const global_index = self.nav_map.get(nav_index).?;
15871587 const comp = zcu.comp;
15881588
1589 // If we're on COFF and linking with LLD, the linker cares about our exports to determine the subsystem in use.
1590 if (comp.bin_file != null and
1591 comp.bin_file.?.tag == .coff and
1592 zcu.comp.config.use_lld and
1593 ip.isFunctionType(ip.getNav(nav_index).typeOf(ip)))
1594 {
1595 const flags = &comp.bin_file.?.cast(.coff).?.lld_export_flags;
1596 for (export_indices) |export_index| {
1597 const name = export_index.ptr(zcu).opts.name;
1598 if (name.eqlSlice("main", ip)) flags.c_main = true;
1599 if (name.eqlSlice("WinMain", ip)) flags.winmain = true;
1600 if (name.eqlSlice("wWinMain", ip)) flags.wwinmain = true;
1601 if (name.eqlSlice("WinMainCRTStartup", ip)) flags.winmain_crt_startup = true;
1602 if (name.eqlSlice("wWinMainCRTStartup", ip)) flags.wwinmain_crt_startup = true;
1603 if (name.eqlSlice("DllMainCRTStartup", ip)) flags.dllmain_crt_startup = true;
1604 }
1605 }
1606
15891607 if (export_indices.len != 0) {
15901608 return updateExportedGlobal(self, zcu, global_index, export_indices);
15911609 } else {
src/codegen/spirv/Section.zig-2
......@@ -386,8 +386,6 @@ test "SPIR-V Section emit() - string" {
386386}
387387
388388test "SPIR-V Section emit() - extended mask" {
389 if (@import("builtin").zig_backend == .stage1) return error.SkipZigTest;
390
391389 var section = Section{};
392390 defer section.deinit(std.testing.allocator);
393391
src/link.zig+48-37
......@@ -19,7 +19,6 @@ const Zcu = @import("Zcu.zig");
1919const InternPool = @import("InternPool.zig");
2020const Type = @import("Type.zig");
2121const Value = @import("Value.zig");
22const LlvmObject = @import("codegen/llvm.zig").Object;
2322const lldMain = @import("main.zig").lldMain;
2423const Package = @import("Package.zig");
2524const dev = @import("dev.zig");
......@@ -704,7 +703,9 @@ pub const File = struct {
704703 }
705704
706705 /// May be called before or after updateExports for any given Nav.
706 /// Asserts that the ZCU is not using the LLVM backend.
707707 fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateNavError!void {
708 assert(base.comp.zcu.?.llvm_object == null);
708709 const nav = pt.zcu.intern_pool.getNav(nav_index);
709710 assert(nav.status == .fully_resolved);
710711 switch (base.tag) {
......@@ -721,7 +722,9 @@ pub const File = struct {
721722 TypeFailureReported,
722723 };
723724
725 /// Never called when LLVM is codegenning the ZCU.
724726 fn updateContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index) UpdateContainerTypeError!void {
727 assert(base.comp.zcu.?.llvm_object == null);
725728 switch (base.tag) {
726729 else => {},
727730 inline .elf => |tag| {
......@@ -733,6 +736,7 @@ pub const File = struct {
733736
734737 /// May be called before or after updateExports for any given Decl.
735738 /// TODO: currently `pub` because `Zcu.PerThread` is calling this.
739 /// Never called when LLVM is codegenning the ZCU.
736740 pub fn updateFunc(
737741 base: *File,
738742 pt: Zcu.PerThread,
......@@ -740,6 +744,7 @@ pub const File = struct {
740744 air: Air,
741745 liveness: Air.Liveness,
742746 ) UpdateNavError!void {
747 assert(base.comp.zcu.?.llvm_object == null);
743748 switch (base.tag) {
744749 inline else => |tag| {
745750 dev.check(tag.devFeature());
......@@ -756,7 +761,9 @@ pub const File = struct {
756761
757762 /// On an incremental update, fixup the line number of all `Nav`s at the given `TrackedInst`, because
758763 /// its line number has changed. The ZIR instruction `ti_id` has tag `.declaration`.
764 /// Never called when LLVM is codegenning the ZCU.
759765 fn updateLineNumber(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) UpdateLineNumberError!void {
766 assert(base.comp.zcu.?.llvm_object == null);
760767 {
761768 const ti = ti_id.resolveFull(&pt.zcu.intern_pool).?;
762769 const file = pt.zcu.fileByIndex(ti.file);
......@@ -846,11 +853,13 @@ pub const File = struct {
846853
847854 /// Commit pending changes and write headers. Works based on `effectiveOutputMode`
848855 /// rather than final output mode.
849 pub fn flushModule(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void {
856 /// Never called when LLVM is codegenning the ZCU.
857 fn flushZcu(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void {
858 assert(base.comp.zcu.?.llvm_object == null);
850859 switch (base.tag) {
851860 inline else => |tag| {
852861 dev.check(tag.devFeature());
853 return @as(*tag.Type(), @fieldParentPtr("base", base)).flushModule(arena, tid, prog_node);
862 return @as(*tag.Type(), @fieldParentPtr("base", base)).flushZcu(arena, tid, prog_node);
854863 },
855864 }
856865 }
......@@ -864,12 +873,14 @@ pub const File = struct {
864873 /// a list of size 1, meaning that `exported` is exported once. However, it is possible
865874 /// to export the same thing with multiple different symbol names (aliases).
866875 /// May be called before or after updateDecl for any given Decl.
876 /// Never called when LLVM is codegenning the ZCU.
867877 pub fn updateExports(
868878 base: *File,
869879 pt: Zcu.PerThread,
870880 exported: Zcu.Exported,
871881 export_indices: []const Zcu.Export.Index,
872882 ) UpdateExportsError!void {
883 assert(base.comp.zcu.?.llvm_object == null);
873884 switch (base.tag) {
874885 inline else => |tag| {
875886 dev.check(tag.devFeature());
......@@ -896,7 +907,9 @@ pub const File = struct {
896907 /// `Nav`'s address was not yet resolved, or the containing atom gets moved in virtual memory.
897908 /// May be called before or after updateFunc/updateNav therefore it is up to the linker to allocate
898909 /// the block/atom.
910 /// Never called when LLVM is codegenning the ZCU.
899911 pub fn getNavVAddr(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, reloc_info: RelocInfo) !u64 {
912 assert(base.comp.zcu.?.llvm_object == null);
900913 switch (base.tag) {
901914 .c => unreachable,
902915 .spirv => unreachable,
......@@ -909,6 +922,7 @@ pub const File = struct {
909922 }
910923 }
911924
925 /// Never called when LLVM is codegenning the ZCU.
912926 pub fn lowerUav(
913927 base: *File,
914928 pt: Zcu.PerThread,
......@@ -916,6 +930,7 @@ pub const File = struct {
916930 decl_align: InternPool.Alignment,
917931 src_loc: Zcu.LazySrcLoc,
918932 ) !codegen.GenResult {
933 assert(base.comp.zcu.?.llvm_object == null);
919934 switch (base.tag) {
920935 .c => unreachable,
921936 .spirv => unreachable,
......@@ -928,7 +943,9 @@ pub const File = struct {
928943 }
929944 }
930945
946 /// Never called when LLVM is codegenning the ZCU.
931947 pub fn getUavVAddr(base: *File, decl_val: InternPool.Index, reloc_info: RelocInfo) !u64 {
948 assert(base.comp.zcu.?.llvm_object == null);
932949 switch (base.tag) {
933950 .c => unreachable,
934951 .spirv => unreachable,
......@@ -941,11 +958,13 @@ pub const File = struct {
941958 }
942959 }
943960
961 /// Never called when LLVM is codegenning the ZCU.
944962 pub fn deleteExport(
945963 base: *File,
946964 exported: Zcu.Exported,
947965 name: InternPool.NullTerminatedString,
948966 ) void {
967 assert(base.comp.zcu.?.llvm_object == null);
949968 switch (base.tag) {
950969 .plan9,
951970 .spirv,
......@@ -1077,7 +1096,7 @@ pub const File = struct {
10771096 }
10781097 }
10791098
1080 pub fn linkAsArchive(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void {
1099 fn linkAsArchive(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void {
10811100 dev.check(.lld_linker);
10821101
10831102 const tracy = trace(@src());
......@@ -1103,9 +1122,12 @@ pub const File = struct {
11031122
11041123 // If there is no Zig code to compile, then we should skip flushing the output file
11051124 // because it will not be part of the linker line anyway.
1106 const zcu_obj_path: ?[]const u8 = if (opt_zcu != null) blk: {
1107 try base.flushModule(arena, tid, prog_node);
1108
1125 const zcu_obj_path: ?[]const u8 = if (opt_zcu) |zcu| blk: {
1126 if (zcu.llvm_object == null) {
1127 try base.flushZcu(arena, tid, prog_node);
1128 } else {
1129 // `Compilation.flush` has already made LLVM emit this object file for us.
1130 }
11091131 const dirname = fs.path.dirname(full_out_path_z) orelse ".";
11101132 break :blk try fs.path.join(arena, &.{ dirname, base.zcu_object_sub_path.? });
11111133 } else null;
......@@ -1346,21 +1368,6 @@ pub const File = struct {
13461368 return output_mode == .Lib and !self.isStatic();
13471369 }
13481370
1349 pub fn emitLlvmObject(
1350 base: File,
1351 arena: Allocator,
1352 llvm_object: LlvmObject.Ptr,
1353 prog_node: std.Progress.Node,
1354 ) !void {
1355 return base.comp.emitLlvmObject(arena, .{
1356 .root_dir = base.emit.root_dir,
1357 .sub_path = std.fs.path.dirname(base.emit.sub_path) orelse "",
1358 }, .{
1359 .directory = null,
1360 .basename = base.zcu_object_sub_path.?,
1361 }, llvm_object, prog_node);
1362 }
1363
13641371 pub fn cgFail(
13651372 base: *File,
13661373 nav_index: InternPool.Nav.Index,
......@@ -1600,7 +1607,11 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {
16001607 // on the failed type, so when it is changed the `Nav` will be updated.
16011608 return;
16021609 }
1603 if (comp.bin_file) |lf| {
1610 if (zcu.llvm_object) |llvm_object| {
1611 llvm_object.updateNav(pt, nav_index) catch |err| switch (err) {
1612 error.OutOfMemory => diags.setAllocFailure(),
1613 };
1614 } else if (comp.bin_file) |lf| {
16041615 lf.updateNav(pt, nav_index) catch |err| switch (err) {
16051616 error.OutOfMemory => diags.setAllocFailure(),
16061617 error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)),
......@@ -1616,10 +1627,6 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {
16161627 // Not a retryable failure.
16171628 },
16181629 };
1619 } else if (zcu.llvm_object) |llvm_object| {
1620 llvm_object.updateNav(pt, nav_index) catch |err| switch (err) {
1621 error.OutOfMemory => diags.setAllocFailure(),
1622 };
16231630 }
16241631 },
16251632 .link_func => |func| {
......@@ -1650,11 +1657,13 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {
16501657 // on the failed type, so when that is changed, this type will be updated.
16511658 return;
16521659 }
1653 if (comp.bin_file) |lf| {
1654 lf.updateContainerType(pt, ty) catch |err| switch (err) {
1655 error.OutOfMemory => diags.setAllocFailure(),
1656 error.TypeFailureReported => assert(zcu.failed_types.contains(ty)),
1657 };
1660 if (zcu.llvm_object == null) {
1661 if (comp.bin_file) |lf| {
1662 lf.updateContainerType(pt, ty) catch |err| switch (err) {
1663 error.OutOfMemory => diags.setAllocFailure(),
1664 error.TypeFailureReported => assert(zcu.failed_types.contains(ty)),
1665 };
1666 }
16581667 }
16591668 },
16601669 .update_line_number => |ti| {
......@@ -1664,11 +1673,13 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void {
16641673 }
16651674 const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid));
16661675 defer pt.deactivate();
1667 if (comp.bin_file) |lf| {
1668 lf.updateLineNumber(pt, ti) catch |err| switch (err) {
1669 error.OutOfMemory => diags.setAllocFailure(),
1670 else => |e| log.err("update line number failed: {s}", .{@errorName(e)}),
1671 };
1676 if (pt.zcu.llvm_object == null) {
1677 if (comp.bin_file) |lf| {
1678 lf.updateLineNumber(pt, ti) catch |err| switch (err) {
1679 error.OutOfMemory => diags.setAllocFailure(),
1680 else => |e| log.err("update line number failed: {s}", .{@errorName(e)}),
1681 };
1682 }
16721683 }
16731684 },
16741685 }
src/link/C.zig+2-2
......@@ -382,7 +382,7 @@ pub fn updateLineNumber(self: *C, pt: Zcu.PerThread, ti_id: InternPool.TrackedIn
382382}
383383
384384pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
385 return self.flushModule(arena, tid, prog_node);
385 return self.flushZcu(arena, tid, prog_node);
386386}
387387
388388fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) {
......@@ -400,7 +400,7 @@ fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) {
400400 return defines;
401401}
402402
403pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
403pub fn flushZcu(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
404404 _ = arena; // Has the same lifetime as the call to Compilation.update.
405405
406406 const tracy = trace(@src());
src/link/Coff.zig+30-84
......@@ -3,9 +3,6 @@
33//! LLD for traditional linking (linking relocatable object files).
44//! LLD is also the default linker for LLVM.
55
6/// If this is not null, an object file is created by LLVM and emitted to zcu_object_sub_path.
7llvm_object: ?LlvmObject.Ptr = null,
8
96base: link.File,
107image_base: u64,
118subsystem: ?std.Target.SubSystem,
......@@ -87,6 +84,16 @@ base_relocs: BaseRelocationTable = .{},
8784/// Hot-code swapping state.
8885hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{},
8986
87/// When linking with LLD, these flags are used to determine the subsystem to pass on the LLD command line.
88lld_export_flags: struct {
89 c_main: bool = false,
90 winmain: bool = false,
91 wwinmain: bool = false,
92 winmain_crt_startup: bool = false,
93 wwinmain_crt_startup: bool = false,
94 dllmain_crt_startup: bool = false,
95} = .{},
96
9097const is_hot_update_compatible = switch (builtin.target.os.tag) {
9198 .windows => true,
9299 else => false,
......@@ -302,9 +309,6 @@ pub fn createEmpty(
302309 .pdb_out_path = options.pdb_out_path,
303310 .repro = options.repro,
304311 };
305 if (use_llvm and comp.config.have_zcu) {
306 coff.llvm_object = try LlvmObject.create(arena, comp);
307 }
308312 errdefer coff.base.destroy();
309313
310314 if (use_lld and (use_llvm or !comp.config.have_zcu)) {
......@@ -322,7 +326,6 @@ pub fn createEmpty(
322326 .mode = link.File.determineMode(use_lld, output_mode, link_mode),
323327 });
324328
325 assert(coff.llvm_object == null);
326329 const gpa = comp.gpa;
327330
328331 try coff.strtab.buffer.ensureUnusedCapacity(gpa, @sizeOf(u32));
......@@ -428,8 +431,6 @@ pub fn open(
428431pub fn deinit(coff: *Coff) void {
429432 const gpa = coff.base.comp.gpa;
430433
431 if (coff.llvm_object) |llvm_object| llvm_object.deinit();
432
433434 for (coff.sections.items(.free_list)) |*free_list| {
434435 free_list.deinit(gpa);
435436 }
......@@ -1103,9 +1104,6 @@ pub fn updateFunc(
11031104 if (build_options.skip_non_native and builtin.object_format != .coff) {
11041105 @panic("Attempted to compile for object format that was disabled by build configuration");
11051106 }
1106 if (coff.llvm_object) |llvm_object| {
1107 return llvm_object.updateFunc(pt, func_index, air, liveness);
1108 }
11091107 const tracy = trace(@src());
11101108 defer tracy.end();
11111109
......@@ -1205,7 +1203,6 @@ pub fn updateNav(
12051203 if (build_options.skip_non_native and builtin.object_format != .coff) {
12061204 @panic("Attempted to compile for object format that was disabled by build configuration");
12071205 }
1208 if (coff.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav_index);
12091206 const tracy = trace(@src());
12101207 defer tracy.end();
12111208
......@@ -1330,7 +1327,7 @@ pub fn getOrCreateAtomForLazySymbol(
13301327 }
13311328 state_ptr.* = .pending_flush;
13321329 const atom = atom_ptr.*;
1333 // anyerror needs to be deferred until flushModule
1330 // anyerror needs to be deferred until flushZcu
13341331 if (lazy_sym.ty != .anyerror_type) try coff.updateLazySymbolAtom(pt, lazy_sym, atom, switch (lazy_sym.kind) {
13351332 .code => coff.text_section_index.?,
13361333 .const_data => coff.rdata_section_index.?,
......@@ -1463,8 +1460,6 @@ fn updateNavCode(
14631460}
14641461
14651462pub fn freeNav(coff: *Coff, nav_index: InternPool.NavIndex) void {
1466 if (coff.llvm_object) |llvm_object| return llvm_object.freeNav(nav_index);
1467
14681463 const gpa = coff.base.comp.gpa;
14691464
14701465 if (coff.decls.fetchOrderedRemove(nav_index)) |const_kv| {
......@@ -1485,50 +1480,7 @@ pub fn updateExports(
14851480 }
14861481
14871482 const zcu = pt.zcu;
1488 const ip = &zcu.intern_pool;
1489 const comp = coff.base.comp;
1490 const target = comp.root_mod.resolved_target.result;
1491
1492 if (comp.config.use_llvm) {
1493 // Even in the case of LLVM, we need to notice certain exported symbols in order to
1494 // detect the default subsystem.
1495 for (export_indices) |export_idx| {
1496 const exp = export_idx.ptr(zcu);
1497 const exported_nav_index = switch (exp.exported) {
1498 .nav => |nav| nav,
1499 .uav => continue,
1500 };
1501 const exported_nav = ip.getNav(exported_nav_index);
1502 const exported_ty = exported_nav.typeOf(ip);
1503 if (!ip.isFunctionType(exported_ty)) continue;
1504 const c_cc = target.cCallingConvention().?;
1505 const winapi_cc: std.builtin.CallingConvention = switch (target.cpu.arch) {
1506 .x86 => .{ .x86_stdcall = .{} },
1507 else => c_cc,
1508 };
1509 const exported_cc = Type.fromInterned(exported_ty).fnCallingConvention(zcu);
1510 const CcTag = std.builtin.CallingConvention.Tag;
1511 if (@as(CcTag, exported_cc) == @as(CcTag, c_cc) and exp.opts.name.eqlSlice("main", ip) and comp.config.link_libc) {
1512 zcu.stage1_flags.have_c_main = true;
1513 } else if (@as(CcTag, exported_cc) == @as(CcTag, winapi_cc) and target.os.tag == .windows) {
1514 if (exp.opts.name.eqlSlice("WinMain", ip)) {
1515 zcu.stage1_flags.have_winmain = true;
1516 } else if (exp.opts.name.eqlSlice("wWinMain", ip)) {
1517 zcu.stage1_flags.have_wwinmain = true;
1518 } else if (exp.opts.name.eqlSlice("WinMainCRTStartup", ip)) {
1519 zcu.stage1_flags.have_winmain_crt_startup = true;
1520 } else if (exp.opts.name.eqlSlice("wWinMainCRTStartup", ip)) {
1521 zcu.stage1_flags.have_wwinmain_crt_startup = true;
1522 } else if (exp.opts.name.eqlSlice("DllMainCRTStartup", ip)) {
1523 zcu.stage1_flags.have_dllmain_crt_startup = true;
1524 }
1525 }
1526 }
1527 }
1528
1529 if (coff.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices);
1530
1531 const gpa = comp.gpa;
1483 const gpa = zcu.gpa;
15321484
15331485 const metadata = switch (exported) {
15341486 .nav => |nav| blk: {
......@@ -1621,7 +1573,6 @@ pub fn deleteExport(
16211573 exported: Zcu.Exported,
16221574 name: InternPool.NullTerminatedString,
16231575) void {
1624 if (coff.llvm_object) |_| return;
16251576 const metadata = switch (exported) {
16261577 .nav => |nav| coff.navs.getPtr(nav),
16271578 .uav => |uav| coff.uavs.getPtr(uav),
......@@ -1692,7 +1643,7 @@ pub fn flush(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: st
16921643 };
16931644 }
16941645 switch (comp.config.output_mode) {
1695 .Exe, .Obj => return coff.flushModule(arena, tid, prog_node),
1646 .Exe, .Obj => return coff.flushZcu(arena, tid, prog_node),
16961647 .Lib => return diags.fail("writing lib files not yet implemented for COFF", .{}),
16971648 }
16981649}
......@@ -1711,8 +1662,12 @@ fn linkWithLLD(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
17111662
17121663 // If there is no Zig code to compile, then we should skip flushing the output file because it
17131664 // will not be part of the linker line anyway.
1714 const module_obj_path: ?[]const u8 = if (comp.zcu != null) blk: {
1715 try coff.flushModule(arena, tid, prog_node);
1665 const module_obj_path: ?[]const u8 = if (comp.zcu) |zcu| blk: {
1666 if (zcu.llvm_object == null) {
1667 try coff.flushZcu(arena, tid, prog_node);
1668 } else {
1669 // `Compilation.flush` has already made LLVM emit this object file for us.
1670 }
17161671
17171672 if (fs.path.dirname(full_out_path)) |dirname| {
17181673 break :blk try fs.path.join(arena, &.{ dirname, coff.base.zcu_object_sub_path.? });
......@@ -1998,16 +1953,16 @@ fn linkWithLLD(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
19981953 if (coff.subsystem) |explicit| break :blk explicit;
19991954 switch (target.os.tag) {
20001955 .windows => {
2001 if (comp.zcu) |module| {
2002 if (module.stage1_flags.have_dllmain_crt_startup or is_dyn_lib)
1956 if (comp.zcu != null) {
1957 if (coff.lld_export_flags.dllmain_crt_startup or is_dyn_lib)
20031958 break :blk null;
2004 if (module.stage1_flags.have_c_main or comp.config.is_test or
2005 module.stage1_flags.have_winmain_crt_startup or
2006 module.stage1_flags.have_wwinmain_crt_startup)
1959 if (coff.lld_export_flags.c_main or comp.config.is_test or
1960 coff.lld_export_flags.winmain_crt_startup or
1961 coff.lld_export_flags.wwinmain_crt_startup)
20071962 {
20081963 break :blk .Console;
20091964 }
2010 if (module.stage1_flags.have_winmain or module.stage1_flags.have_wwinmain)
1965 if (coff.lld_export_flags.winmain or coff.lld_export_flags.wwinmain)
20111966 break :blk .Windows;
20121967 }
20131968 },
......@@ -2136,8 +2091,8 @@ fn linkWithLLD(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
21362091 } else {
21372092 try argv.append("-NODEFAULTLIB");
21382093 if (!is_lib and entry_name == null) {
2139 if (comp.zcu) |module| {
2140 if (module.stage1_flags.have_winmain_crt_startup) {
2094 if (comp.zcu != null) {
2095 if (coff.lld_export_flags.winmain_crt_startup) {
21412096 try argv.append("-ENTRY:WinMainCRTStartup");
21422097 } else {
21432098 try argv.append("-ENTRY:wWinMainCRTStartup");
......@@ -2244,7 +2199,7 @@ fn findLib(arena: Allocator, name: []const u8, lib_directories: []const Director
22442199 return null;
22452200}
22462201
2247pub fn flushModule(
2202pub fn flushZcu(
22482203 coff: *Coff,
22492204 arena: Allocator,
22502205 tid: Zcu.PerThread.Id,
......@@ -2256,22 +2211,17 @@ pub fn flushModule(
22562211 const comp = coff.base.comp;
22572212 const diags = &comp.link_diags;
22582213
2259 if (coff.llvm_object) |llvm_object| {
2260 try coff.base.emitLlvmObject(arena, llvm_object, prog_node);
2261 return;
2262 }
2263
22642214 const sub_prog_node = prog_node.start("COFF Flush", 0);
22652215 defer sub_prog_node.end();
22662216
2267 return flushModuleInner(coff, arena, tid) catch |err| switch (err) {
2217 return flushZcuInner(coff, arena, tid) catch |err| switch (err) {
22682218 error.OutOfMemory => return error.OutOfMemory,
22692219 error.LinkFailure => return error.LinkFailure,
22702220 else => |e| return diags.fail("COFF flush failed: {s}", .{@errorName(e)}),
22712221 };
22722222}
22732223
2274fn flushModuleInner(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id) !void {
2224fn flushZcuInner(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id) !void {
22752225 _ = arena;
22762226
22772227 const comp = coff.base.comp;
......@@ -2397,7 +2347,6 @@ pub fn getNavVAddr(
23972347 nav_index: InternPool.Nav.Index,
23982348 reloc_info: link.File.RelocInfo,
23992349) !u64 {
2400 assert(coff.llvm_object == null);
24012350 const zcu = pt.zcu;
24022351 const ip = &zcu.intern_pool;
24032352 const nav = ip.getNav(nav_index);
......@@ -2483,8 +2432,6 @@ pub fn getUavVAddr(
24832432 uav: InternPool.Index,
24842433 reloc_info: link.File.RelocInfo,
24852434) !u64 {
2486 assert(coff.llvm_object == null);
2487
24882435 const this_atom_index = coff.uavs.get(uav).?.atom;
24892436 const sym_index = coff.getAtom(this_atom_index).getSymbolIndex().?;
24902437 const atom_index = coff.getAtomIndexForSymbol(.{
......@@ -3798,7 +3745,6 @@ const trace = @import("../tracy.zig").trace;
37983745
37993746const Air = @import("../Air.zig");
38003747const Compilation = @import("../Compilation.zig");
3801const LlvmObject = @import("../codegen/llvm.zig").Object;
38023748const Zcu = @import("../Zcu.zig");
38033749const InternPool = @import("../InternPool.zig");
38043750const TableSection = @import("table_section.zig").TableSection;
src/link/Dwarf.zig+1-1
......@@ -4391,7 +4391,7 @@ fn refAbbrevCode(dwarf: *Dwarf, abbrev_code: AbbrevCode) UpdateError!@typeInfo(A
43914391 return @intFromEnum(abbrev_code);
43924392}
43934393
4394pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
4394pub fn flushZcu(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
43954395 const zcu = pt.zcu;
43964396 const ip = &zcu.intern_pool;
43974397
src/link/Elf.zig+10-30
......@@ -32,9 +32,6 @@ entry_name: ?[]const u8,
3232
3333ptr_width: PtrWidth,
3434
35/// If this is not null, an object file is created by LLVM and emitted to zcu_object_sub_path.
36llvm_object: ?LlvmObject.Ptr = null,
37
3835/// A list of all input files.
3936/// First index is a special "null file". Order is otherwise not observed.
4037files: std.MultiArrayList(File.Entry) = .{},
......@@ -344,9 +341,6 @@ pub fn createEmpty(
344341 .print_map = options.print_map,
345342 .dump_argv_list = .empty,
346343 };
347 if (use_llvm and comp.config.have_zcu) {
348 self.llvm_object = try LlvmObject.create(arena, comp);
349 }
350344 errdefer self.base.destroy();
351345
352346 if (use_lld and (use_llvm or !comp.config.have_zcu)) {
......@@ -457,8 +451,6 @@ pub fn open(
457451pub fn deinit(self: *Elf) void {
458452 const gpa = self.base.comp.gpa;
459453
460 if (self.llvm_object) |llvm_object| llvm_object.deinit();
461
462454 for (self.file_handles.items) |fh| {
463455 fh.close();
464456 }
......@@ -515,7 +507,6 @@ pub fn deinit(self: *Elf) void {
515507}
516508
517509pub fn getNavVAddr(self: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, reloc_info: link.File.RelocInfo) !u64 {
518 assert(self.llvm_object == null);
519510 return self.zigObjectPtr().?.getNavVAddr(self, pt, nav_index, reloc_info);
520511}
521512
......@@ -530,7 +521,6 @@ pub fn lowerUav(
530521}
531522
532523pub fn getUavVAddr(self: *Elf, uav: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
533 assert(self.llvm_object == null);
534524 return self.zigObjectPtr().?.getUavVAddr(self, uav, reloc_info);
535525}
536526
......@@ -805,35 +795,29 @@ pub fn flush(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std
805795 else => |e| return diags.fail("failed to link with LLD: {s}", .{@errorName(e)}),
806796 };
807797 }
808 try self.flushModule(arena, tid, prog_node);
798 try self.flushZcu(arena, tid, prog_node);
809799}
810800
811pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
801pub fn flushZcu(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
812802 const tracy = trace(@src());
813803 defer tracy.end();
814804
815805 const comp = self.base.comp;
816806 const diags = &comp.link_diags;
817807
818 if (self.llvm_object) |llvm_object| {
819 try self.base.emitLlvmObject(arena, llvm_object, prog_node);
820 const use_lld = build_options.have_llvm and comp.config.use_lld;
821 if (use_lld) return;
822 }
823
824808 if (comp.verbose_link) Compilation.dump_argv(self.dump_argv_list.items);
825809
826810 const sub_prog_node = prog_node.start("ELF Flush", 0);
827811 defer sub_prog_node.end();
828812
829 return flushModuleInner(self, arena, tid) catch |err| switch (err) {
813 return flushZcuInner(self, arena, tid) catch |err| switch (err) {
830814 error.OutOfMemory => return error.OutOfMemory,
831815 error.LinkFailure => return error.LinkFailure,
832816 else => |e| return diags.fail("ELF flush failed: {s}", .{@errorName(e)}),
833817 };
834818}
835819
836fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
820fn flushZcuInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
837821 const comp = self.base.comp;
838822 const gpa = comp.gpa;
839823 const diags = &comp.link_diags;
......@@ -1523,8 +1507,12 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s
15231507
15241508 // If there is no Zig code to compile, then we should skip flushing the output file because it
15251509 // will not be part of the linker line anyway.
1526 const module_obj_path: ?[]const u8 = if (comp.zcu != null) blk: {
1527 try self.flushModule(arena, tid, prog_node);
1510 const module_obj_path: ?[]const u8 = if (comp.zcu) |zcu| blk: {
1511 if (zcu.llvm_object == null) {
1512 try self.flushZcu(arena, tid, prog_node);
1513 } else {
1514 // `Compilation.flush` has already made LLVM emit this object file for us.
1515 }
15281516
15291517 if (fs.path.dirname(full_out_path)) |dirname| {
15301518 break :blk try fs.path.join(arena, &.{ dirname, self.base.zcu_object_sub_path.? });
......@@ -2385,7 +2373,6 @@ pub fn writeElfHeader(self: *Elf) !void {
23852373}
23862374
23872375pub fn freeNav(self: *Elf, nav: InternPool.Nav.Index) void {
2388 if (self.llvm_object) |llvm_object| return llvm_object.freeNav(nav);
23892376 return self.zigObjectPtr().?.freeNav(self, nav);
23902377}
23912378
......@@ -2399,7 +2386,6 @@ pub fn updateFunc(
23992386 if (build_options.skip_non_native and builtin.object_format != .elf) {
24002387 @panic("Attempted to compile for object format that was disabled by build configuration");
24012388 }
2402 if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(pt, func_index, air, liveness);
24032389 return self.zigObjectPtr().?.updateFunc(self, pt, func_index, air, liveness);
24042390}
24052391
......@@ -2411,7 +2397,6 @@ pub fn updateNav(
24112397 if (build_options.skip_non_native and builtin.object_format != .elf) {
24122398 @panic("Attempted to compile for object format that was disabled by build configuration");
24132399 }
2414 if (self.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav);
24152400 return self.zigObjectPtr().?.updateNav(self, pt, nav);
24162401}
24172402
......@@ -2423,7 +2408,6 @@ pub fn updateContainerType(
24232408 if (build_options.skip_non_native and builtin.object_format != .elf) {
24242409 @panic("Attempted to compile for object format that was disabled by build configuration");
24252410 }
2426 if (self.llvm_object) |_| return;
24272411 const zcu = pt.zcu;
24282412 const gpa = zcu.gpa;
24292413 return self.zigObjectPtr().?.updateContainerType(pt, ty) catch |err| switch (err) {
......@@ -2449,12 +2433,10 @@ pub fn updateExports(
24492433 if (build_options.skip_non_native and builtin.object_format != .elf) {
24502434 @panic("Attempted to compile for object format that was disabled by build configuration");
24512435 }
2452 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices);
24532436 return self.zigObjectPtr().?.updateExports(self, pt, exported, export_indices);
24542437}
24552438
24562439pub fn updateLineNumber(self: *Elf, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {
2457 if (self.llvm_object) |_| return;
24582440 return self.zigObjectPtr().?.updateLineNumber(pt, ti_id);
24592441}
24602442
......@@ -2463,7 +2445,6 @@ pub fn deleteExport(
24632445 exported: Zcu.Exported,
24642446 name: InternPool.NullTerminatedString,
24652447) void {
2466 if (self.llvm_object) |_| return;
24672448 return self.zigObjectPtr().?.deleteExport(self, exported, name);
24682449}
24692450
......@@ -5332,7 +5313,6 @@ const GotSection = synthetic_sections.GotSection;
53325313const GotPltSection = synthetic_sections.GotPltSection;
53335314const HashSection = synthetic_sections.HashSection;
53345315const LinkerDefined = @import("Elf/LinkerDefined.zig");
5335const LlvmObject = @import("../codegen/llvm.zig").Object;
53365316const Zcu = @import("../Zcu.zig");
53375317const Object = @import("Elf/Object.zig");
53385318const InternPool = @import("../InternPool.zig");
src/link/Elf/ZigObject.zig+4-4
......@@ -310,7 +310,7 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {
310310 if (self.dwarf) |*dwarf| {
311311 const pt: Zcu.PerThread = .activate(elf_file.base.comp.zcu.?, tid);
312312 defer pt.deactivate();
313 try dwarf.flushModule(pt);
313 try dwarf.flushZcu(pt);
314314
315315 const gpa = elf_file.base.comp.gpa;
316316 const cpu_arch = elf_file.getTarget().cpu.arch;
......@@ -481,7 +481,7 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {
481481 self.debug_str_section_dirty = false;
482482 }
483483
484 // The point of flushModule() is to commit changes, so in theory, nothing should
484 // The point of flushZcu() is to commit changes, so in theory, nothing should
485485 // be dirty after this. However, it is possible for some things to remain
486486 // dirty because they fail to be written in the event of compile errors,
487487 // such as debug_line_header_dirty and debug_info_header_dirty.
......@@ -661,7 +661,7 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
661661 if (shdr.sh_type == elf.SHT_NOBITS) continue;
662662 if (atom_ptr.scanRelocsRequiresCode(elf_file)) {
663663 // TODO ideally we don't have to fetch the code here.
664 // Perhaps it would make sense to save the code until flushModule where we
664 // Perhaps it would make sense to save the code until flushZcu where we
665665 // would free all of generated code?
666666 const code = try self.codeAlloc(elf_file, atom_index);
667667 defer gpa.free(code);
......@@ -1075,7 +1075,7 @@ pub fn getOrCreateMetadataForLazySymbol(
10751075 }
10761076 state_ptr.* = .pending_flush;
10771077 const symbol_index = symbol_index_ptr.*;
1078 // anyerror needs to be deferred until flushModule
1078 // anyerror needs to be deferred until flushZcu
10791079 if (lazy_sym.ty != .anyerror_type) try self.updateLazySymbol(elf_file, pt, lazy_sym, symbol_index);
10801080 return symbol_index;
10811081}
src/link/Goff.zig+22-24
......@@ -17,10 +17,8 @@ const link = @import("../link.zig");
1717const trace = @import("../tracy.zig").trace;
1818const build_options = @import("build_options");
1919const Air = @import("../Air.zig");
20const LlvmObject = @import("../codegen/llvm.zig").Object;
2120
2221base: link.File,
23llvm_object: LlvmObject.Ptr,
2422
2523pub fn createEmpty(
2624 arena: Allocator,
......@@ -36,7 +34,6 @@ pub fn createEmpty(
3634 assert(!use_lld); // Caught by Compilation.Config.resolve.
3735 assert(target.os.tag == .zos); // Caught by Compilation.Config.resolve.
3836
39 const llvm_object = try LlvmObject.create(arena, comp);
4037 const goff = try arena.create(Goff);
4138 goff.* = .{
4239 .base = .{
......@@ -52,7 +49,6 @@ pub fn createEmpty(
5249 .disable_lld_caching = options.disable_lld_caching,
5350 .build_id = options.build_id,
5451 },
55 .llvm_object = llvm_object,
5652 };
5753
5854 return goff;
......@@ -70,7 +66,7 @@ pub fn open(
7066}
7167
7268pub fn deinit(self: *Goff) void {
73 self.llvm_object.deinit();
69 _ = self;
7470}
7571
7672pub fn updateFunc(
......@@ -80,17 +76,19 @@ pub fn updateFunc(
8076 air: Air,
8177 liveness: Air.Liveness,
8278) link.File.UpdateNavError!void {
83 if (build_options.skip_non_native and builtin.object_format != .goff)
84 @panic("Attempted to compile for object format that was disabled by build configuration");
85
86 try self.llvm_object.updateFunc(pt, func_index, air, liveness);
79 _ = self;
80 _ = pt;
81 _ = func_index;
82 _ = air;
83 _ = liveness;
84 unreachable; // we always use llvm
8785}
8886
8987pub fn updateNav(self: *Goff, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.File.UpdateNavError!void {
90 if (build_options.skip_non_native and builtin.object_format != .goff)
91 @panic("Attempted to compile for object format that was disabled by build configuration");
92
93 return self.llvm_object.updateNav(pt, nav);
88 _ = self;
89 _ = pt;
90 _ = nav;
91 unreachable; // we always use llvm
9492}
9593
9694pub fn updateExports(
......@@ -99,21 +97,21 @@ pub fn updateExports(
9997 exported: Zcu.Exported,
10098 export_indices: []const Zcu.Export.Index,
10199) !void {
102 if (build_options.skip_non_native and builtin.object_format != .goff)
103 @panic("Attempted to compile for object format that was disabled by build configuration");
104
105 return self.llvm_object.updateExports(pt, exported, export_indices);
100 _ = self;
101 _ = pt;
102 _ = exported;
103 _ = export_indices;
104 unreachable; // we always use llvm
106105}
107106
108107pub fn flush(self: *Goff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
109 return self.flushModule(arena, tid, prog_node);
108 return self.flushZcu(arena, tid, prog_node);
110109}
111110
112pub fn flushModule(self: *Goff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
113 if (build_options.skip_non_native and builtin.object_format != .goff)
114 @panic("Attempted to compile for object format that was disabled by build configuration");
115
111pub fn flushZcu(self: *Goff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
112 _ = self;
113 _ = arena;
116114 _ = tid;
117
118 try self.base.emitLlvmObject(arena, self.llvm_object, prog_node);
115 _ = prog_node;
116 unreachable; // we always use llvm
119117}
src/link/MachO.zig+4-25
......@@ -6,9 +6,6 @@ base: link.File,
66
77rpath_list: []const []const u8,
88
9/// If this is not null, an object file is created by LLVM and emitted to zcu_object_sub_path.
10llvm_object: ?LlvmObject.Ptr = null,
11
129/// Debug symbols bundle (or dSym).
1310d_sym: ?DebugSymbols = null,
1411
......@@ -225,9 +222,6 @@ pub fn createEmpty(
225222 .force_load_objc = options.force_load_objc,
226223 .discard_local_symbols = options.discard_local_symbols,
227224 };
228 if (use_llvm and comp.config.have_zcu) {
229 self.llvm_object = try LlvmObject.create(arena, comp);
230 }
231225 errdefer self.base.destroy();
232226
233227 self.base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{
......@@ -280,8 +274,6 @@ pub fn open(
280274pub fn deinit(self: *MachO) void {
281275 const gpa = self.base.comp.gpa;
282276
283 if (self.llvm_object) |llvm_object| llvm_object.deinit();
284
285277 if (self.d_sym) |*d_sym| {
286278 d_sym.deinit();
287279 }
......@@ -350,10 +342,10 @@ pub fn flush(
350342 tid: Zcu.PerThread.Id,
351343 prog_node: std.Progress.Node,
352344) link.File.FlushError!void {
353 try self.flushModule(arena, tid, prog_node);
345 try self.flushZcu(arena, tid, prog_node);
354346}
355347
356pub fn flushModule(
348pub fn flushZcu(
357349 self: *MachO,
358350 arena: Allocator,
359351 tid: Zcu.PerThread.Id,
......@@ -366,10 +358,6 @@ pub fn flushModule(
366358 const gpa = comp.gpa;
367359 const diags = &self.base.comp.link_diags;
368360
369 if (self.llvm_object) |llvm_object| {
370 try self.base.emitLlvmObject(arena, llvm_object, prog_node);
371 }
372
373361 const sub_prog_node = prog_node.start("MachO Flush", 0);
374362 defer sub_prog_node.end();
375363
......@@ -385,7 +373,7 @@ pub fn flushModule(
385373 // --verbose-link
386374 if (comp.verbose_link) try self.dumpArgv(comp);
387375
388 if (self.getZigObject()) |zo| try zo.flushModule(self, tid);
376 if (self.getZigObject()) |zo| try zo.flushZcu(self, tid);
389377 if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, module_obj_path);
390378 if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path);
391379
......@@ -629,7 +617,7 @@ pub fn flushModule(
629617 error.LinkFailure => return error.LinkFailure,
630618 else => |e| return diags.fail("failed to calculate and write uuid: {s}", .{@errorName(e)}),
631619 };
632 if (self.getDebugSymbols()) |dsym| dsym.flushModule(self) catch |err| switch (err) {
620 if (self.getDebugSymbols()) |dsym| dsym.flushZcu(self) catch |err| switch (err) {
633621 error.OutOfMemory => return error.OutOfMemory,
634622 else => |e| return diags.fail("failed to get debug symbols: {s}", .{@errorName(e)}),
635623 };
......@@ -3079,7 +3067,6 @@ pub fn updateFunc(
30793067 if (build_options.skip_non_native and builtin.object_format != .macho) {
30803068 @panic("Attempted to compile for object format that was disabled by build configuration");
30813069 }
3082 if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(pt, func_index, air, liveness);
30833070 return self.getZigObject().?.updateFunc(self, pt, func_index, air, liveness);
30843071}
30853072
......@@ -3087,12 +3074,10 @@ pub fn updateNav(self: *MachO, pt: Zcu.PerThread, nav: InternPool.Nav.Index) lin
30873074 if (build_options.skip_non_native and builtin.object_format != .macho) {
30883075 @panic("Attempted to compile for object format that was disabled by build configuration");
30893076 }
3090 if (self.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav);
30913077 return self.getZigObject().?.updateNav(self, pt, nav);
30923078}
30933079
30943080pub fn updateLineNumber(self: *MachO, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void {
3095 if (self.llvm_object) |_| return;
30963081 return self.getZigObject().?.updateLineNumber(pt, ti_id);
30973082}
30983083
......@@ -3105,7 +3090,6 @@ pub fn updateExports(
31053090 if (build_options.skip_non_native and builtin.object_format != .macho) {
31063091 @panic("Attempted to compile for object format that was disabled by build configuration");
31073092 }
3108 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices);
31093093 return self.getZigObject().?.updateExports(self, pt, exported, export_indices);
31103094}
31113095
......@@ -3114,17 +3098,14 @@ pub fn deleteExport(
31143098 exported: Zcu.Exported,
31153099 name: InternPool.NullTerminatedString,
31163100) void {
3117 if (self.llvm_object) |_| return;
31183101 return self.getZigObject().?.deleteExport(self, exported, name);
31193102}
31203103
31213104pub fn freeNav(self: *MachO, nav: InternPool.Nav.Index) void {
3122 if (self.llvm_object) |llvm_object| return llvm_object.freeNav(nav);
31233105 return self.getZigObject().?.freeNav(nav);
31243106}
31253107
31263108pub fn getNavVAddr(self: *MachO, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, reloc_info: link.File.RelocInfo) !u64 {
3127 assert(self.llvm_object == null);
31283109 return self.getZigObject().?.getNavVAddr(self, pt, nav_index, reloc_info);
31293110}
31303111
......@@ -3139,7 +3120,6 @@ pub fn lowerUav(
31393120}
31403121
31413122pub fn getUavVAddr(self: *MachO, uav: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
3142 assert(self.llvm_object == null);
31433123 return self.getZigObject().?.getUavVAddr(self, uav, reloc_info);
31443124}
31453125
......@@ -5496,7 +5476,6 @@ const ObjcStubsSection = synthetic.ObjcStubsSection;
54965476const Object = @import("MachO/Object.zig");
54975477const LazyBind = bind.LazyBind;
54985478const LaSymbolPtrSection = synthetic.LaSymbolPtrSection;
5499const LlvmObject = @import("../codegen/llvm.zig").Object;
55005479const Md5 = std.crypto.hash.Md5;
55015480const Zcu = @import("../Zcu.zig");
55025481const InternPool = @import("../InternPool.zig");
src/link/MachO/DebugSymbols.zig+1-1
......@@ -178,7 +178,7 @@ fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) !u64
178178 return offset;
179179}
180180
181pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void {
181pub fn flushZcu(self: *DebugSymbols, macho_file: *MachO) !void {
182182 const zo = macho_file.getZigObject().?;
183183 for (self.relocs.items) |*reloc| {
184184 const sym = zo.symbols.items[reloc.target];
src/link/MachO/ZigObject.zig+4-4
......@@ -550,7 +550,7 @@ pub fn getInputSection(self: ZigObject, atom: Atom, macho_file: *MachO) macho.se
550550 return sect;
551551}
552552
553pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id) link.File.FlushError!void {
553pub fn flushZcu(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id) link.File.FlushError!void {
554554 const diags = &macho_file.base.comp.link_diags;
555555
556556 // Handle any lazy symbols that were emitted by incremental compilation.
......@@ -589,7 +589,7 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id)
589589 if (self.dwarf) |*dwarf| {
590590 const pt: Zcu.PerThread = .activate(macho_file.base.comp.zcu.?, tid);
591591 defer pt.deactivate();
592 dwarf.flushModule(pt) catch |err| switch (err) {
592 dwarf.flushZcu(pt) catch |err| switch (err) {
593593 error.OutOfMemory => return error.OutOfMemory,
594594 else => |e| return diags.fail("failed to flush dwarf module: {s}", .{@errorName(e)}),
595595 };
......@@ -599,7 +599,7 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id)
599599 self.debug_strtab_dirty = false;
600600 }
601601
602 // The point of flushModule() is to commit changes, so in theory, nothing should
602 // The point of flushZcu() is to commit changes, so in theory, nothing should
603603 // be dirty after this. However, it is possible for some things to remain
604604 // dirty because they fail to be written in the event of compile errors,
605605 // such as debug_line_header_dirty and debug_info_header_dirty.
......@@ -1537,7 +1537,7 @@ pub fn getOrCreateMetadataForLazySymbol(
15371537 }
15381538 state_ptr.* = .pending_flush;
15391539 const symbol_index = symbol_index_ptr.*;
1540 // anyerror needs to be deferred until flushModule
1540 // anyerror needs to be deferred until flushZcu
15411541 if (lazy_sym.ty != .anyerror_type) try self.updateLazySymbol(macho_file, pt, lazy_sym, symbol_index);
15421542 return symbol_index;
15431543}
src/link/Plan9.zig+5-5
......@@ -494,7 +494,7 @@ fn updateFinish(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
494494 // write the symbol
495495 // we already have the got index
496496 const sym: aout.Sym = .{
497 .value = undefined, // the value of stuff gets filled in in flushModule
497 .value = undefined, // the value of stuff gets filled in in flushZcu
498498 .type = atom.type,
499499 .name = try gpa.dupe(u8, nav.name.toSlice(ip)),
500500 };
......@@ -543,7 +543,7 @@ pub fn flush(
543543 .Obj => return diags.fail("writing plan9 object files unimplemented", .{}),
544544 .Lib => return diags.fail("writing plan9 lib files unimplemented", .{}),
545545 }
546 return self.flushModule(arena, tid, prog_node);
546 return self.flushZcu(arena, tid, prog_node);
547547}
548548
549549pub fn changeLine(l: *std.ArrayList(u8), delta_line: i32) !void {
......@@ -586,7 +586,7 @@ fn atomCount(self: *Plan9) usize {
586586 return data_nav_count + fn_nav_count + lazy_atom_count + extern_atom_count + uav_atom_count;
587587}
588588
589pub fn flushModule(
589pub fn flushZcu(
590590 self: *Plan9,
591591 arena: Allocator,
592592 /// TODO: stop using this
......@@ -610,7 +610,7 @@ pub fn flushModule(
610610 const sub_prog_node = prog_node.start("Flush Module", 0);
611611 defer sub_prog_node.end();
612612
613 log.debug("flushModule", .{});
613 log.debug("flushZcu", .{});
614614
615615 defer assert(self.hdr.entry != 0x0);
616616
......@@ -1039,7 +1039,7 @@ pub fn getOrCreateAtomForLazySymbol(self: *Plan9, pt: Zcu.PerThread, lazy_sym: F
10391039 const atom = atom_ptr.*;
10401040 _ = try self.getAtomPtr(atom).getOrCreateSymbolTableEntry(self);
10411041 _ = self.getAtomPtr(atom).getOrCreateOffsetTableEntry(self);
1042 // anyerror needs to be deferred until flushModule
1042 // anyerror needs to be deferred until flushZcu
10431043 if (lazy_sym.ty != .anyerror_type) try self.updateLazySymbolAtom(pt, lazy_sym, atom);
10441044 return atom;
10451045}
src/link/SpirV.zig+4-4
......@@ -17,7 +17,7 @@
1717//! All regular functions.
1818
1919// Because SPIR-V requires re-compilation anyway, and so hot swapping will not work
20// anyway, we simply generate all the code in flushModule. This keeps
20// anyway, we simply generate all the code in flushZcu. This keeps
2121// things considerably simpler.
2222
2323const SpirV = @This();
......@@ -194,17 +194,17 @@ pub fn updateExports(
194194}
195195
196196pub fn flush(self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
197 return self.flushModule(arena, tid, prog_node);
197 return self.flushZcu(arena, tid, prog_node);
198198}
199199
200pub fn flushModule(
200pub fn flushZcu(
201201 self: *SpirV,
202202 arena: Allocator,
203203 tid: Zcu.PerThread.Id,
204204 prog_node: std.Progress.Node,
205205) link.File.FlushError!void {
206206 // The goal is to never use this because it's only needed if we need to
207 // write to InternPool, but flushModule is too late to be writing to the
207 // write to InternPool, but flushZcu is too late to be writing to the
208208 // InternPool.
209209 _ = tid;
210210
src/link/Wasm.zig+9-23
......@@ -36,7 +36,6 @@ const abi = @import("../arch/wasm/abi.zig");
3636const Compilation = @import("../Compilation.zig");
3737const Dwarf = @import("Dwarf.zig");
3838const InternPool = @import("../InternPool.zig");
39const LlvmObject = @import("../codegen/llvm.zig").Object;
4039const Zcu = @import("../Zcu.zig");
4140const codegen = @import("../codegen.zig");
4241const dev = @import("../dev.zig");
......@@ -81,8 +80,6 @@ import_table: bool,
8180export_table: bool,
8281/// Output name of the file
8382name: []const u8,
84/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
85llvm_object: ?LlvmObject.Ptr = null,
8683/// List of relocatable files to be linked into the final binary.
8784objects: std.ArrayListUnmanaged(Object) = .{},
8885
......@@ -2992,9 +2989,6 @@ pub fn createEmpty(
29922989 .object_host_name = .none,
29932990 .preloaded_strings = undefined,
29942991 };
2995 if (use_llvm and comp.config.have_zcu) {
2996 wasm.llvm_object = try LlvmObject.create(arena, comp);
2997 }
29982992 errdefer wasm.base.destroy();
29992993
30002994 if (options.object_host_name) |name| wasm.object_host_name = (try wasm.internString(name)).toOptional();
......@@ -3116,7 +3110,6 @@ fn parseArchive(wasm: *Wasm, obj: link.Input.Object) !void {
31163110
31173111pub fn deinit(wasm: *Wasm) void {
31183112 const gpa = wasm.base.comp.gpa;
3119 if (wasm.llvm_object) |llvm_object| llvm_object.deinit();
31203113
31213114 wasm.navs_exe.deinit(gpa);
31223115 wasm.navs_obj.deinit(gpa);
......@@ -3196,7 +3189,6 @@ pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index,
31963189 if (build_options.skip_non_native and builtin.object_format != .wasm) {
31973190 @panic("Attempted to compile for object format that was disabled by build configuration");
31983191 }
3199 if (wasm.llvm_object) |llvm_object| return llvm_object.updateFunc(pt, func_index, air, liveness);
32003192
32013193 dev.check(.wasm_backend);
32023194
......@@ -3228,7 +3220,6 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
32283220 if (build_options.skip_non_native and builtin.object_format != .wasm) {
32293221 @panic("Attempted to compile for object format that was disabled by build configuration");
32303222 }
3231 if (wasm.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav_index);
32323223 const zcu = pt.zcu;
32333224 const ip = &zcu.intern_pool;
32343225 const nav = ip.getNav(nav_index);
......@@ -3308,8 +3299,6 @@ pub fn deleteExport(
33083299 exported: Zcu.Exported,
33093300 name: InternPool.NullTerminatedString,
33103301) void {
3311 if (wasm.llvm_object != null) return;
3312
33133302 const zcu = wasm.base.comp.zcu.?;
33143303 const ip = &zcu.intern_pool;
33153304 const name_slice = name.toSlice(ip);
......@@ -3332,7 +3321,6 @@ pub fn updateExports(
33323321 if (build_options.skip_non_native and builtin.object_format != .wasm) {
33333322 @panic("Attempted to compile for object format that was disabled by build configuration");
33343323 }
3335 if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices);
33363324
33373325 const zcu = pt.zcu;
33383326 const gpa = zcu.gpa;
......@@ -3391,7 +3379,7 @@ pub fn flush(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: st
33913379 else => |e| return diags.fail("failed to link with LLD: {s}", .{@errorName(e)}),
33923380 };
33933381 }
3394 return wasm.flushModule(arena, tid, prog_node);
3382 return wasm.flushZcu(arena, tid, prog_node);
33953383}
33963384
33973385pub fn prelink(wasm: *Wasm, prog_node: std.Progress.Node) link.File.FlushError!void {
......@@ -3785,26 +3773,20 @@ fn markTable(wasm: *Wasm, i: ObjectTableIndex) link.File.FlushError!void {
37853773 try wasm.tables.put(wasm.base.comp.gpa, .fromObjectTable(i), {});
37863774}
37873775
3788pub fn flushModule(
3776pub fn flushZcu(
37893777 wasm: *Wasm,
37903778 arena: Allocator,
37913779 tid: Zcu.PerThread.Id,
37923780 prog_node: std.Progress.Node,
37933781) link.File.FlushError!void {
37943782 // The goal is to never use this because it's only needed if we need to
3795 // write to InternPool, but flushModule is too late to be writing to the
3783 // write to InternPool, but flushZcu is too late to be writing to the
37963784 // InternPool.
37973785 _ = tid;
37983786 const comp = wasm.base.comp;
3799 const use_lld = build_options.have_llvm and comp.config.use_lld;
38003787 const diags = &comp.link_diags;
38013788 const gpa = comp.gpa;
38023789
3803 if (wasm.llvm_object) |llvm_object| {
3804 try wasm.base.emitLlvmObject(arena, llvm_object, prog_node);
3805 if (use_lld) return;
3806 }
3807
38083790 if (comp.verbose_link) Compilation.dump_argv(wasm.dump_argv_list.items);
38093791
38103792 if (wasm.base.zcu_object_sub_path) |path| {
......@@ -3870,8 +3852,12 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
38703852
38713853 // If there is no Zig code to compile, then we should skip flushing the output file because it
38723854 // will not be part of the linker line anyway.
3873 const module_obj_path: ?[]const u8 = if (comp.zcu != null) blk: {
3874 try wasm.flushModule(arena, tid, prog_node);
3855 const module_obj_path: ?[]const u8 = if (comp.zcu) |zcu| blk: {
3856 if (zcu.llvm_object == null) {
3857 try wasm.flushZcu(arena, tid, prog_node);
3858 } else {
3859 // `Compilation.flush` has already made LLVM emit this object file for us.
3860 }
38753861
38763862 if (fs.path.dirname(full_out_path)) |dirname| {
38773863 break :blk try fs.path.join(arena, &.{ dirname, wasm.base.zcu_object_sub_path.? });
src/link/Xcoff.zig+22-24
......@@ -17,10 +17,8 @@ const link = @import("../link.zig");
1717const trace = @import("../tracy.zig").trace;
1818const build_options = @import("build_options");
1919const Air = @import("../Air.zig");
20const LlvmObject = @import("../codegen/llvm.zig").Object;
2120
2221base: link.File,
23llvm_object: LlvmObject.Ptr,
2422
2523pub fn createEmpty(
2624 arena: Allocator,
......@@ -36,7 +34,6 @@ pub fn createEmpty(
3634 assert(!use_lld); // Caught by Compilation.Config.resolve.
3735 assert(target.os.tag == .aix); // Caught by Compilation.Config.resolve.
3836
39 const llvm_object = try LlvmObject.create(arena, comp);
4037 const xcoff = try arena.create(Xcoff);
4138 xcoff.* = .{
4239 .base = .{
......@@ -52,7 +49,6 @@ pub fn createEmpty(
5249 .disable_lld_caching = options.disable_lld_caching,
5350 .build_id = options.build_id,
5451 },
55 .llvm_object = llvm_object,
5652 };
5753
5854 return xcoff;
......@@ -70,7 +66,7 @@ pub fn open(
7066}
7167
7268pub fn deinit(self: *Xcoff) void {
73 self.llvm_object.deinit();
69 _ = self;
7470}
7571
7672pub fn updateFunc(
......@@ -80,17 +76,19 @@ pub fn updateFunc(
8076 air: Air,
8177 liveness: Air.Liveness,
8278) link.File.UpdateNavError!void {
83 if (build_options.skip_non_native and builtin.object_format != .xcoff)
84 @panic("Attempted to compile for object format that was disabled by build configuration");
85
86 try self.llvm_object.updateFunc(pt, func_index, air, liveness);
79 _ = self;
80 _ = pt;
81 _ = func_index;
82 _ = air;
83 _ = liveness;
84 unreachable; // we always use llvm
8785}
8886
8987pub fn updateNav(self: *Xcoff, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.File.UpdateNavError!void {
90 if (build_options.skip_non_native and builtin.object_format != .xcoff)
91 @panic("Attempted to compile for object format that was disabled by build configuration");
92
93 return self.llvm_object.updateNav(pt, nav);
88 _ = self;
89 _ = pt;
90 _ = nav;
91 unreachable; // we always use llvm
9492}
9593
9694pub fn updateExports(
......@@ -99,21 +97,21 @@ pub fn updateExports(
9997 exported: Zcu.Exported,
10098 export_indices: []const Zcu.Export.Index,
10199) !void {
102 if (build_options.skip_non_native and builtin.object_format != .xcoff)
103 @panic("Attempted to compile for object format that was disabled by build configuration");
104
105 return self.llvm_object.updateExports(pt, exported, export_indices);
100 _ = self;
101 _ = pt;
102 _ = exported;
103 _ = export_indices;
104 unreachable; // we always use llvm
106105}
107106
108107pub fn flush(self: *Xcoff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
109 return self.flushModule(arena, tid, prog_node);
108 return self.flushZcu(arena, tid, prog_node);
110109}
111110
112pub fn flushModule(self: *Xcoff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
113 if (build_options.skip_non_native and builtin.object_format != .xcoff)
114 @panic("Attempted to compile for object format that was disabled by build configuration");
115
111pub fn flushZcu(self: *Xcoff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void {
112 _ = self;
113 _ = arena;
116114 _ = tid;
117
118 try self.base.emitLlvmObject(arena, self.llvm_object, prog_node);
115 _ = prog_node;
116 unreachable; // we always use llvm
119117}
src/target.zig+1-1
......@@ -739,7 +739,7 @@ pub fn functionPointerMask(target: std.Target) ?u64 {
739739
740740pub fn supportsTailCall(target: std.Target, backend: std.builtin.CompilerBackend) bool {
741741 switch (backend) {
742 .stage1, .stage2_llvm => return @import("codegen/llvm.zig").supportsTailCall(target),
742 .stage2_llvm => return @import("codegen/llvm.zig").supportsTailCall(target),
743743 .stage2_c => return true,
744744 else => return false,
745745 }