diff --git a/src/Compilation.zig b/src/Compilation.zig index 69cb2c4d6f..61201f39f4 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2188,14 +2188,10 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil }, } - // Handle the case of e.g. -fno-emit-bin -femit-llvm-ir. - if (options.emit_bin == null and (comp.verbose_llvm_ir != null or - comp.verbose_llvm_bc != null or - (use_llvm and comp.emit_asm != null) or - comp.emit_llvm_ir != null or - comp.emit_llvm_bc != null)) - { - if (opt_zcu) |zcu| zcu.llvm_object = try LlvmObject.create(arena, comp); + if (use_llvm) { + if (opt_zcu) |zcu| { + zcu.llvm_object = try LlvmObject.create(arena, comp); + } } break :comp comp; @@ -2945,6 +2941,33 @@ fn flush( tid: Zcu.PerThread.Id, prog_node: std.Progress.Node, ) !void { + if (comp.zcu) |zcu| { + if (zcu.llvm_object) |llvm_object| { + // Emit the ZCU object from LLVM now; it's required to flush the output file. + // If there's an output file, it wants to decide where the LLVM object goes! + const zcu_obj_emit_loc: ?EmitLoc = if (comp.bin_file) |lf| .{ + .directory = null, + .basename = lf.zcu_object_sub_path.?, + } else null; + const sub_prog_node = prog_node.start("LLVM Emit Object", 0); + defer sub_prog_node.end(); + try llvm_object.emit(.{ + .pre_ir_path = comp.verbose_llvm_ir, + .pre_bc_path = comp.verbose_llvm_bc, + .bin_path = try resolveEmitLoc(arena, default_artifact_directory, zcu_obj_emit_loc), + .asm_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_asm), + .post_ir_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_llvm_ir), + .post_bc_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_llvm_bc), + + .is_debug = comp.root_mod.optimize_mode == .Debug, + .is_small = comp.root_mod.optimize_mode == .ReleaseSmall, + .time_report = comp.time_report, + .sanitize_thread = comp.config.any_sanitize_thread, + .fuzz = comp.config.any_fuzz, + .lto = comp.config.lto, + }); + } + } if (comp.bin_file) |lf| { // This is needed before reading the error flags. lf.flush(arena, tid, prog_node) catch |err| switch (err) { @@ -2952,13 +2975,8 @@ fn flush( error.OutOfMemory => return error.OutOfMemory, }; } - if (comp.zcu) |zcu| { try link.File.C.flushEmitH(zcu); - - if (zcu.llvm_object) |llvm_object| { - try emitLlvmObject(comp, arena, default_artifact_directory, null, llvm_object, prog_node); - } } } @@ -3233,34 +3251,6 @@ fn emitOthers(comp: *Compilation) void { } } -pub fn emitLlvmObject( - comp: *Compilation, - arena: Allocator, - default_artifact_directory: Cache.Path, - bin_emit_loc: ?EmitLoc, - llvm_object: LlvmObject.Ptr, - prog_node: std.Progress.Node, -) !void { - const sub_prog_node = prog_node.start("LLVM Emit Object", 0); - defer sub_prog_node.end(); - - try llvm_object.emit(.{ - .pre_ir_path = comp.verbose_llvm_ir, - .pre_bc_path = comp.verbose_llvm_bc, - .bin_path = try resolveEmitLoc(arena, default_artifact_directory, bin_emit_loc), - .asm_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_asm), - .post_ir_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_llvm_ir), - .post_bc_path = try resolveEmitLoc(arena, default_artifact_directory, comp.emit_llvm_bc), - - .is_debug = comp.root_mod.optimize_mode == .Debug, - .is_small = comp.root_mod.optimize_mode == .ReleaseSmall, - .time_report = comp.time_report, - .sanitize_thread = comp.config.any_sanitize_thread, - .fuzz = comp.config.any_fuzz, - .lto = comp.config.lto, - }); -} - fn resolveEmitLoc( arena: Allocator, default_artifact_directory: Cache.Path, diff --git a/src/Zcu.zig b/src/Zcu.zig index 7223e5a55e..6a6a74e260 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -56,9 +56,8 @@ comptime { /// General-purpose allocator. Used for both temporary and long-term storage. gpa: Allocator, comp: *Compilation, -/// Usually, the LlvmObject is managed by linker code, however, in the case -/// that -fno-emit-bin is specified, the linker code never executes, so we -/// store the LlvmObject here. +/// If the ZCU is emitting an LLVM object (i.e. we are using the LLVM backend), then this is the +/// `LlvmObject` we are emitting to. llvm_object: ?LlvmObject.Ptr, /// Pointer to externally managed resource. @@ -267,16 +266,6 @@ resolved_references: ?std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) = n /// Reset to `false` at the start of each update in `Compilation.update`. skip_analysis_this_update: bool = false, -stage1_flags: packed struct { - have_winmain: bool = false, - have_wwinmain: bool = false, - have_winmain_crt_startup: bool = false, - have_wwinmain_crt_startup: bool = false, - have_dllmain_crt_startup: bool = false, - have_c_main: bool = false, - reserved: u2 = 0, -} = .{}, - test_functions: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, void) = .empty, global_assembly: std.AutoArrayHashMapUnmanaged(AnalUnit, []u8) = .empty, diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig index 4b4ae98cb4..b10e6d7c41 100644 --- a/src/Zcu/PerThread.zig +++ b/src/Zcu/PerThread.zig @@ -1784,8 +1784,12 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: *A }; } - if (comp.bin_file) |lf| { - lf.updateFunc(pt, func_index, air.*, liveness) catch |err| switch (err) { + if (zcu.llvm_object) |llvm_object| { + llvm_object.updateFunc(pt, func_index, air.*, liveness) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + }; + } else if (comp.bin_file) |lf| { + lf.updateFunc(pt, func_index, air, liveness) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.CodegenFail => assert(zcu.failed_codegen.contains(nav_index)), error.Overflow, error.RelocationNotByteAligned => { @@ -1798,10 +1802,6 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: *A // Not a retryable failure. }, }; - } else if (zcu.llvm_object) |llvm_object| { - llvm_object.updateFunc(pt, func_index, air.*, liveness) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - }; } } @@ -1877,7 +1877,6 @@ fn createFileRootStruct( try pt.scanNamespace(namespace_index, decls); try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); codegen_type: { - if (zcu.comp.config.use_llvm) break :codegen_type; if (file.mod.?.strip) break :codegen_type; // This job depends on any resolve_type_fully jobs queued up before it. try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); @@ -3309,10 +3308,10 @@ fn processExportsInner( .uav => {}, } - if (zcu.comp.bin_file) |lf| { - try zcu.handleUpdateExports(export_indices, lf.updateExports(pt, exported, export_indices)); - } else if (zcu.llvm_object) |llvm_object| { + if (zcu.llvm_object) |llvm_object| { try zcu.handleUpdateExports(export_indices, llvm_object.updateExports(pt, exported, export_indices)); + } else if (zcu.comp.bin_file) |lf| { + try zcu.handleUpdateExports(export_indices, lf.updateExports(pt, exported, export_indices)); } } @@ -4064,7 +4063,6 @@ fn recreateStructType( try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); codegen_type: { - if (zcu.comp.config.use_llvm) break :codegen_type; if (file.mod.?.strip) break :codegen_type; // This job depends on any resolve_type_fully jobs queued up before it. try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); @@ -4157,7 +4155,6 @@ fn recreateUnionType( try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index }); codegen_type: { - if (zcu.comp.config.use_llvm) break :codegen_type; if (file.mod.?.strip) break :codegen_type; // This job depends on any resolve_type_fully jobs queued up before it. try zcu.comp.queueJob(.{ .link_type = wip_ty.index }); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 3fc6250d3f..2b39396c38 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1586,6 +1586,24 @@ pub const Object = struct { const global_index = self.nav_map.get(nav_index).?; const comp = zcu.comp; + // If we're on COFF and linking with LLD, the linker cares about our exports to determine the subsystem in use. + if (comp.bin_file != null and + comp.bin_file.?.tag == .coff and + zcu.comp.config.use_lld and + ip.isFunctionType(ip.getNav(nav_index).typeOf(ip))) + { + const flags = &comp.bin_file.?.cast(.coff).?.lld_export_flags; + for (export_indices) |export_index| { + const name = export_index.ptr(zcu).opts.name; + if (name.eqlSlice("main", ip)) flags.c_main = true; + if (name.eqlSlice("WinMain", ip)) flags.winmain = true; + if (name.eqlSlice("wWinMain", ip)) flags.wwinmain = true; + if (name.eqlSlice("WinMainCRTStartup", ip)) flags.winmain_crt_startup = true; + if (name.eqlSlice("wWinMainCRTStartup", ip)) flags.wwinmain_crt_startup = true; + if (name.eqlSlice("DllMainCRTStartup", ip)) flags.dllmain_crt_startup = true; + } + } + if (export_indices.len != 0) { return updateExportedGlobal(self, zcu, global_index, export_indices); } else { diff --git a/src/codegen/spirv/Section.zig b/src/codegen/spirv/Section.zig index 4fe12f999f..5c2a5fde62 100644 --- a/src/codegen/spirv/Section.zig +++ b/src/codegen/spirv/Section.zig @@ -386,8 +386,6 @@ test "SPIR-V Section emit() - string" { } test "SPIR-V Section emit() - extended mask" { - if (@import("builtin").zig_backend == .stage1) return error.SkipZigTest; - var section = Section{}; defer section.deinit(std.testing.allocator); diff --git a/src/link.zig b/src/link.zig index 7673b44e47..3270d10c87 100644 --- a/src/link.zig +++ b/src/link.zig @@ -19,7 +19,6 @@ const Zcu = @import("Zcu.zig"); const InternPool = @import("InternPool.zig"); const Type = @import("Type.zig"); const Value = @import("Value.zig"); -const LlvmObject = @import("codegen/llvm.zig").Object; const lldMain = @import("main.zig").lldMain; const Package = @import("Package.zig"); const dev = @import("dev.zig"); @@ -704,7 +703,9 @@ pub const File = struct { } /// May be called before or after updateExports for any given Nav. + /// Asserts that the ZCU is not using the LLVM backend. fn updateNav(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) UpdateNavError!void { + assert(base.comp.zcu.?.llvm_object == null); const nav = pt.zcu.intern_pool.getNav(nav_index); assert(nav.status == .fully_resolved); switch (base.tag) { @@ -721,7 +722,9 @@ pub const File = struct { TypeFailureReported, }; + /// Never called when LLVM is codegenning the ZCU. fn updateContainerType(base: *File, pt: Zcu.PerThread, ty: InternPool.Index) UpdateContainerTypeError!void { + assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { else => {}, inline .elf => |tag| { @@ -733,6 +736,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. + /// Never called when LLVM is codegenning the ZCU. pub fn updateFunc( base: *File, pt: Zcu.PerThread, @@ -740,6 +744,7 @@ pub const File = struct { air: Air, liveness: Air.Liveness, ) UpdateNavError!void { + assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { inline else => |tag| { dev.check(tag.devFeature()); @@ -756,7 +761,9 @@ 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`. + /// Never called when LLVM is codegenning the ZCU. fn updateLineNumber(base: *File, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) UpdateLineNumberError!void { + assert(base.comp.zcu.?.llvm_object == null); { const ti = ti_id.resolveFull(&pt.zcu.intern_pool).?; const file = pt.zcu.fileByIndex(ti.file); @@ -846,11 +853,13 @@ pub const File = struct { /// Commit pending changes and write headers. Works based on `effectiveOutputMode` /// rather than final output mode. - pub fn flushModule(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void { + /// Never called when LLVM is codegenning the ZCU. + fn flushZcu(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void { + assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { inline else => |tag| { dev.check(tag.devFeature()); - return @as(*tag.Type(), @fieldParentPtr("base", base)).flushModule(arena, tid, prog_node); + return @as(*tag.Type(), @fieldParentPtr("base", base)).flushZcu(arena, tid, prog_node); }, } } @@ -864,12 +873,14 @@ pub const File = struct { /// a list of size 1, meaning that `exported` is exported once. However, it is possible /// to export the same thing with multiple different symbol names (aliases). /// May be called before or after updateDecl for any given Decl. + /// Never called when LLVM is codegenning the ZCU. pub fn updateExports( base: *File, pt: Zcu.PerThread, exported: Zcu.Exported, export_indices: []const Zcu.Export.Index, ) UpdateExportsError!void { + assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { inline else => |tag| { dev.check(tag.devFeature()); @@ -896,7 +907,9 @@ pub const File = struct { /// `Nav`'s address was not yet resolved, or the containing atom gets moved in virtual memory. /// May be called before or after updateFunc/updateNav therefore it is up to the linker to allocate /// the block/atom. + /// Never called when LLVM is codegenning the ZCU. pub fn getNavVAddr(base: *File, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, reloc_info: RelocInfo) !u64 { + assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { .c => unreachable, .spirv => unreachable, @@ -909,6 +922,7 @@ pub const File = struct { } } + /// Never called when LLVM is codegenning the ZCU. pub fn lowerUav( base: *File, pt: Zcu.PerThread, @@ -916,6 +930,7 @@ pub const File = struct { decl_align: InternPool.Alignment, src_loc: Zcu.LazySrcLoc, ) !codegen.GenResult { + assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { .c => unreachable, .spirv => unreachable, @@ -928,7 +943,9 @@ pub const File = struct { } } + /// Never called when LLVM is codegenning the ZCU. pub fn getUavVAddr(base: *File, decl_val: InternPool.Index, reloc_info: RelocInfo) !u64 { + assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { .c => unreachable, .spirv => unreachable, @@ -941,11 +958,13 @@ pub const File = struct { } } + /// Never called when LLVM is codegenning the ZCU. pub fn deleteExport( base: *File, exported: Zcu.Exported, name: InternPool.NullTerminatedString, ) void { + assert(base.comp.zcu.?.llvm_object == null); switch (base.tag) { .plan9, .spirv, @@ -1077,7 +1096,7 @@ pub const File = struct { } } - pub fn linkAsArchive(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void { + fn linkAsArchive(base: *File, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) FlushError!void { dev.check(.lld_linker); const tracy = trace(@src()); @@ -1103,9 +1122,12 @@ pub const File = struct { // If there is no Zig code to compile, then we should skip flushing the output file // because it will not be part of the linker line anyway. - const zcu_obj_path: ?[]const u8 = if (opt_zcu != null) blk: { - try base.flushModule(arena, tid, prog_node); - + const zcu_obj_path: ?[]const u8 = if (opt_zcu) |zcu| blk: { + if (zcu.llvm_object == null) { + try base.flushZcu(arena, tid, prog_node); + } else { + // `Compilation.flush` has already made LLVM emit this object file for us. + } const dirname = fs.path.dirname(full_out_path_z) orelse "."; break :blk try fs.path.join(arena, &.{ dirname, base.zcu_object_sub_path.? }); } else null; @@ -1346,21 +1368,6 @@ pub const File = struct { return output_mode == .Lib and !self.isStatic(); } - pub fn emitLlvmObject( - base: File, - arena: Allocator, - llvm_object: LlvmObject.Ptr, - prog_node: std.Progress.Node, - ) !void { - return base.comp.emitLlvmObject(arena, .{ - .root_dir = base.emit.root_dir, - .sub_path = std.fs.path.dirname(base.emit.sub_path) orelse "", - }, .{ - .directory = null, - .basename = base.zcu_object_sub_path.?, - }, llvm_object, prog_node); - } - pub fn cgFail( base: *File, nav_index: InternPool.Nav.Index, @@ -1600,7 +1607,11 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void { // on the failed type, so when it is changed the `Nav` will be updated. return; } - if (comp.bin_file) |lf| { + if (zcu.llvm_object) |llvm_object| { + llvm_object.updateNav(pt, nav_index) catch |err| switch (err) { + error.OutOfMemory => diags.setAllocFailure(), + }; + } else 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)), @@ -1616,10 +1627,6 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void { // 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(), - }; } }, .link_func => |func| { @@ -1650,11 +1657,13 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void { // 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)), - }; + if (zcu.llvm_object == null) { + 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)), + }; + } } }, .update_line_number => |ti| { @@ -1664,11 +1673,13 @@ pub fn doTask(comp: *Compilation, tid: usize, task: Task) void { } const pt: Zcu.PerThread = .activate(comp.zcu.?, @enumFromInt(tid)); defer pt.deactivate(); - 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)}), - }; + if (pt.zcu.llvm_object == null) { + 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)}), + }; + } } }, } diff --git a/src/link/C.zig b/src/link/C.zig index c32d8ba80b..15004a26b7 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -382,7 +382,7 @@ pub fn updateLineNumber(self: *C, pt: Zcu.PerThread, ti_id: InternPool.TrackedIn } pub fn flush(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { - return self.flushModule(arena, tid, prog_node); + return self.flushZcu(arena, tid, prog_node); } fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) { @@ -400,7 +400,7 @@ fn abiDefines(self: *C, target: std.Target) !std.ArrayList(u8) { return defines; } -pub fn flushModule(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { +pub fn flushZcu(self: *C, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { _ = arena; // Has the same lifetime as the call to Compilation.update. const tracy = trace(@src()); diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 5100406030..12a9dc9753 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -3,9 +3,6 @@ //! LLD for traditional linking (linking relocatable object files). //! LLD is also the default linker for LLVM. -/// If this is not null, an object file is created by LLVM and emitted to zcu_object_sub_path. -llvm_object: ?LlvmObject.Ptr = null, - base: link.File, image_base: u64, subsystem: ?std.Target.SubSystem, @@ -87,6 +84,16 @@ base_relocs: BaseRelocationTable = .{}, /// Hot-code swapping state. hot_state: if (is_hot_update_compatible) HotUpdateState else struct {} = .{}, +/// When linking with LLD, these flags are used to determine the subsystem to pass on the LLD command line. +lld_export_flags: struct { + c_main: bool = false, + winmain: bool = false, + wwinmain: bool = false, + winmain_crt_startup: bool = false, + wwinmain_crt_startup: bool = false, + dllmain_crt_startup: bool = false, +} = .{}, + const is_hot_update_compatible = switch (builtin.target.os.tag) { .windows => true, else => false, @@ -302,9 +309,6 @@ pub fn createEmpty( .pdb_out_path = options.pdb_out_path, .repro = options.repro, }; - if (use_llvm and comp.config.have_zcu) { - coff.llvm_object = try LlvmObject.create(arena, comp); - } errdefer coff.base.destroy(); if (use_lld and (use_llvm or !comp.config.have_zcu)) { @@ -322,7 +326,6 @@ pub fn createEmpty( .mode = link.File.determineMode(use_lld, output_mode, link_mode), }); - assert(coff.llvm_object == null); const gpa = comp.gpa; try coff.strtab.buffer.ensureUnusedCapacity(gpa, @sizeOf(u32)); @@ -428,8 +431,6 @@ pub fn open( pub fn deinit(coff: *Coff) void { const gpa = coff.base.comp.gpa; - if (coff.llvm_object) |llvm_object| llvm_object.deinit(); - for (coff.sections.items(.free_list)) |*free_list| { free_list.deinit(gpa); } @@ -1103,9 +1104,6 @@ pub fn updateFunc( if (build_options.skip_non_native and builtin.object_format != .coff) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (coff.llvm_object) |llvm_object| { - return llvm_object.updateFunc(pt, func_index, air, liveness); - } const tracy = trace(@src()); defer tracy.end(); @@ -1205,7 +1203,6 @@ pub fn updateNav( if (build_options.skip_non_native and builtin.object_format != .coff) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (coff.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav_index); const tracy = trace(@src()); defer tracy.end(); @@ -1330,7 +1327,7 @@ pub fn getOrCreateAtomForLazySymbol( } state_ptr.* = .pending_flush; const atom = atom_ptr.*; - // anyerror needs to be deferred until flushModule + // anyerror needs to be deferred until flushZcu if (lazy_sym.ty != .anyerror_type) try coff.updateLazySymbolAtom(pt, lazy_sym, atom, switch (lazy_sym.kind) { .code => coff.text_section_index.?, .const_data => coff.rdata_section_index.?, @@ -1463,8 +1460,6 @@ fn updateNavCode( } pub fn freeNav(coff: *Coff, nav_index: InternPool.NavIndex) void { - if (coff.llvm_object) |llvm_object| return llvm_object.freeNav(nav_index); - const gpa = coff.base.comp.gpa; if (coff.decls.fetchOrderedRemove(nav_index)) |const_kv| { @@ -1485,50 +1480,7 @@ pub fn updateExports( } const zcu = pt.zcu; - const ip = &zcu.intern_pool; - const comp = coff.base.comp; - const target = comp.root_mod.resolved_target.result; - - if (comp.config.use_llvm) { - // Even in the case of LLVM, we need to notice certain exported symbols in order to - // detect the default subsystem. - for (export_indices) |export_idx| { - const exp = export_idx.ptr(zcu); - const exported_nav_index = switch (exp.exported) { - .nav => |nav| nav, - .uav => continue, - }; - const exported_nav = ip.getNav(exported_nav_index); - const exported_ty = exported_nav.typeOf(ip); - if (!ip.isFunctionType(exported_ty)) continue; - const c_cc = target.cCallingConvention().?; - const winapi_cc: std.builtin.CallingConvention = switch (target.cpu.arch) { - .x86 => .{ .x86_stdcall = .{} }, - else => c_cc, - }; - const exported_cc = Type.fromInterned(exported_ty).fnCallingConvention(zcu); - const CcTag = std.builtin.CallingConvention.Tag; - if (@as(CcTag, exported_cc) == @as(CcTag, c_cc) and exp.opts.name.eqlSlice("main", ip) and comp.config.link_libc) { - zcu.stage1_flags.have_c_main = true; - } else if (@as(CcTag, exported_cc) == @as(CcTag, winapi_cc) and target.os.tag == .windows) { - if (exp.opts.name.eqlSlice("WinMain", ip)) { - zcu.stage1_flags.have_winmain = true; - } else if (exp.opts.name.eqlSlice("wWinMain", ip)) { - zcu.stage1_flags.have_wwinmain = true; - } else if (exp.opts.name.eqlSlice("WinMainCRTStartup", ip)) { - zcu.stage1_flags.have_winmain_crt_startup = true; - } else if (exp.opts.name.eqlSlice("wWinMainCRTStartup", ip)) { - zcu.stage1_flags.have_wwinmain_crt_startup = true; - } else if (exp.opts.name.eqlSlice("DllMainCRTStartup", ip)) { - zcu.stage1_flags.have_dllmain_crt_startup = true; - } - } - } - } - - if (coff.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices); - - const gpa = comp.gpa; + const gpa = zcu.gpa; const metadata = switch (exported) { .nav => |nav| blk: { @@ -1621,7 +1573,6 @@ pub fn deleteExport( exported: Zcu.Exported, name: InternPool.NullTerminatedString, ) void { - if (coff.llvm_object) |_| return; const metadata = switch (exported) { .nav => |nav| coff.navs.getPtr(nav), .uav => |uav| coff.uavs.getPtr(uav), @@ -1692,7 +1643,7 @@ pub fn flush(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: st }; } switch (comp.config.output_mode) { - .Exe, .Obj => return coff.flushModule(arena, tid, prog_node), + .Exe, .Obj => return coff.flushZcu(arena, tid, prog_node), .Lib => return diags.fail("writing lib files not yet implemented for COFF", .{}), } } @@ -1711,8 +1662,12 @@ fn linkWithLLD(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: // If there is no Zig code to compile, then we should skip flushing the output file because it // will not be part of the linker line anyway. - const module_obj_path: ?[]const u8 = if (comp.zcu != null) blk: { - try coff.flushModule(arena, tid, prog_node); + const module_obj_path: ?[]const u8 = if (comp.zcu) |zcu| blk: { + if (zcu.llvm_object == null) { + try coff.flushZcu(arena, tid, prog_node); + } else { + // `Compilation.flush` has already made LLVM emit this object file for us. + } if (fs.path.dirname(full_out_path)) |dirname| { 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: if (coff.subsystem) |explicit| break :blk explicit; switch (target.os.tag) { .windows => { - if (comp.zcu) |module| { - if (module.stage1_flags.have_dllmain_crt_startup or is_dyn_lib) + if (comp.zcu != null) { + if (coff.lld_export_flags.dllmain_crt_startup or is_dyn_lib) break :blk null; - if (module.stage1_flags.have_c_main or comp.config.is_test or - module.stage1_flags.have_winmain_crt_startup or - module.stage1_flags.have_wwinmain_crt_startup) + if (coff.lld_export_flags.c_main or comp.config.is_test or + coff.lld_export_flags.winmain_crt_startup or + coff.lld_export_flags.wwinmain_crt_startup) { break :blk .Console; } - if (module.stage1_flags.have_winmain or module.stage1_flags.have_wwinmain) + if (coff.lld_export_flags.winmain or coff.lld_export_flags.wwinmain) break :blk .Windows; } }, @@ -2136,8 +2091,8 @@ fn linkWithLLD(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: } else { try argv.append("-NODEFAULTLIB"); if (!is_lib and entry_name == null) { - if (comp.zcu) |module| { - if (module.stage1_flags.have_winmain_crt_startup) { + if (comp.zcu != null) { + if (coff.lld_export_flags.winmain_crt_startup) { try argv.append("-ENTRY:WinMainCRTStartup"); } else { try argv.append("-ENTRY:wWinMainCRTStartup"); @@ -2244,7 +2199,7 @@ fn findLib(arena: Allocator, name: []const u8, lib_directories: []const Director return null; } -pub fn flushModule( +pub fn flushZcu( coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, @@ -2256,22 +2211,17 @@ pub fn flushModule( const comp = coff.base.comp; const diags = &comp.link_diags; - if (coff.llvm_object) |llvm_object| { - try coff.base.emitLlvmObject(arena, llvm_object, prog_node); - return; - } - const sub_prog_node = prog_node.start("COFF Flush", 0); defer sub_prog_node.end(); - return flushModuleInner(coff, arena, tid) catch |err| switch (err) { + return flushZcuInner(coff, arena, tid) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.LinkFailure => return error.LinkFailure, else => |e| return diags.fail("COFF flush failed: {s}", .{@errorName(e)}), }; } -fn flushModuleInner(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id) !void { +fn flushZcuInner(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id) !void { _ = arena; const comp = coff.base.comp; @@ -2397,7 +2347,6 @@ pub fn getNavVAddr( nav_index: InternPool.Nav.Index, reloc_info: link.File.RelocInfo, ) !u64 { - assert(coff.llvm_object == null); const zcu = pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); @@ -2483,8 +2432,6 @@ pub fn getUavVAddr( uav: InternPool.Index, reloc_info: link.File.RelocInfo, ) !u64 { - assert(coff.llvm_object == null); - const this_atom_index = coff.uavs.get(uav).?.atom; const sym_index = coff.getAtom(this_atom_index).getSymbolIndex().?; const atom_index = coff.getAtomIndexForSymbol(.{ @@ -3798,7 +3745,6 @@ const trace = @import("../tracy.zig").trace; const Air = @import("../Air.zig"); const Compilation = @import("../Compilation.zig"); -const LlvmObject = @import("../codegen/llvm.zig").Object; const Zcu = @import("../Zcu.zig"); const InternPool = @import("../InternPool.zig"); const TableSection = @import("table_section.zig").TableSection; diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index e2b8229736..c0d1281df2 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -4391,7 +4391,7 @@ fn refAbbrevCode(dwarf: *Dwarf, abbrev_code: AbbrevCode) UpdateError!@typeInfo(A return @intFromEnum(abbrev_code); } -pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { +pub fn flushZcu(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void { const zcu = pt.zcu; const ip = &zcu.intern_pool; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 1516993c74..b18fc7ce33 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -32,9 +32,6 @@ entry_name: ?[]const u8, ptr_width: PtrWidth, -/// If this is not null, an object file is created by LLVM and emitted to zcu_object_sub_path. -llvm_object: ?LlvmObject.Ptr = null, - /// A list of all input files. /// First index is a special "null file". Order is otherwise not observed. files: std.MultiArrayList(File.Entry) = .{}, @@ -344,9 +341,6 @@ pub fn createEmpty( .print_map = options.print_map, .dump_argv_list = .empty, }; - if (use_llvm and comp.config.have_zcu) { - self.llvm_object = try LlvmObject.create(arena, comp); - } errdefer self.base.destroy(); if (use_lld and (use_llvm or !comp.config.have_zcu)) { @@ -457,8 +451,6 @@ pub fn open( pub fn deinit(self: *Elf) void { const gpa = self.base.comp.gpa; - if (self.llvm_object) |llvm_object| llvm_object.deinit(); - for (self.file_handles.items) |fh| { fh.close(); } @@ -515,7 +507,6 @@ pub fn deinit(self: *Elf) void { } pub fn getNavVAddr(self: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, reloc_info: link.File.RelocInfo) !u64 { - assert(self.llvm_object == null); return self.zigObjectPtr().?.getNavVAddr(self, pt, nav_index, reloc_info); } @@ -530,7 +521,6 @@ pub fn lowerUav( } pub fn getUavVAddr(self: *Elf, uav: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { - assert(self.llvm_object == null); return self.zigObjectPtr().?.getUavVAddr(self, uav, reloc_info); } @@ -805,35 +795,29 @@ pub fn flush(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std else => |e| return diags.fail("failed to link with LLD: {s}", .{@errorName(e)}), }; } - try self.flushModule(arena, tid, prog_node); + try self.flushZcu(arena, tid, prog_node); } -pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { +pub fn flushZcu(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { const tracy = trace(@src()); defer tracy.end(); const comp = self.base.comp; const diags = &comp.link_diags; - if (self.llvm_object) |llvm_object| { - try self.base.emitLlvmObject(arena, llvm_object, prog_node); - const use_lld = build_options.have_llvm and comp.config.use_lld; - if (use_lld) return; - } - if (comp.verbose_link) Compilation.dump_argv(self.dump_argv_list.items); const sub_prog_node = prog_node.start("ELF Flush", 0); defer sub_prog_node.end(); - return flushModuleInner(self, arena, tid) catch |err| switch (err) { + return flushZcuInner(self, arena, tid) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.LinkFailure => return error.LinkFailure, else => |e| return diags.fail("ELF flush failed: {s}", .{@errorName(e)}), }; } -fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void { +fn flushZcuInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void { const comp = self.base.comp; const gpa = comp.gpa; const diags = &comp.link_diags; @@ -1523,8 +1507,12 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s // If there is no Zig code to compile, then we should skip flushing the output file because it // will not be part of the linker line anyway. - const module_obj_path: ?[]const u8 = if (comp.zcu != null) blk: { - try self.flushModule(arena, tid, prog_node); + const module_obj_path: ?[]const u8 = if (comp.zcu) |zcu| blk: { + if (zcu.llvm_object == null) { + try self.flushZcu(arena, tid, prog_node); + } else { + // `Compilation.flush` has already made LLVM emit this object file for us. + } if (fs.path.dirname(full_out_path)) |dirname| { break :blk try fs.path.join(arena, &.{ dirname, self.base.zcu_object_sub_path.? }); @@ -2385,7 +2373,6 @@ pub fn writeElfHeader(self: *Elf) !void { } pub fn freeNav(self: *Elf, nav: InternPool.Nav.Index) void { - if (self.llvm_object) |llvm_object| return llvm_object.freeNav(nav); return self.zigObjectPtr().?.freeNav(self, nav); } @@ -2399,7 +2386,6 @@ pub fn updateFunc( if (build_options.skip_non_native and builtin.object_format != .elf) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(pt, func_index, air, liveness); return self.zigObjectPtr().?.updateFunc(self, pt, func_index, air, liveness); } @@ -2411,7 +2397,6 @@ pub fn updateNav( if (build_options.skip_non_native and builtin.object_format != .elf) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (self.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav); return self.zigObjectPtr().?.updateNav(self, pt, nav); } @@ -2423,7 +2408,6 @@ pub fn updateContainerType( if (build_options.skip_non_native and builtin.object_format != .elf) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (self.llvm_object) |_| return; const zcu = pt.zcu; const gpa = zcu.gpa; return self.zigObjectPtr().?.updateContainerType(pt, ty) catch |err| switch (err) { @@ -2449,12 +2433,10 @@ pub fn updateExports( if (build_options.skip_non_native and builtin.object_format != .elf) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (self.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices); return self.zigObjectPtr().?.updateExports(self, pt, exported, export_indices); } pub fn updateLineNumber(self: *Elf, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void { - if (self.llvm_object) |_| return; return self.zigObjectPtr().?.updateLineNumber(pt, ti_id); } @@ -2463,7 +2445,6 @@ pub fn deleteExport( exported: Zcu.Exported, name: InternPool.NullTerminatedString, ) void { - if (self.llvm_object) |_| return; return self.zigObjectPtr().?.deleteExport(self, exported, name); } @@ -5332,7 +5313,6 @@ const GotSection = synthetic_sections.GotSection; const GotPltSection = synthetic_sections.GotPltSection; const HashSection = synthetic_sections.HashSection; const LinkerDefined = @import("Elf/LinkerDefined.zig"); -const LlvmObject = @import("../codegen/llvm.zig").Object; const Zcu = @import("../Zcu.zig"); const Object = @import("Elf/Object.zig"); const InternPool = @import("../InternPool.zig"); diff --git a/src/link/Elf/ZigObject.zig b/src/link/Elf/ZigObject.zig index 13816940fe..49921089f7 100644 --- a/src/link/Elf/ZigObject.zig +++ b/src/link/Elf/ZigObject.zig @@ -310,7 +310,7 @@ pub fn flush(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void { if (self.dwarf) |*dwarf| { const pt: Zcu.PerThread = .activate(elf_file.base.comp.zcu.?, tid); defer pt.deactivate(); - try dwarf.flushModule(pt); + try dwarf.flushZcu(pt); const gpa = elf_file.base.comp.gpa; 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 { self.debug_str_section_dirty = false; } - // The point of flushModule() is to commit changes, so in theory, nothing should + // The point of flushZcu() is to commit changes, so in theory, nothing should // be dirty after this. However, it is possible for some things to remain // dirty because they fail to be written in the event of compile errors, // 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 { if (shdr.sh_type == elf.SHT_NOBITS) continue; if (atom_ptr.scanRelocsRequiresCode(elf_file)) { // TODO ideally we don't have to fetch the code here. - // Perhaps it would make sense to save the code until flushModule where we + // Perhaps it would make sense to save the code until flushZcu where we // would free all of generated code? const code = try self.codeAlloc(elf_file, atom_index); defer gpa.free(code); @@ -1075,7 +1075,7 @@ pub fn getOrCreateMetadataForLazySymbol( } state_ptr.* = .pending_flush; const symbol_index = symbol_index_ptr.*; - // anyerror needs to be deferred until flushModule + // anyerror needs to be deferred until flushZcu if (lazy_sym.ty != .anyerror_type) try self.updateLazySymbol(elf_file, pt, lazy_sym, symbol_index); return symbol_index; } diff --git a/src/link/Goff.zig b/src/link/Goff.zig index 6ed360be25..35821289cd 100644 --- a/src/link/Goff.zig +++ b/src/link/Goff.zig @@ -17,10 +17,8 @@ const link = @import("../link.zig"); const trace = @import("../tracy.zig").trace; const build_options = @import("build_options"); const Air = @import("../Air.zig"); -const LlvmObject = @import("../codegen/llvm.zig").Object; base: link.File, -llvm_object: LlvmObject.Ptr, pub fn createEmpty( arena: Allocator, @@ -36,7 +34,6 @@ pub fn createEmpty( assert(!use_lld); // Caught by Compilation.Config.resolve. assert(target.os.tag == .zos); // Caught by Compilation.Config.resolve. - const llvm_object = try LlvmObject.create(arena, comp); const goff = try arena.create(Goff); goff.* = .{ .base = .{ @@ -52,7 +49,6 @@ pub fn createEmpty( .disable_lld_caching = options.disable_lld_caching, .build_id = options.build_id, }, - .llvm_object = llvm_object, }; return goff; @@ -70,7 +66,7 @@ pub fn open( } pub fn deinit(self: *Goff) void { - self.llvm_object.deinit(); + _ = self; } pub fn updateFunc( @@ -80,17 +76,19 @@ pub fn updateFunc( air: Air, liveness: Air.Liveness, ) link.File.UpdateNavError!void { - if (build_options.skip_non_native and builtin.object_format != .goff) - @panic("Attempted to compile for object format that was disabled by build configuration"); - - try self.llvm_object.updateFunc(pt, func_index, air, liveness); + _ = self; + _ = pt; + _ = func_index; + _ = air; + _ = liveness; + unreachable; // we always use llvm } pub fn updateNav(self: *Goff, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.File.UpdateNavError!void { - if (build_options.skip_non_native and builtin.object_format != .goff) - @panic("Attempted to compile for object format that was disabled by build configuration"); - - return self.llvm_object.updateNav(pt, nav); + _ = self; + _ = pt; + _ = nav; + unreachable; // we always use llvm } pub fn updateExports( @@ -99,21 +97,21 @@ pub fn updateExports( exported: Zcu.Exported, export_indices: []const Zcu.Export.Index, ) !void { - if (build_options.skip_non_native and builtin.object_format != .goff) - @panic("Attempted to compile for object format that was disabled by build configuration"); - - return self.llvm_object.updateExports(pt, exported, export_indices); + _ = self; + _ = pt; + _ = exported; + _ = export_indices; + unreachable; // we always use llvm } pub fn flush(self: *Goff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { - return self.flushModule(arena, tid, prog_node); + return self.flushZcu(arena, tid, prog_node); } -pub fn flushModule(self: *Goff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { - if (build_options.skip_non_native and builtin.object_format != .goff) - @panic("Attempted to compile for object format that was disabled by build configuration"); - +pub fn flushZcu(self: *Goff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { + _ = self; + _ = arena; _ = tid; - - try self.base.emitLlvmObject(arena, self.llvm_object, prog_node); + _ = prog_node; + unreachable; // we always use llvm } diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 3ddc12a5b0..6667ed6a63 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -6,9 +6,6 @@ base: link.File, rpath_list: []const []const u8, -/// If this is not null, an object file is created by LLVM and emitted to zcu_object_sub_path. -llvm_object: ?LlvmObject.Ptr = null, - /// Debug symbols bundle (or dSym). d_sym: ?DebugSymbols = null, @@ -225,9 +222,6 @@ pub fn createEmpty( .force_load_objc = options.force_load_objc, .discard_local_symbols = options.discard_local_symbols, }; - if (use_llvm and comp.config.have_zcu) { - self.llvm_object = try LlvmObject.create(arena, comp); - } errdefer self.base.destroy(); self.base.file = try emit.root_dir.handle.createFile(emit.sub_path, .{ @@ -280,8 +274,6 @@ pub fn open( pub fn deinit(self: *MachO) void { const gpa = self.base.comp.gpa; - if (self.llvm_object) |llvm_object| llvm_object.deinit(); - if (self.d_sym) |*d_sym| { d_sym.deinit(); } @@ -350,10 +342,10 @@ pub fn flush( tid: Zcu.PerThread.Id, prog_node: std.Progress.Node, ) link.File.FlushError!void { - try self.flushModule(arena, tid, prog_node); + try self.flushZcu(arena, tid, prog_node); } -pub fn flushModule( +pub fn flushZcu( self: *MachO, arena: Allocator, tid: Zcu.PerThread.Id, @@ -366,10 +358,6 @@ pub fn flushModule( const gpa = comp.gpa; const diags = &self.base.comp.link_diags; - if (self.llvm_object) |llvm_object| { - try self.base.emitLlvmObject(arena, llvm_object, prog_node); - } - const sub_prog_node = prog_node.start("MachO Flush", 0); defer sub_prog_node.end(); @@ -385,7 +373,7 @@ pub fn flushModule( // --verbose-link if (comp.verbose_link) try self.dumpArgv(comp); - if (self.getZigObject()) |zo| try zo.flushModule(self, tid); + if (self.getZigObject()) |zo| try zo.flushZcu(self, tid); if (self.base.isStaticLib()) return relocatable.flushStaticLib(self, comp, module_obj_path); if (self.base.isObject()) return relocatable.flushObject(self, comp, module_obj_path); @@ -629,7 +617,7 @@ pub fn flushModule( error.LinkFailure => return error.LinkFailure, else => |e| return diags.fail("failed to calculate and write uuid: {s}", .{@errorName(e)}), }; - if (self.getDebugSymbols()) |dsym| dsym.flushModule(self) catch |err| switch (err) { + if (self.getDebugSymbols()) |dsym| dsym.flushZcu(self) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, else => |e| return diags.fail("failed to get debug symbols: {s}", .{@errorName(e)}), }; @@ -3079,7 +3067,6 @@ pub fn updateFunc( if (build_options.skip_non_native and builtin.object_format != .macho) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(pt, func_index, air, liveness); return self.getZigObject().?.updateFunc(self, pt, func_index, air, liveness); } @@ -3087,12 +3074,10 @@ pub fn updateNav(self: *MachO, pt: Zcu.PerThread, nav: InternPool.Nav.Index) lin if (build_options.skip_non_native and builtin.object_format != .macho) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (self.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav); return self.getZigObject().?.updateNav(self, pt, nav); } pub fn updateLineNumber(self: *MachO, pt: Zcu.PerThread, ti_id: InternPool.TrackedInst.Index) !void { - if (self.llvm_object) |_| return; return self.getZigObject().?.updateLineNumber(pt, ti_id); } @@ -3105,7 +3090,6 @@ pub fn updateExports( if (build_options.skip_non_native and builtin.object_format != .macho) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (self.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices); return self.getZigObject().?.updateExports(self, pt, exported, export_indices); } @@ -3114,17 +3098,14 @@ pub fn deleteExport( exported: Zcu.Exported, name: InternPool.NullTerminatedString, ) void { - if (self.llvm_object) |_| return; return self.getZigObject().?.deleteExport(self, exported, name); } pub fn freeNav(self: *MachO, nav: InternPool.Nav.Index) void { - if (self.llvm_object) |llvm_object| return llvm_object.freeNav(nav); return self.getZigObject().?.freeNav(nav); } pub fn getNavVAddr(self: *MachO, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index, reloc_info: link.File.RelocInfo) !u64 { - assert(self.llvm_object == null); return self.getZigObject().?.getNavVAddr(self, pt, nav_index, reloc_info); } @@ -3139,7 +3120,6 @@ pub fn lowerUav( } pub fn getUavVAddr(self: *MachO, uav: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { - assert(self.llvm_object == null); return self.getZigObject().?.getUavVAddr(self, uav, reloc_info); } @@ -5496,7 +5476,6 @@ const ObjcStubsSection = synthetic.ObjcStubsSection; const Object = @import("MachO/Object.zig"); const LazyBind = bind.LazyBind; const LaSymbolPtrSection = synthetic.LaSymbolPtrSection; -const LlvmObject = @import("../codegen/llvm.zig").Object; const Md5 = std.crypto.hash.Md5; const Zcu = @import("../Zcu.zig"); const InternPool = @import("../InternPool.zig"); diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig index 04b2fe92b0..8579863d03 100644 --- a/src/link/MachO/DebugSymbols.zig +++ b/src/link/MachO/DebugSymbols.zig @@ -178,7 +178,7 @@ fn findFreeSpace(self: *DebugSymbols, object_size: u64, min_alignment: u64) !u64 return offset; } -pub fn flushModule(self: *DebugSymbols, macho_file: *MachO) !void { +pub fn flushZcu(self: *DebugSymbols, macho_file: *MachO) !void { const zo = macho_file.getZigObject().?; for (self.relocs.items) |*reloc| { const sym = zo.symbols.items[reloc.target]; diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index a0de866544..4d99afc61a 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -550,7 +550,7 @@ pub fn getInputSection(self: ZigObject, atom: Atom, macho_file: *MachO) macho.se return sect; } -pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id) link.File.FlushError!void { +pub fn flushZcu(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id) link.File.FlushError!void { const diags = &macho_file.base.comp.link_diags; // 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) if (self.dwarf) |*dwarf| { const pt: Zcu.PerThread = .activate(macho_file.base.comp.zcu.?, tid); defer pt.deactivate(); - dwarf.flushModule(pt) catch |err| switch (err) { + dwarf.flushZcu(pt) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, else => |e| return diags.fail("failed to flush dwarf module: {s}", .{@errorName(e)}), }; @@ -599,7 +599,7 @@ pub fn flushModule(self: *ZigObject, macho_file: *MachO, tid: Zcu.PerThread.Id) self.debug_strtab_dirty = false; } - // The point of flushModule() is to commit changes, so in theory, nothing should + // The point of flushZcu() is to commit changes, so in theory, nothing should // be dirty after this. However, it is possible for some things to remain // dirty because they fail to be written in the event of compile errors, // such as debug_line_header_dirty and debug_info_header_dirty. @@ -1537,7 +1537,7 @@ pub fn getOrCreateMetadataForLazySymbol( } state_ptr.* = .pending_flush; const symbol_index = symbol_index_ptr.*; - // anyerror needs to be deferred until flushModule + // anyerror needs to be deferred until flushZcu if (lazy_sym.ty != .anyerror_type) try self.updateLazySymbol(macho_file, pt, lazy_sym, symbol_index); return symbol_index; } diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 5cbb9287d7..0a940cb0b3 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -494,7 +494,7 @@ fn updateFinish(self: *Plan9, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index // write the symbol // we already have the got index const sym: aout.Sym = .{ - .value = undefined, // the value of stuff gets filled in in flushModule + .value = undefined, // the value of stuff gets filled in in flushZcu .type = atom.type, .name = try gpa.dupe(u8, nav.name.toSlice(ip)), }; @@ -543,7 +543,7 @@ pub fn flush( .Obj => return diags.fail("writing plan9 object files unimplemented", .{}), .Lib => return diags.fail("writing plan9 lib files unimplemented", .{}), } - return self.flushModule(arena, tid, prog_node); + return self.flushZcu(arena, tid, prog_node); } pub fn changeLine(l: *std.ArrayList(u8), delta_line: i32) !void { @@ -586,7 +586,7 @@ fn atomCount(self: *Plan9) usize { return data_nav_count + fn_nav_count + lazy_atom_count + extern_atom_count + uav_atom_count; } -pub fn flushModule( +pub fn flushZcu( self: *Plan9, arena: Allocator, /// TODO: stop using this @@ -610,7 +610,7 @@ pub fn flushModule( const sub_prog_node = prog_node.start("Flush Module", 0); defer sub_prog_node.end(); - log.debug("flushModule", .{}); + log.debug("flushZcu", .{}); defer assert(self.hdr.entry != 0x0); @@ -1039,7 +1039,7 @@ pub fn getOrCreateAtomForLazySymbol(self: *Plan9, pt: Zcu.PerThread, lazy_sym: F const atom = atom_ptr.*; _ = try self.getAtomPtr(atom).getOrCreateSymbolTableEntry(self); _ = self.getAtomPtr(atom).getOrCreateOffsetTableEntry(self); - // anyerror needs to be deferred until flushModule + // anyerror needs to be deferred until flushZcu if (lazy_sym.ty != .anyerror_type) try self.updateLazySymbolAtom(pt, lazy_sym, atom); return atom; } diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index a49771c3e2..c6e86895f5 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -17,7 +17,7 @@ //! All regular functions. // Because SPIR-V requires re-compilation anyway, and so hot swapping will not work -// anyway, we simply generate all the code in flushModule. This keeps +// anyway, we simply generate all the code in flushZcu. This keeps // things considerably simpler. const SpirV = @This(); @@ -194,17 +194,17 @@ pub fn updateExports( } pub fn flush(self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { - return self.flushModule(arena, tid, prog_node); + return self.flushZcu(arena, tid, prog_node); } -pub fn flushModule( +pub fn flushZcu( self: *SpirV, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node, ) link.File.FlushError!void { // The goal is to never use this because it's only needed if we need to - // write to InternPool, but flushModule is too late to be writing to the + // write to InternPool, but flushZcu is too late to be writing to the // InternPool. _ = tid; diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 69684724a5..e92be32b7d 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -36,7 +36,6 @@ const abi = @import("../arch/wasm/abi.zig"); const Compilation = @import("../Compilation.zig"); const Dwarf = @import("Dwarf.zig"); const InternPool = @import("../InternPool.zig"); -const LlvmObject = @import("../codegen/llvm.zig").Object; const Zcu = @import("../Zcu.zig"); const codegen = @import("../codegen.zig"); const dev = @import("../dev.zig"); @@ -81,8 +80,6 @@ import_table: bool, export_table: bool, /// Output name of the file name: []const u8, -/// If this is not null, an object file is created by LLVM and linked with LLD afterwards. -llvm_object: ?LlvmObject.Ptr = null, /// List of relocatable files to be linked into the final binary. objects: std.ArrayListUnmanaged(Object) = .{}, @@ -2992,9 +2989,6 @@ pub fn createEmpty( .object_host_name = .none, .preloaded_strings = undefined, }; - if (use_llvm and comp.config.have_zcu) { - wasm.llvm_object = try LlvmObject.create(arena, comp); - } errdefer wasm.base.destroy(); 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 { pub fn deinit(wasm: *Wasm) void { const gpa = wasm.base.comp.gpa; - if (wasm.llvm_object) |llvm_object| llvm_object.deinit(); wasm.navs_exe.deinit(gpa); wasm.navs_obj.deinit(gpa); @@ -3196,7 +3189,6 @@ pub fn updateFunc(wasm: *Wasm, pt: Zcu.PerThread, func_index: InternPool.Index, if (build_options.skip_non_native and builtin.object_format != .wasm) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (wasm.llvm_object) |llvm_object| return llvm_object.updateFunc(pt, func_index, air, liveness); dev.check(.wasm_backend); @@ -3228,7 +3220,6 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index if (build_options.skip_non_native and builtin.object_format != .wasm) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (wasm.llvm_object) |llvm_object| return llvm_object.updateNav(pt, nav_index); const zcu = pt.zcu; const ip = &zcu.intern_pool; const nav = ip.getNav(nav_index); @@ -3308,8 +3299,6 @@ pub fn deleteExport( exported: Zcu.Exported, name: InternPool.NullTerminatedString, ) void { - if (wasm.llvm_object != null) return; - const zcu = wasm.base.comp.zcu.?; const ip = &zcu.intern_pool; const name_slice = name.toSlice(ip); @@ -3332,7 +3321,6 @@ pub fn updateExports( if (build_options.skip_non_native and builtin.object_format != .wasm) { @panic("Attempted to compile for object format that was disabled by build configuration"); } - if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(pt, exported, export_indices); const zcu = pt.zcu; const gpa = zcu.gpa; @@ -3391,7 +3379,7 @@ pub fn flush(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: st else => |e| return diags.fail("failed to link with LLD: {s}", .{@errorName(e)}), }; } - return wasm.flushModule(arena, tid, prog_node); + return wasm.flushZcu(arena, tid, prog_node); } pub 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 { try wasm.tables.put(wasm.base.comp.gpa, .fromObjectTable(i), {}); } -pub fn flushModule( +pub fn flushZcu( wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node, ) link.File.FlushError!void { // The goal is to never use this because it's only needed if we need to - // write to InternPool, but flushModule is too late to be writing to the + // write to InternPool, but flushZcu is too late to be writing to the // InternPool. _ = tid; const comp = wasm.base.comp; - const use_lld = build_options.have_llvm and comp.config.use_lld; const diags = &comp.link_diags; const gpa = comp.gpa; - if (wasm.llvm_object) |llvm_object| { - try wasm.base.emitLlvmObject(arena, llvm_object, prog_node); - if (use_lld) return; - } - if (comp.verbose_link) Compilation.dump_argv(wasm.dump_argv_list.items); if (wasm.base.zcu_object_sub_path) |path| { @@ -3870,8 +3852,12 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: // If there is no Zig code to compile, then we should skip flushing the output file because it // will not be part of the linker line anyway. - const module_obj_path: ?[]const u8 = if (comp.zcu != null) blk: { - try wasm.flushModule(arena, tid, prog_node); + const module_obj_path: ?[]const u8 = if (comp.zcu) |zcu| blk: { + if (zcu.llvm_object == null) { + try wasm.flushZcu(arena, tid, prog_node); + } else { + // `Compilation.flush` has already made LLVM emit this object file for us. + } if (fs.path.dirname(full_out_path)) |dirname| { break :blk try fs.path.join(arena, &.{ dirname, wasm.base.zcu_object_sub_path.? }); diff --git a/src/link/Xcoff.zig b/src/link/Xcoff.zig index 525d99d391..e2f81e015e 100644 --- a/src/link/Xcoff.zig +++ b/src/link/Xcoff.zig @@ -17,10 +17,8 @@ const link = @import("../link.zig"); const trace = @import("../tracy.zig").trace; const build_options = @import("build_options"); const Air = @import("../Air.zig"); -const LlvmObject = @import("../codegen/llvm.zig").Object; base: link.File, -llvm_object: LlvmObject.Ptr, pub fn createEmpty( arena: Allocator, @@ -36,7 +34,6 @@ pub fn createEmpty( assert(!use_lld); // Caught by Compilation.Config.resolve. assert(target.os.tag == .aix); // Caught by Compilation.Config.resolve. - const llvm_object = try LlvmObject.create(arena, comp); const xcoff = try arena.create(Xcoff); xcoff.* = .{ .base = .{ @@ -52,7 +49,6 @@ pub fn createEmpty( .disable_lld_caching = options.disable_lld_caching, .build_id = options.build_id, }, - .llvm_object = llvm_object, }; return xcoff; @@ -70,7 +66,7 @@ pub fn open( } pub fn deinit(self: *Xcoff) void { - self.llvm_object.deinit(); + _ = self; } pub fn updateFunc( @@ -80,17 +76,19 @@ pub fn updateFunc( air: Air, liveness: Air.Liveness, ) link.File.UpdateNavError!void { - if (build_options.skip_non_native and builtin.object_format != .xcoff) - @panic("Attempted to compile for object format that was disabled by build configuration"); - - try self.llvm_object.updateFunc(pt, func_index, air, liveness); + _ = self; + _ = pt; + _ = func_index; + _ = air; + _ = liveness; + unreachable; // we always use llvm } pub fn updateNav(self: *Xcoff, pt: Zcu.PerThread, nav: InternPool.Nav.Index) link.File.UpdateNavError!void { - if (build_options.skip_non_native and builtin.object_format != .xcoff) - @panic("Attempted to compile for object format that was disabled by build configuration"); - - return self.llvm_object.updateNav(pt, nav); + _ = self; + _ = pt; + _ = nav; + unreachable; // we always use llvm } pub fn updateExports( @@ -99,21 +97,21 @@ pub fn updateExports( exported: Zcu.Exported, export_indices: []const Zcu.Export.Index, ) !void { - if (build_options.skip_non_native and builtin.object_format != .xcoff) - @panic("Attempted to compile for object format that was disabled by build configuration"); - - return self.llvm_object.updateExports(pt, exported, export_indices); + _ = self; + _ = pt; + _ = exported; + _ = export_indices; + unreachable; // we always use llvm } pub fn flush(self: *Xcoff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { - return self.flushModule(arena, tid, prog_node); + return self.flushZcu(arena, tid, prog_node); } -pub fn flushModule(self: *Xcoff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { - if (build_options.skip_non_native and builtin.object_format != .xcoff) - @panic("Attempted to compile for object format that was disabled by build configuration"); - +pub fn flushZcu(self: *Xcoff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: std.Progress.Node) link.File.FlushError!void { + _ = self; + _ = arena; _ = tid; - - try self.base.emitLlvmObject(arena, self.llvm_object, prog_node); + _ = prog_node; + unreachable; // we always use llvm } diff --git a/src/target.zig b/src/target.zig index 247b783439..6172b5e7e9 100644 --- a/src/target.zig +++ b/src/target.zig @@ -739,7 +739,7 @@ pub fn functionPointerMask(target: std.Target) ?u64 { pub fn supportsTailCall(target: std.Target, backend: std.builtin.CompilerBackend) bool { switch (backend) { - .stage1, .stage2_llvm => return @import("codegen/llvm.zig").supportsTailCall(target), + .stage2_llvm => return @import("codegen/llvm.zig").supportsTailCall(target), .stage2_c => return true, else => return false, }