diff --git a/src/Compilation.zig b/src/Compilation.zig index 7ff5801e46..e086e23830 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -39,6 +39,7 @@ const Zir = @import("Zir.zig"); const Autodoc = @import("Autodoc.zig"); const resinator = @import("resinator.zig"); const Builtin = @import("Builtin.zig"); +const LlvmObject = @import("codegen/llvm.zig").Object; pub const Config = @import("Compilation/Config.zig"); @@ -1434,6 +1435,7 @@ pub fn create(gpa: Allocator, options: CreateOptions) !*Compilation { .emit_h = emit_h, .tmp_hack_arena = std.heap.ArenaAllocator.init(gpa), .error_limit = error_limit, + .llvm_object = null, }; try zcu.init(); break :blk zcu; @@ -1683,6 +1685,17 @@ pub fn create(gpa: Allocator, options: CreateOptions) !*Compilation { }, } + // 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 (build_options.only_c) unreachable; + if (opt_zcu) |zcu| zcu.llvm_object = try LlvmObject.create(arena, comp); + } + comp.arena = arena_allocator; break :comp comp; }; @@ -2016,6 +2029,12 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void const tracy_trace = trace(@src()); defer tracy_trace.end(); + // This arena is scoped to this one update. + const gpa = comp.gpa; + var arena_allocator = std.heap.ArenaAllocator.init(gpa); + defer arena_allocator.deinit(); + const arena = arena_allocator.allocator(); + comp.clearMiscFailures(); comp.last_update_was_cache_hit = false; @@ -2034,7 +2053,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void man = comp.cache_parent.obtain(); whole.cache_manifest = &man; - try comp.addNonIncrementalStuffToCacheManifest(&man); + try addNonIncrementalStuffToCacheManifest(comp, arena, &man); const is_hit = man.hit() catch |err| { const i = man.failed_file_index orelse return err; @@ -2065,8 +2084,8 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void tmp_dir_rand_int = std.crypto.random.int(u64); const tmp_dir_sub_path = "tmp" ++ s ++ Package.Manifest.hex64(tmp_dir_rand_int); - const path = try comp.local_cache_directory.join(comp.gpa, &.{tmp_dir_sub_path}); - errdefer comp.gpa.free(path); + const path = try comp.local_cache_directory.join(gpa, &.{tmp_dir_sub_path}); + errdefer gpa.free(path); const handle = try comp.local_cache_directory.handle.makeOpenPath(tmp_dir_sub_path, .{}); errdefer handle.close(); @@ -2100,10 +2119,6 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void .directory = tmp_artifact_directory, .sub_path = std.fs.path.basename(sub_path), }; - // It's a bit strange to use the Compilation arena allocator here - // but in practice it won't leak much and usually whole cache mode - // will be combined with exactly one call to update(). - const arena = comp.arena.allocator(); comp.bin_file = try link.File.createEmpty(arena, comp, emit, whole.lf_open_opts); } }, @@ -2127,7 +2142,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void } if (comp.module) |module| { - module.compile_log_text.shrinkAndFree(module.gpa, 0); + module.compile_log_text.shrinkAndFree(gpa, 0); module.generation += 1; // Make sure std.zig is inside the import_table. We unconditionally need @@ -2189,7 +2204,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void comp.root_name, @as(usize, @intFromPtr(module)), }); - module.intern_pool.dumpGenericInstances(comp.gpa); + module.intern_pool.dumpGenericInstances(gpa); } if (comp.config.is_test and comp.totalErrorCount() == 0) { @@ -2222,8 +2237,23 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void }; } - if (comp.module) |module| { - try link.File.C.flushEmitH(module); + if (comp.module) |zcu| { + try link.File.C.flushEmitH(zcu); + + if (zcu.llvm_object) |llvm_object| { + if (build_options.only_c) unreachable; + const default_emit = switch (comp.cache_use) { + .whole => |whole| .{ + .directory = whole.tmp_artifact_directory.?, + .sub_path = "dummy", + }, + .incremental => |incremental| .{ + .directory = incremental.artifact_directory, + .sub_path = "dummy", + }, + }; + try emitLlvmObject(comp, arena, default_emit, null, llvm_object, main_progress_node); + } } } @@ -2238,7 +2268,7 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void // Close tmp dir and link.File to avoid open handle during rename. if (whole.tmp_artifact_directory) |*tmp_directory| { tmp_directory.handle.close(); - if (tmp_directory.path) |p| comp.gpa.free(p); + if (tmp_directory.path) |p| gpa.free(p); whole.tmp_artifact_directory = null; } else unreachable; @@ -2389,13 +2419,13 @@ fn prepareWholeEmitSubPath(arena: Allocator, opt_emit: ?EmitLoc) error{OutOfMemo /// anything from the link cache manifest. pub const link_hash_implementation_version = 10; -fn addNonIncrementalStuffToCacheManifest(comp: *Compilation, man: *Cache.Manifest) !void { +fn addNonIncrementalStuffToCacheManifest( + comp: *Compilation, + arena: Allocator, + man: *Cache.Manifest, +) !void { const gpa = comp.gpa; - var arena_allocator = std.heap.ArenaAllocator.init(gpa); - defer arena_allocator.deinit(); - const arena = arena_allocator.allocator(); - comptime assert(link_hash_implementation_version == 10); if (comp.module) |mod| { @@ -2568,6 +2598,50 @@ fn emitOthers(comp: *Compilation) void { } } +pub fn emitLlvmObject( + comp: *Compilation, + arena: Allocator, + default_emit: Emit, + bin_emit_loc: ?EmitLoc, + llvm_object: *LlvmObject, + prog_node: *std.Progress.Node, +) !void { + if (build_options.only_c) @compileError("unreachable"); + + var sub_prog_node = prog_node.start("LLVM Emit Object", 0); + sub_prog_node.activate(); + sub_prog_node.context.refresh(); + 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_emit, bin_emit_loc), + .asm_path = try resolveEmitLoc(arena, default_emit, comp.emit_asm), + .post_ir_path = try resolveEmitLoc(arena, default_emit, comp.emit_llvm_ir), + .post_bc_path = try resolveEmitLoc(arena, default_emit, 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, + .lto = comp.config.lto, + }); +} + +fn resolveEmitLoc( + arena: Allocator, + default_emit: Emit, + opt_loc: ?EmitLoc, +) Allocator.Error!?[*:0]const u8 { + const loc = opt_loc orelse return null; + const slice = if (loc.directory) |directory| + try directory.joinZ(arena, &.{loc.basename}) + else + try default_emit.basenamePath(arena, loc.basename); + return slice.ptr; +} + fn reportMultiModuleErrors(mod: *Module) !void { // Some cases can give you a whole bunch of multi-module errors, which it's not helpful to // print all of, so we'll cap the number of these to emit. diff --git a/src/Module.zig b/src/Module.zig index 9d5f4a69d2..558c03d685 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -37,6 +37,7 @@ const clang = @import("clang.zig"); const InternPool = @import("InternPool.zig"); const Alignment = InternPool.Alignment; const BuiltinFn = std.zig.BuiltinFn; +const LlvmObject = @import("codegen/llvm.zig").Object; comptime { @setEvalBranchQuota(4000); @@ -53,6 +54,10 @@ 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. +llvm_object: ?*LlvmObject, /// Pointer to externally managed resource. root_mod: *Package.Module, @@ -2476,36 +2481,41 @@ pub fn init(mod: *Module) !void { try mod.global_error_set.put(gpa, .empty, {}); } -pub fn deinit(mod: *Module) void { - const gpa = mod.gpa; +pub fn deinit(zcu: *Zcu) void { + const gpa = zcu.gpa; - for (mod.import_table.keys()) |key| { + if (zcu.llvm_object) |llvm_object| { + if (build_options.only_c) unreachable; + llvm_object.deinit(); + } + + for (zcu.import_table.keys()) |key| { gpa.free(key); } - var failed_decls = mod.failed_decls; - mod.failed_decls = .{}; - for (mod.import_table.values()) |value| { - value.destroy(mod); + var failed_decls = zcu.failed_decls; + zcu.failed_decls = .{}; + for (zcu.import_table.values()) |value| { + value.destroy(zcu); } - mod.import_table.deinit(gpa); + zcu.import_table.deinit(gpa); - for (mod.embed_table.keys(), mod.embed_table.values()) |path, embed_file| { + for (zcu.embed_table.keys(), zcu.embed_table.values()) |path, embed_file| { gpa.free(path); gpa.destroy(embed_file); } - mod.embed_table.deinit(gpa); + zcu.embed_table.deinit(gpa); - mod.compile_log_text.deinit(gpa); + zcu.compile_log_text.deinit(gpa); - mod.local_zir_cache.handle.close(); - mod.global_zir_cache.handle.close(); + zcu.local_zir_cache.handle.close(); + zcu.global_zir_cache.handle.close(); for (failed_decls.values()) |value| { value.destroy(gpa); } failed_decls.deinit(gpa); - if (mod.emit_h) |emit_h| { + if (zcu.emit_h) |emit_h| { for (emit_h.failed_decls.values()) |value| { value.destroy(gpa); } @@ -2514,68 +2524,68 @@ pub fn deinit(mod: *Module) void { emit_h.allocated_emit_h.deinit(gpa); } - for (mod.failed_files.values()) |value| { + for (zcu.failed_files.values()) |value| { if (value) |msg| msg.destroy(gpa); } - mod.failed_files.deinit(gpa); + zcu.failed_files.deinit(gpa); - for (mod.failed_embed_files.values()) |msg| { + for (zcu.failed_embed_files.values()) |msg| { msg.destroy(gpa); } - mod.failed_embed_files.deinit(gpa); + zcu.failed_embed_files.deinit(gpa); - for (mod.failed_exports.values()) |value| { + for (zcu.failed_exports.values()) |value| { value.destroy(gpa); } - mod.failed_exports.deinit(gpa); + zcu.failed_exports.deinit(gpa); - for (mod.cimport_errors.values()) |*errs| { + for (zcu.cimport_errors.values()) |*errs| { errs.deinit(gpa); } - mod.cimport_errors.deinit(gpa); + zcu.cimport_errors.deinit(gpa); - mod.compile_log_decls.deinit(gpa); + zcu.compile_log_decls.deinit(gpa); - for (mod.decl_exports.values()) |*export_list| { + for (zcu.decl_exports.values()) |*export_list| { export_list.deinit(gpa); } - mod.decl_exports.deinit(gpa); + zcu.decl_exports.deinit(gpa); - for (mod.value_exports.values()) |*export_list| { + for (zcu.value_exports.values()) |*export_list| { export_list.deinit(gpa); } - mod.value_exports.deinit(gpa); + zcu.value_exports.deinit(gpa); - for (mod.export_owners.values()) |*value| { + for (zcu.export_owners.values()) |*value| { freeExportList(gpa, value); } - mod.export_owners.deinit(gpa); + zcu.export_owners.deinit(gpa); - mod.global_error_set.deinit(gpa); + zcu.global_error_set.deinit(gpa); - mod.test_functions.deinit(gpa); + zcu.test_functions.deinit(gpa); - for (mod.global_assembly.values()) |s| { + for (zcu.global_assembly.values()) |s| { gpa.free(s); } - mod.global_assembly.deinit(gpa); + zcu.global_assembly.deinit(gpa); - mod.reference_table.deinit(gpa); + zcu.reference_table.deinit(gpa); { - var it = mod.intern_pool.allocated_namespaces.iterator(0); + var it = zcu.intern_pool.allocated_namespaces.iterator(0); while (it.next()) |namespace| { namespace.decls.deinit(gpa); namespace.usingnamespace_set.deinit(gpa); } } - mod.intern_pool.deinit(gpa); - mod.tmp_hack_arena.deinit(); + zcu.intern_pool.deinit(gpa); + zcu.tmp_hack_arena.deinit(); - mod.capture_scope_parents.deinit(gpa); - mod.runtime_capture_scopes.deinit(gpa); - mod.comptime_capture_scopes.deinit(gpa); + zcu.capture_scope_parents.deinit(gpa); + zcu.runtime_capture_scopes.deinit(gpa); + zcu.comptime_capture_scopes.deinit(gpa); } pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void { @@ -3222,14 +3232,14 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { } } -pub fn ensureFuncBodyAnalyzed(mod: *Module, func_index: InternPool.Index) SemaError!void { +pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, func_index: InternPool.Index) SemaError!void { const tracy = trace(@src()); defer tracy.end(); - const ip = &mod.intern_pool; - const func = mod.funcInfo(func_index); + const ip = &zcu.intern_pool; + const func = zcu.funcInfo(func_index); const decl_index = func.owner_decl; - const decl = mod.declPtr(decl_index); + const decl = zcu.declPtr(decl_index); switch (decl.analysis) { .unreferenced => unreachable, @@ -3253,13 +3263,13 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func_index: InternPool.Index) SemaEr .success => return, } - const gpa = mod.gpa; + const gpa = zcu.gpa; var tmp_arena = std.heap.ArenaAllocator.init(gpa); defer tmp_arena.deinit(); const sema_arena = tmp_arena.allocator(); - var air = mod.analyzeFnBody(func_index, sema_arena) catch |err| switch (err) { + var air = zcu.analyzeFnBody(func_index, sema_arena) catch |err| switch (err) { error.AnalysisFail => { if (func.analysis(ip).state == .in_progress) { // If this decl caused the compile error, the analysis field would @@ -3273,25 +3283,22 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func_index: InternPool.Index) SemaEr }; defer air.deinit(gpa); - const comp = mod.comp; - - const no_bin_file = (comp.bin_file == null and - comp.emit_asm == null and - comp.emit_llvm_ir == null and - comp.emit_llvm_bc == null); + const comp = zcu.comp; const dump_air = builtin.mode == .Debug and comp.verbose_air; const dump_llvm_ir = builtin.mode == .Debug and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null); - if (no_bin_file and !dump_air and !dump_llvm_ir) return; + if (comp.bin_file == null and zcu.llvm_object == null and !dump_air and !dump_llvm_ir) { + return; + } var liveness = try Liveness.analyze(gpa, air, ip); defer liveness.deinit(gpa); if (dump_air) { - const fqn = try decl.getFullyQualifiedName(mod); + const fqn = try decl.getFullyQualifiedName(zcu); std.debug.print("# Begin Function AIR: {}:\n", .{fqn.fmt(ip)}); - @import("print_air.zig").dump(mod, air, liveness); + @import("print_air.zig").dump(zcu, air, liveness); std.debug.print("# End Function AIR: {}\n\n", .{fqn.fmt(ip)}); } @@ -3307,12 +3314,12 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func_index: InternPool.Index) SemaEr verify.verify() catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, else => { - try mod.failed_decls.ensureUnusedCapacity(gpa, 1); - mod.failed_decls.putAssumeCapacityNoClobber( + try zcu.failed_decls.ensureUnusedCapacity(gpa, 1); + zcu.failed_decls.putAssumeCapacityNoClobber( decl_index, try Module.ErrorMsg.create( gpa, - decl.srcLoc(mod), + decl.srcLoc(zcu), "invalid liveness: {s}", .{@errorName(err)}, ), @@ -3323,28 +3330,32 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func_index: InternPool.Index) SemaEr }; } - if (no_bin_file and !dump_llvm_ir) return; - - const lf = comp.bin_file.?; - lf.updateFunc(mod, func_index, air, liveness) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - error.AnalysisFail => { - decl.analysis = .codegen_failure; - return; - }, - else => { - try mod.failed_decls.ensureUnusedCapacity(gpa, 1); - mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create( - gpa, - decl.srcLoc(mod), - "unable to codegen: {s}", - .{@errorName(err)}, - )); - decl.analysis = .codegen_failure_retryable; - return; - }, - }; - return; + if (comp.bin_file) |lf| { + lf.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.AnalysisFail => { + decl.analysis = .codegen_failure; + }, + else => { + try zcu.failed_decls.ensureUnusedCapacity(gpa, 1); + zcu.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create( + gpa, + decl.srcLoc(zcu), + "unable to codegen: {s}", + .{@errorName(err)}, + )); + decl.analysis = .codegen_failure_retryable; + }, + }; + } else if (zcu.llvm_object) |llvm_object| { + if (build_options.only_c) unreachable; + llvm_object.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.AnalysisFail => { + decl.analysis = .codegen_failure; + }, + }; + } }, } } @@ -5235,44 +5246,57 @@ pub fn processExports(mod: *Module) !void { const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, *Export); fn processExportsInner( - mod: *Module, + zcu: *Zcu, symbol_exports: *SymbolExports, exported: Exported, exports: []const *Export, ) error{OutOfMemory}!void { - const gpa = mod.gpa; + const gpa = zcu.gpa; for (exports) |new_export| { const gop = try symbol_exports.getOrPut(gpa, new_export.opts.name); if (gop.found_existing) { new_export.status = .failed_retryable; - try mod.failed_exports.ensureUnusedCapacity(gpa, 1); - const src_loc = new_export.getSrcLoc(mod); + try zcu.failed_exports.ensureUnusedCapacity(gpa, 1); + const src_loc = new_export.getSrcLoc(zcu); const msg = try ErrorMsg.create(gpa, src_loc, "exported symbol collision: {}", .{ - new_export.opts.name.fmt(&mod.intern_pool), + new_export.opts.name.fmt(&zcu.intern_pool), }); errdefer msg.destroy(gpa); const other_export = gop.value_ptr.*; - const other_src_loc = other_export.getSrcLoc(mod); - try mod.errNoteNonLazy(other_src_loc, msg, "other symbol here", .{}); - mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg); + const other_src_loc = other_export.getSrcLoc(zcu); + try zcu.errNoteNonLazy(other_src_loc, msg, "other symbol here", .{}); + zcu.failed_exports.putAssumeCapacityNoClobber(new_export, msg); new_export.status = .failed; } else { gop.value_ptr.* = new_export; } } - const lf = mod.comp.bin_file orelse return; - lf.updateExports(mod, exported, exports) catch |err| switch (err) { + if (zcu.comp.bin_file) |lf| { + try handleUpdateExports(zcu, exports, lf.updateExports(zcu, exported, exports)); + } else if (zcu.llvm_object) |llvm_object| { + if (build_options.only_c) unreachable; + try handleUpdateExports(zcu, exports, llvm_object.updateExports(zcu, exported, exports)); + } +} + +fn handleUpdateExports( + zcu: *Zcu, + exports: []const *Export, + result: link.File.UpdateExportsError!void, +) Allocator.Error!void { + const gpa = zcu.gpa; + result catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, - else => { + error.AnalysisFail => { const new_export = exports[0]; new_export.status = .failed_retryable; - try mod.failed_exports.ensureUnusedCapacity(gpa, 1); - const src_loc = new_export.getSrcLoc(mod); + try zcu.failed_exports.ensureUnusedCapacity(gpa, 1); + const src_loc = new_export.getSrcLoc(zcu); const msg = try ErrorMsg.create(gpa, src_loc, "unable to export: {s}", .{ @errorName(err), }); - mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg); + zcu.failed_exports.putAssumeCapacityNoClobber(new_export, msg); }, }; } @@ -5415,41 +5439,38 @@ pub fn populateTestFunctions( try mod.linkerUpdateDecl(decl_index); } -pub fn linkerUpdateDecl(mod: *Module, decl_index: Decl.Index) !void { - const comp = mod.comp; +pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void { + const comp = zcu.comp; if (comp.bin_file) |lf| { - const decl = mod.declPtr(decl_index); - lf.updateDecl(mod, decl_index) catch |err| switch (err) { + lf.updateDecl(zcu, decl_index) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => { + const decl = zcu.declPtr(decl_index); decl.analysis = .codegen_failure; - return; }, else => { - const gpa = mod.gpa; - try mod.failed_decls.ensureUnusedCapacity(gpa, 1); - mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( + const decl = zcu.declPtr(decl_index); + const gpa = zcu.gpa; + try zcu.failed_decls.ensureUnusedCapacity(gpa, 1); + zcu.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( gpa, - decl.srcLoc(mod), + decl.srcLoc(zcu), "unable to codegen: {s}", .{@errorName(err)}, )); decl.analysis = .codegen_failure_retryable; - return; }, }; - } else { - const dump_llvm_ir = builtin.mode == .Debug and - (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null); - - if (comp.emit_asm != null or - comp.emit_llvm_ir != null or - comp.emit_llvm_bc != null or - dump_llvm_ir) - { - @panic("TODO handle emit_asm, emit_llvm_ir, and emit_llvm_bc along with -fno-emit-bin"); - } + } else if (zcu.llvm_object) |llvm_object| { + if (build_options.only_c) unreachable; + llvm_object.updateDecl(zcu, decl_index) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.AnalysisFail => { + const decl = zcu.declPtr(decl_index); + decl.analysis = .codegen_failure; + }, + }; } } diff --git a/src/link.zig b/src/link.zig index e60571a473..89f4125888 100644 --- a/src/link.zig +++ b/src/link.zig @@ -984,49 +984,16 @@ pub const File = struct { return output_mode == .Lib and !self.isStatic(); } - pub fn resolveEmitLoc( - base: File, - arena: Allocator, - opt_loc: ?Compilation.EmitLoc, - ) Allocator.Error!?[*:0]const u8 { - const loc = opt_loc orelse return null; - const slice = if (loc.directory) |directory| - try directory.joinZ(arena, &.{loc.basename}) - else - try base.emit.basenamePath(arena, loc.basename); - return slice.ptr; - } - pub fn emitLlvmObject( base: File, arena: Allocator, llvm_object: *LlvmObject, prog_node: *std.Progress.Node, ) !void { - const comp = base.comp; - - var sub_prog_node = prog_node.start("LLVM Emit Object", 0); - sub_prog_node.activate(); - sub_prog_node.context.refresh(); - 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 base.resolveEmitLoc(arena, .{ - .directory = null, - .basename = base.zcu_object_sub_path.?, - }), - .asm_path = try base.resolveEmitLoc(arena, comp.emit_asm), - .post_ir_path = try base.resolveEmitLoc(arena, comp.emit_llvm_ir), - .post_bc_path = try base.resolveEmitLoc(arena, 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, - .lto = comp.config.lto, - }); + return base.comp.emitLlvmObject(arena, base.emit, .{ + .directory = null, + .basename = base.zcu_object_sub_path.?, + }, llvm_object, prog_node); } pub const C = @import("link/C.zig");