authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-23 02:22:23-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-07-23 02:22:23-04:00
loge3fe3acce0fc65a7f0c7227085456e8d167ed2a7
tree17b5feeab6232ed6bbeff5f5ea7026c6b1ec2235
parenta38a6914875ab3bda02fb1732467228ef876074e
parent80ba9f060d81e8c5674acb4eb07c833d26121462
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9440 from ziglang/emit-bc

add -femit-llvm-bc CLI option and implement it, and improve -fcompiler-rt support

22 files changed, 454 insertions(+), 235 deletions(-)

CMakeLists.txt+1
......@@ -796,6 +796,7 @@ set(BUILD_ZIG1_ARGS
796796 --name zig1
797797 --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib"
798798 "-femit-bin=${ZIG1_OBJECT}"
799 -fcompiler-rt
799800 "${ZIG1_RELEASE_ARG}"
800801 "${ZIG1_SINGLE_THREADED_ARG}"
801802 -lc
doc/docgen.zig+4-4
......@@ -1,5 +1,5 @@
11const std = @import("std");
2const builtin = std.builtin;
2const builtin = @import("builtin");
33const io = std.io;
44const fs = std.fs;
55const process = std.process;
......@@ -13,7 +13,7 @@ const Allocator = std.mem.Allocator;
1313const max_doc_file_size = 10 * 1024 * 1024;
1414
1515const exe_ext = @as(std.zig.CrossTarget, .{}).exeFileExt();
16const obj_ext = @as(std.zig.CrossTarget, .{}).oFileExt();
16const obj_ext = builtin.object_format.fileExt(builtin.cpu.arch);
1717const tmp_dir_name = "docgen_tmp";
1818const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext;
1919
......@@ -281,7 +281,7 @@ const Code = struct {
281281 name: []const u8,
282282 source_token: Token,
283283 is_inline: bool,
284 mode: builtin.Mode,
284 mode: std.builtin.Mode,
285285 link_objects: []const []const u8,
286286 target_str: ?[]const u8,
287287 link_libc: bool,
......@@ -531,7 +531,7 @@ fn genToc(allocator: *Allocator, tokenizer: *Tokenizer) !Toc {
531531 return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {s}", .{code_kind_str});
532532 }
533533
534 var mode: builtin.Mode = .Debug;
534 var mode: std.builtin.Mode = .Debug;
535535 var link_objects = std.ArrayList([]const u8).init(allocator);
536536 defer link_objects.deinit();
537537 var target_str: ?[]const u8 = null;
lib/std/target.zig+63-37
......@@ -549,16 +549,36 @@ pub const Target = struct {
549549 };
550550
551551 pub const ObjectFormat = enum {
552 /// Common Object File Format (Windows)
552553 coff,
553 pe,
554 /// Executable and Linking Format
554555 elf,
556 /// macOS relocatables
555557 macho,
558 /// WebAssembly
556559 wasm,
560 /// C source code
557561 c,
562 /// Standard, Portable Intermediate Representation V
558563 spirv,
564 /// Intel IHEX
559565 hex,
566 /// Machine code with no metadata.
560567 raw,
568 /// Plan 9 from Bell Labs
561569 plan9,
570
571 pub fn fileExt(of: ObjectFormat, cpu_arch: Cpu.Arch) [:0]const u8 {
572 return switch (of) {
573 .coff => ".obj",
574 .elf, .macho, .wasm => ".o",
575 .c => ".c",
576 .spirv => ".spv",
577 .hex => ".ihex",
578 .raw => ".bin",
579 .plan9 => plan9Ext(cpu_arch),
580 };
581 }
562582 };
563583
564584 pub const SubSystem = enum {
......@@ -1290,30 +1310,16 @@ pub const Target = struct {
12901310 return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi);
12911311 }
12921312
1293 pub fn oFileExt_os_abi(os_tag: Os.Tag, abi: Abi) [:0]const u8 {
1294 if (abi == .msvc) {
1295 return ".obj";
1296 }
1297 switch (os_tag) {
1298 .windows, .uefi => return ".obj",
1299 else => return ".o",
1300 }
1301 }
1302
1303 pub fn oFileExt(self: Target) [:0]const u8 {
1304 return oFileExt_os_abi(self.os.tag, self.abi);
1305 }
1306
13071313 pub fn exeFileExtSimple(cpu_arch: Cpu.Arch, os_tag: Os.Tag) [:0]const u8 {
1308 switch (os_tag) {
1309 .windows => return ".exe",
1310 .uefi => return ".efi",
1311 else => if (cpu_arch.isWasm()) {
1312 return ".wasm";
1313 } else {
1314 return "";
1314 return switch (os_tag) {
1315 .windows => ".exe",
1316 .uefi => ".efi",
1317 .plan9 => plan9Ext(cpu_arch),
1318 else => switch (cpu_arch) {
1319 .wasm32, .wasm64 => ".wasm",
1320 else => "",
13151321 },
1316 }
1322 };
13171323 }
13181324
13191325 pub fn exeFileExt(self: Target) [:0]const u8 {
......@@ -1353,20 +1359,16 @@ pub const Target = struct {
13531359 }
13541360
13551361 pub fn getObjectFormatSimple(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat {
1356 if (os_tag == .windows or os_tag == .uefi) {
1357 return .coff;
1358 } else if (os_tag.isDarwin()) {
1359 return .macho;
1360 }
1361 if (cpu_arch.isWasm()) {
1362 return .wasm;
1363 }
1364 if (cpu_arch.isSPIRV()) {
1365 return .spirv;
1366 }
1367 if (os_tag == .plan9)
1368 return .plan9;
1369 return .elf;
1362 return switch (os_tag) {
1363 .windows, .uefi => .coff,
1364 .ios, .macos, .watchos, .tvos => .macho,
1365 .plan9 => .plan9,
1366 else => return switch (cpu_arch) {
1367 .wasm32, .wasm64 => .wasm,
1368 .spirv32, .spirv64 => .spirv,
1369 else => .elf,
1370 },
1371 };
13701372 }
13711373
13721374 pub fn getObjectFormat(self: Target) ObjectFormat {
......@@ -1677,6 +1679,30 @@ pub const Target = struct {
16771679
16781680 return false;
16791681 }
1682
1683 /// 0c spim little-endian MIPS 3000 family
1684 /// 1c 68000 Motorola MC68000
1685 /// 2c 68020 Motorola MC68020
1686 /// 5c arm little-endian ARM
1687 /// 6c amd64 AMD64 and compatibles (e.g., Intel EM64T)
1688 /// 7c arm64 ARM64 (ARMv8)
1689 /// 8c 386 Intel i386, i486, Pentium, etc.
1690 /// kc sparc Sun SPARC
1691 /// qc power Power PC
1692 /// vc mips big-endian MIPS 3000 family
1693 pub fn plan9Ext(cpu_arch: Cpu.Arch) [:0]const u8 {
1694 return switch (cpu_arch) {
1695 .arm => ".5",
1696 .x86_64 => ".6",
1697 .aarch64 => ".7",
1698 .i386 => ".8",
1699 .sparc => ".k",
1700 .powerpc, .powerpcle => ".q",
1701 .mips, .mipsel => ".v",
1702 // ISAs without designated characters get 'X' for lack of a better option.
1703 else => ".X",
1704 };
1705 }
16801706};
16811707
16821708test {
lib/std/zig.zig+10-30
......@@ -108,8 +108,9 @@ pub const BinNameOptions = struct {
108108pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) error{OutOfMemory}![]u8 {
109109 const root_name = options.root_name;
110110 const target = options.target;
111 switch (options.object_format orelse target.getObjectFormat()) {
112 .coff, .pe => switch (options.output_mode) {
111 const ofmt = options.object_format orelse target.getObjectFormat();
112 switch (ofmt) {
113 .coff => switch (options.output_mode) {
113114 .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.exeFileExt() }),
114115 .Lib => {
115116 const suffix = switch (options.link_mode orelse .Static) {
......@@ -118,7 +119,7 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro
118119 };
119120 return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, suffix });
120121 },
121 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.oFileExt() }),
122 .Obj => return std.fmt.allocPrint(allocator, "{s}.obj", .{root_name}),
122123 },
123124 .elf => switch (options.output_mode) {
124125 .Exe => return allocator.dupe(u8, root_name),
......@@ -140,7 +141,7 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro
140141 },
141142 }
142143 },
143 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.oFileExt() }),
144 .Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}),
144145 },
145146 .macho => switch (options.output_mode) {
146147 .Exe => return allocator.dupe(u8, root_name),
......@@ -163,7 +164,7 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro
163164 }
164165 return std.fmt.allocPrint(allocator, "{s}{s}{s}", .{ target.libPrefix(), root_name, suffix });
165166 },
166 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.oFileExt() }),
167 .Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}),
167168 },
168169 .wasm => switch (options.output_mode) {
169170 .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.exeFileExt() }),
......@@ -175,36 +176,15 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro
175176 .Dynamic => return std.fmt.allocPrint(allocator, "{s}.wasm", .{root_name}),
176177 }
177178 },
178 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.oFileExt() }),
179 .Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}),
179180 },
180181 .c => return std.fmt.allocPrint(allocator, "{s}.c", .{root_name}),
181182 .spirv => return std.fmt.allocPrint(allocator, "{s}.spv", .{root_name}),
182183 .hex => return std.fmt.allocPrint(allocator, "{s}.ihex", .{root_name}),
183184 .raw => return std.fmt.allocPrint(allocator, "{s}.bin", .{root_name}),
184 .plan9 => {
185 // copied from 2c(1)
186 // 0c spim little-endian MIPS 3000 family
187 // 1c 68000 Motorola MC68000
188 // 2c 68020 Motorola MC68020
189 // 5c arm little-endian ARM
190 // 6c amd64 AMD64 and compatibles (e.g., Intel EM64T)
191 // 7c arm64 ARM64 (ARMv8)
192 // 8c 386 Intel i386, i486, Pentium, etc.
193 // kc sparc Sun SPARC
194 // qc power Power PC
195 // vc mips big-endian MIPS 3000 family
196 const char: u8 = switch (target.cpu.arch) {
197 .arm => '5',
198 .x86_64 => '6',
199 .aarch64 => '7',
200 .i386 => '8',
201 .sparc => 'k',
202 .powerpc, .powerpcle => 'q',
203 .mips, .mipsel => 'v',
204 else => 'X', // this arch does not have a char or maybe was not ported to plan9 so we just use X
205 };
206 return std.fmt.allocPrint(allocator, "{s}.{c}", .{ root_name, char });
207 },
185 .plan9 => return std.fmt.allocPrint(allocator, "{s}{s}", .{
186 root_name, ofmt.fileExt(target.cpu.arch),
187 }),
208188 }
209189}
210190
lib/std/zig/cross_target.zig-4
......@@ -473,10 +473,6 @@ pub const CrossTarget = struct {
473473 return self.getOsTag() == .windows;
474474 }
475475
476 pub fn oFileExt(self: CrossTarget) [:0]const u8 {
477 return Target.oFileExt_os_abi(self.getOsTag(), self.getAbi());
478 }
479
480476 pub fn exeFileExt(self: CrossTarget) [:0]const u8 {
481477 return Target.exeFileExtSimple(self.getCpuArch(), self.getOsTag());
482478 }
src/Compilation.zig+58-17
......@@ -143,6 +143,7 @@ debug_compiler_runtime_libs: bool,
143143
144144emit_asm: ?EmitLoc,
145145emit_llvm_ir: ?EmitLoc,
146emit_llvm_bc: ?EmitLoc,
146147emit_analysis: ?EmitLoc,
147148emit_docs: ?EmitLoc,
148149
......@@ -586,6 +587,17 @@ pub const Directory = struct {
586587 return std.fs.path.join(allocator, paths);
587588 }
588589 }
590
591 pub fn joinZ(self: Directory, allocator: *Allocator, paths: []const []const u8) ![:0]u8 {
592 if (self.path) |p| {
593 // TODO clean way to do this with only 1 allocation
594 const part2 = try std.fs.path.join(allocator, paths);
595 defer allocator.free(part2);
596 return std.fs.path.joinZ(allocator, &[_][]const u8{ p, part2 });
597 } else {
598 return std.fs.path.joinZ(allocator, paths);
599 }
600 }
589601};
590602
591603pub const EmitLoc = struct {
......@@ -623,6 +635,8 @@ pub const InitOptions = struct {
623635 emit_asm: ?EmitLoc = null,
624636 /// `null` means to not emit LLVM IR.
625637 emit_llvm_ir: ?EmitLoc = null,
638 /// `null` means to not emit LLVM module bitcode.
639 emit_llvm_bc: ?EmitLoc = null,
626640 /// `null` means to not emit semantic analysis JSON.
627641 emit_analysis: ?EmitLoc = null,
628642 /// `null` means to not emit docs.
......@@ -812,6 +826,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
812826 const ofmt = options.object_format orelse options.target.getObjectFormat();
813827
814828 const use_stage1 = options.use_stage1 orelse blk: {
829 // Even though we may have no Zig code to compile (depending on `options.root_pkg`),
830 // we may need to use stage1 for building compiler-rt and other dependencies.
831
815832 if (build_options.omit_stage2)
816833 break :blk true;
817834 if (options.use_llvm) |use_llvm| {
......@@ -819,6 +836,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
819836 break :blk false;
820837 }
821838 }
839
822840 break :blk build_options.is_stage1;
823841 };
824842
......@@ -835,6 +853,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
835853 if (ofmt == .c)
836854 break :blk false;
837855
856 // If emitting to LLVM bitcode object format, must use LLVM backend.
857 if (options.emit_llvm_ir != null or options.emit_llvm_bc != null)
858 break :blk true;
859
838860 // The stage1 compiler depends on the stage1 C++ LLVM backend
839861 // to compile zig code.
840862 if (use_stage1)
......@@ -853,6 +875,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
853875 if (options.machine_code_model != .default) {
854876 return error.MachineCodeModelNotSupportedWithoutLlvm;
855877 }
878 if (options.emit_llvm_ir != null or options.emit_llvm_bc != null) {
879 return error.EmittingLlvmModuleRequiresUsingLlvmBackend;
880 }
856881 }
857882
858883 const tsan = options.want_tsan orelse false;
......@@ -1381,6 +1406,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
13811406 .bin_file = bin_file,
13821407 .emit_asm = options.emit_asm,
13831408 .emit_llvm_ir = options.emit_llvm_ir,
1409 .emit_llvm_bc = options.emit_llvm_bc,
13841410 .emit_analysis = options.emit_analysis,
13851411 .emit_docs = options.emit_docs,
13861412 .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
......@@ -1513,24 +1539,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
15131539 }
15141540
15151541 // The `use_stage1` condition is here only because stage2 cannot yet build compiler-rt.
1516 // Once it is capable this condition should be removed.
1542 // Once it is capable this condition should be removed. When removing this condition,
1543 // also test the use case of `build-obj -fcompiler-rt` with the self-hosted compiler
1544 // and make sure the compiler-rt symbols are emitted. Currently this is hooked up for
1545 // stage1 but not stage2.
15171546 if (comp.bin_file.options.use_stage1) {
15181547 if (comp.bin_file.options.include_compiler_rt) {
15191548 if (is_exe_or_dyn_lib) {
15201549 try comp.work_queue.writeItem(.{ .compiler_rt_lib = {} });
1521 } else {
1550 } else if (options.output_mode != .Obj) {
1551 // If build-obj with -fcompiler-rt is requested, that is handled specially
1552 // elsewhere. In this case we are making a static library, so we ask
1553 // for a compiler-rt object to put in it.
15221554 try comp.work_queue.writeItem(.{ .compiler_rt_obj = {} });
1523 if (comp.bin_file.options.object_format != .elf and
1524 comp.bin_file.options.output_mode == .Obj)
1525 {
1526 // For ELF we can rely on using -r to link multiple objects together into one,
1527 // but to truly support `build-obj -fcompiler-rt` will require virtually
1528 // injecting `_ = @import("compiler_rt.zig")` into the root source file of
1529 // the compilation.
1530 fatal("Embedding compiler-rt into {s} objects is not yet implemented.", .{
1531 @tagName(comp.bin_file.options.object_format),
1532 });
1533 }
15341555 }
15351556 }
15361557 if (needs_c_symbols) {
......@@ -2728,7 +2749,10 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
27282749 comp.bin_file.options.root_name
27292750 else
27302751 c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len];
2731 const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, comp.getTarget().oFileExt() });
2752 const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{
2753 o_basename_noext,
2754 comp.bin_file.options.object_format.fileExt(comp.bin_file.options.target.cpu.arch),
2755 });
27322756
27332757 const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: {
27342758 var argv = std.ArrayList([]const u8).init(comp.gpa);
......@@ -3023,7 +3047,7 @@ pub fn addCCArgs(
30233047 if (!comp.bin_file.options.strip) {
30243048 try argv.append("-g");
30253049 switch (comp.bin_file.options.object_format) {
3026 .coff, .pe => try argv.append("-gcodeview"),
3050 .coff => try argv.append("-gcodeview"),
30273051 else => {},
30283052 }
30293053 }
......@@ -3949,6 +3973,16 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
39493973 const id_symlink_basename = "stage1.id";
39503974 const libs_txt_basename = "libs.txt";
39513975
3976 // The include_compiler_rt stored in the bin file options here means that we need
3977 // compiler-rt symbols *somehow*. However, in the context of using the stage1 backend
3978 // we need to tell stage1 to include compiler-rt only if stage1 is the place that
3979 // needs to provide those symbols. Otherwise the stage2 infrastructure will take care
3980 // of it in the linker, by putting compiler_rt.o into a static archive, or linking
3981 // compiler_rt.a against an executable. In other words we only want to set this flag
3982 // for stage1 if we are using build-obj.
3983 const include_compiler_rt = comp.bin_file.options.output_mode == .Obj and
3984 comp.bin_file.options.include_compiler_rt;
3985
39523986 // We are about to obtain this lock, so here we give other processes a chance first.
39533987 comp.releaseStage1Lock();
39543988
......@@ -3970,6 +4004,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
39704004 man.hash.add(target.os.getVersionRange());
39714005 man.hash.add(comp.bin_file.options.dll_export_fns);
39724006 man.hash.add(comp.bin_file.options.function_sections);
4007 man.hash.add(include_compiler_rt);
39734008 man.hash.add(comp.bin_file.options.is_test);
39744009 man.hash.add(comp.bin_file.options.emit != null);
39754010 man.hash.add(mod.emit_h != null);
......@@ -3978,6 +4013,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
39784013 }
39794014 man.hash.addOptionalEmitLoc(comp.emit_asm);
39804015 man.hash.addOptionalEmitLoc(comp.emit_llvm_ir);
4016 man.hash.addOptionalEmitLoc(comp.emit_llvm_bc);
39814017 man.hash.addOptionalEmitLoc(comp.emit_analysis);
39824018 man.hash.addOptionalEmitLoc(comp.emit_docs);
39834019 man.hash.add(comp.test_evented_io);
......@@ -4083,13 +4119,14 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
40834119 ) orelse return error.OutOfMemory;
40844120
40854121 const emit_bin_path = if (comp.bin_file.options.emit != null) blk: {
4086 const bin_basename = try std.zig.binNameAlloc(arena, .{
4122 const obj_basename = try std.zig.binNameAlloc(arena, .{
40874123 .root_name = comp.bin_file.options.root_name,
40884124 .target = target,
40894125 .output_mode = .Obj,
40904126 });
4091 break :blk try directory.join(arena, &[_][]const u8{bin_basename});
4127 break :blk try directory.join(arena, &[_][]const u8{obj_basename});
40924128 } else "";
4129
40934130 if (mod.emit_h != null) {
40944131 log.warn("-femit-h is not available in the stage1 backend; no .h file will be produced", .{});
40954132 }
......@@ -4097,6 +4134,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
40974134 const emit_h_path = try stage1LocPath(arena, emit_h_loc, directory);
40984135 const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory);
40994136 const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory);
4137 const emit_llvm_bc_path = try stage1LocPath(arena, comp.emit_llvm_bc, directory);
41004138 const emit_analysis_path = try stage1LocPath(arena, comp.emit_analysis, directory);
41014139 const emit_docs_path = try stage1LocPath(arena, comp.emit_docs, directory);
41024140 const stage1_pkg = try createStage1Pkg(arena, "root", mod.root_pkg, null);
......@@ -4117,6 +4155,8 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
41174155 .emit_asm_len = emit_asm_path.len,
41184156 .emit_llvm_ir_ptr = emit_llvm_ir_path.ptr,
41194157 .emit_llvm_ir_len = emit_llvm_ir_path.len,
4158 .emit_bitcode_ptr = emit_llvm_bc_path.ptr,
4159 .emit_bitcode_len = emit_llvm_bc_path.len,
41204160 .emit_analysis_json_ptr = emit_analysis_path.ptr,
41214161 .emit_analysis_json_len = emit_analysis_path.len,
41224162 .emit_docs_ptr = emit_docs_path.ptr,
......@@ -4145,6 +4185,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
41454185 .valgrind_enabled = comp.bin_file.options.valgrind,
41464186 .tsan_enabled = comp.bin_file.options.tsan,
41474187 .function_sections = comp.bin_file.options.function_sections,
4188 .include_compiler_rt = include_compiler_rt,
41484189 .enable_stack_probing = comp.bin_file.options.stack_check,
41494190 .red_zone = comp.bin_file.options.red_zone,
41504191 .enable_time_report = comp.time_report,
src/codegen/llvm.zig+131-65
......@@ -72,9 +72,9 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {
7272 .renderscript32 => "renderscript32",
7373 .renderscript64 => "renderscript64",
7474 .ve => "ve",
75 .spu_2 => return error.LLVMBackendDoesNotSupportSPUMarkII,
76 .spirv32 => return error.LLVMBackendDoesNotSupportSPIRV,
77 .spirv64 => return error.LLVMBackendDoesNotSupportSPIRV,
75 .spu_2 => return error.@"LLVM backend does not support SPU Mark II",
76 .spirv32 => return error.@"LLVM backend does not support SPIR-V",
77 .spirv64 => return error.@"LLVM backend does not support SPIR-V",
7878 };
7979
8080 const llvm_os = switch (target.os.tag) {
......@@ -114,11 +114,13 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {
114114 .wasi => "wasi",
115115 .emscripten => "emscripten",
116116 .uefi => "windows",
117 .opencl => return error.LLVMBackendDoesNotSupportOpenCL,
118 .glsl450 => return error.LLVMBackendDoesNotSupportGLSL450,
119 .vulkan => return error.LLVMBackendDoesNotSupportVulkan,
120 .plan9 => return error.LLVMBackendDoesNotSupportPlan9,
121 .other => "unknown",
117
118 .opencl,
119 .glsl450,
120 .vulkan,
121 .plan9,
122 .other,
123 => "unknown",
122124 };
123125
124126 const llvm_abi = switch (target.abi) {
......@@ -152,84 +154,105 @@ pub const Object = struct {
152154 llvm_module: *const llvm.Module,
153155 context: *const llvm.Context,
154156 target_machine: *const llvm.TargetMachine,
155 object_pathZ: [:0]const u8,
156
157 pub fn create(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Object {
158 _ = sub_path;
159 const self = try allocator.create(Object);
160 errdefer allocator.destroy(self);
161
162 const obj_basename = try std.zig.binNameAlloc(allocator, .{
163 .root_name = options.root_name,
164 .target = options.target,
165 .output_mode = .Obj,
166 });
167 defer allocator.free(obj_basename);
168157
169 const o_directory = options.module.?.zig_cache_artifact_directory;
170 const object_path = try o_directory.join(allocator, &[_][]const u8{obj_basename});
171 defer allocator.free(object_path);
172
173 const object_pathZ = try allocator.dupeZ(u8, object_path);
174 errdefer allocator.free(object_pathZ);
158 pub fn create(gpa: *Allocator, options: link.Options) !*Object {
159 const obj = try gpa.create(Object);
160 errdefer gpa.destroy(obj);
161 obj.* = try Object.init(gpa, options);
162 return obj;
163 }
175164
165 pub fn init(gpa: *Allocator, options: link.Options) !Object {
176166 const context = llvm.Context.create();
177167 errdefer context.dispose();
178168
179169 initializeLLVMTargets();
180170
181 const root_nameZ = try allocator.dupeZ(u8, options.root_name);
182 defer allocator.free(root_nameZ);
171 const root_nameZ = try gpa.dupeZ(u8, options.root_name);
172 defer gpa.free(root_nameZ);
183173 const llvm_module = llvm.Module.createWithName(root_nameZ.ptr, context);
184174 errdefer llvm_module.dispose();
185175
186 const llvm_target_triple = try targetTriple(allocator, options.target);
187 defer allocator.free(llvm_target_triple);
176 const llvm_target_triple = try targetTriple(gpa, options.target);
177 defer gpa.free(llvm_target_triple);
188178
189179 var error_message: [*:0]const u8 = undefined;
190180 var target: *const llvm.Target = undefined;
191181 if (llvm.Target.getFromTriple(llvm_target_triple.ptr, &target, &error_message).toBool()) {
192182 defer llvm.disposeMessage(error_message);
193183
194 const stderr = std.io.getStdErr().writer();
195 try stderr.print(
196 \\Zig is expecting LLVM to understand this target: '{s}'
197 \\However LLVM responded with: "{s}"
198 \\
199 ,
200 .{ llvm_target_triple, error_message },
201 );
202 return error.InvalidLLVMTriple;
184 log.err("LLVM failed to parse '{s}': {s}", .{ llvm_target_triple, error_message });
185 return error.InvalidLlvmTriple;
203186 }
204187
205 const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug) .None else .Aggressive;
188 const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug)
189 .None
190 else
191 .Aggressive;
192
193 const reloc_mode: llvm.RelocMode = if (options.pic)
194 .PIC
195 else if (options.link_mode == .Dynamic)
196 llvm.RelocMode.DynamicNoPIC
197 else
198 .Static;
199
200 const code_model: llvm.CodeModel = switch (options.machine_code_model) {
201 .default => .Default,
202 .tiny => .Tiny,
203 .small => .Small,
204 .kernel => .Kernel,
205 .medium => .Medium,
206 .large => .Large,
207 };
208
209 // TODO handle float ABI better- it should depend on the ABI portion of std.Target
210 const float_abi: llvm.ABIType = .Default;
211
212 // TODO a way to override this as part of std.Target ABI?
213 const abi_name: ?[*:0]const u8 = switch (options.target.cpu.arch) {
214 .riscv32 => switch (options.target.os.tag) {
215 .linux => "ilp32d",
216 else => "ilp32",
217 },
218 .riscv64 => switch (options.target.os.tag) {
219 .linux => "lp64d",
220 else => "lp64",
221 },
222 else => null,
223 };
224
206225 const target_machine = llvm.TargetMachine.create(
207226 target,
208227 llvm_target_triple.ptr,
209 "",
210 "",
228 if (options.target.cpu.model.llvm_name) |s| s.ptr else null,
229 options.llvm_cpu_features,
211230 opt_level,
212 .Static,
213 .Default,
231 reloc_mode,
232 code_model,
233 options.function_sections,
234 float_abi,
235 abi_name,
214236 );
215237 errdefer target_machine.dispose();
216238
217 self.* = .{
239 return Object{
218240 .llvm_module = llvm_module,
219241 .context = context,
220242 .target_machine = target_machine,
221 .object_pathZ = object_pathZ,
222243 };
223 return self;
224244 }
225245
226 pub fn deinit(self: *Object, allocator: *Allocator) void {
246 pub fn deinit(self: *Object) void {
227247 self.target_machine.dispose();
228248 self.llvm_module.dispose();
229249 self.context.dispose();
250 self.* = undefined;
251 }
230252
231 allocator.free(self.object_pathZ);
232 allocator.destroy(self);
253 pub fn destroy(self: *Object, gpa: *Allocator) void {
254 self.deinit();
255 gpa.destroy(self);
233256 }
234257
235258 fn initializeLLVMTargets() void {
......@@ -240,38 +263,81 @@ pub const Object = struct {
240263 llvm.initializeAllAsmParsers();
241264 }
242265
266 fn locPath(
267 arena: *Allocator,
268 opt_loc: ?Compilation.EmitLoc,
269 cache_directory: Compilation.Directory,
270 ) !?[*:0]u8 {
271 const loc = opt_loc orelse return null;
272 const directory = loc.directory orelse cache_directory;
273 const slice = try directory.joinZ(arena, &[_][]const u8{loc.basename});
274 return slice.ptr;
275 }
276
243277 pub fn flushModule(self: *Object, comp: *Compilation) !void {
244278 if (comp.verbose_llvm_ir) {
245 const dump = self.llvm_module.printToString();
246 defer llvm.disposeMessage(dump);
247
248 const stderr = std.io.getStdErr().writer();
249 try stderr.writeAll(std.mem.spanZ(dump));
279 self.llvm_module.dump();
250280 }
251281
252 {
282 if (std.debug.runtime_safety) {
253283 var error_message: [*:0]const u8 = undefined;
254284 // verifyModule always allocs the error_message even if there is no error
255285 defer llvm.disposeMessage(error_message);
256286
257287 if (self.llvm_module.verify(.ReturnStatus, &error_message).toBool()) {
258 const stderr = std.io.getStdErr().writer();
259 try stderr.print("broken LLVM module found: {s}\nThis is a bug in the Zig compiler.", .{error_message});
260 return error.BrokenLLVMModule;
288 std.debug.print("\n{s}\n", .{error_message});
289 @panic("LLVM module verification failed");
261290 }
262291 }
263292
293 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
294 defer arena_allocator.deinit();
295 const arena = &arena_allocator.allocator;
296
297 const mod = comp.bin_file.options.module.?;
298 const cache_dir = mod.zig_cache_artifact_directory;
299
300 const emit_bin_path: ?[*:0]const u8 = if (comp.bin_file.options.emit != null) blk: {
301 const obj_basename = try std.zig.binNameAlloc(arena, .{
302 .root_name = comp.bin_file.options.root_name,
303 .target = comp.bin_file.options.target,
304 .output_mode = .Obj,
305 });
306 if (cache_dir.joinZ(arena, &[_][]const u8{obj_basename})) |p| {
307 break :blk p.ptr;
308 } else |err| {
309 return err;
310 }
311 } else null;
312
313 const emit_asm_path = try locPath(arena, comp.emit_asm, cache_dir);
314 const emit_llvm_ir_path = try locPath(arena, comp.emit_llvm_ir, cache_dir);
315 const emit_llvm_bc_path = try locPath(arena, comp.emit_llvm_bc, cache_dir);
316
264317 var error_message: [*:0]const u8 = undefined;
265318 if (self.target_machine.emitToFile(
266319 self.llvm_module,
267 self.object_pathZ.ptr,
268 .ObjectFile,
269320 &error_message,
270 ).toBool()) {
321 comp.bin_file.options.optimize_mode == .Debug,
322 comp.bin_file.options.optimize_mode == .ReleaseSmall,
323 comp.time_report,
324 comp.bin_file.options.tsan,
325 comp.bin_file.options.lto,
326 emit_asm_path,
327 emit_bin_path,
328 emit_llvm_ir_path,
329 emit_llvm_bc_path,
330 )) {
271331 defer llvm.disposeMessage(error_message);
272332
273 const stderr = std.io.getStdErr().writer();
274 try stderr.print("LLVM failed to emit file: {s}\n", .{error_message});
333 const emit_asm_msg = emit_asm_path orelse "(none)";
334 const emit_bin_msg = emit_bin_path orelse "(none)";
335 const emit_llvm_ir_msg = emit_llvm_ir_path orelse "(none)";
336 const emit_llvm_bc_msg = emit_llvm_bc_path orelse "(none)";
337 log.err("LLVM failed to emit asm={s} bin={s} ir={s} bc={s}: {s}", .{
338 emit_asm_msg, emit_bin_msg, emit_llvm_ir_msg, emit_llvm_bc_msg,
339 error_message,
340 });
275341 return error.FailedToEmit;
276342 }
277343 }
src/codegen/llvm/bindings.zig+35-13
......@@ -123,6 +123,9 @@ pub const Module = opaque {
123123
124124 pub const getNamedGlobal = LLVMGetNamedGlobal;
125125 extern fn LLVMGetNamedGlobal(M: *const Module, Name: [*:0]const u8) ?*const Value;
126
127 pub const dump = LLVMDumpModule;
128 extern fn LLVMDumpModule(M: *const Module) void;
126129};
127130
128131pub const lookupIntrinsicID = LLVMLookupIntrinsicID;
......@@ -250,31 +253,41 @@ pub const BasicBlock = opaque {
250253};
251254
252255pub const TargetMachine = opaque {
253 pub const create = LLVMCreateTargetMachine;
254 extern fn LLVMCreateTargetMachine(
256 pub const create = ZigLLVMCreateTargetMachine;
257 extern fn ZigLLVMCreateTargetMachine(
255258 T: *const Target,
256259 Triple: [*:0]const u8,
257 CPU: [*:0]const u8,
258 Features: [*:0]const u8,
260 CPU: ?[*:0]const u8,
261 Features: ?[*:0]const u8,
259262 Level: CodeGenOptLevel,
260263 Reloc: RelocMode,
261 CodeModel: CodeMode,
264 CodeModel: CodeModel,
265 function_sections: bool,
266 float_abi: ABIType,
267 abi_name: ?[*:0]const u8,
262268 ) *const TargetMachine;
263269
264270 pub const dispose = LLVMDisposeTargetMachine;
265271 extern fn LLVMDisposeTargetMachine(T: *const TargetMachine) void;
266272
267 pub const emitToFile = LLVMTargetMachineEmitToFile;
268 extern fn LLVMTargetMachineEmitToFile(
269 *const TargetMachine,
273 pub const emitToFile = ZigLLVMTargetMachineEmitToFile;
274 extern fn ZigLLVMTargetMachineEmitToFile(
275 T: *const TargetMachine,
270276 M: *const Module,
271 Filename: [*:0]const u8,
272 codegen: CodeGenFileType,
273277 ErrorMessage: *[*:0]const u8,
274 ) Bool;
278 is_debug: bool,
279 is_small: bool,
280 time_report: bool,
281 tsan: bool,
282 lto: bool,
283 asm_filename: ?[*:0]const u8,
284 bin_filename: ?[*:0]const u8,
285 llvm_ir_filename: ?[*:0]const u8,
286 bitcode_filename: ?[*:0]const u8,
287 ) bool;
275288};
276289
277pub const CodeMode = enum(c_int) {
290pub const CodeModel = enum(c_int) {
278291 Default,
279292 JITDefault,
280293 Tiny,
......@@ -295,7 +308,7 @@ pub const RelocMode = enum(c_int) {
295308 Default,
296309 Static,
297310 PIC,
298 DynamicNoPic,
311 DynamicNoPIC,
299312 ROPI,
300313 RWPI,
301314 ROPI_RWPI,
......@@ -306,6 +319,15 @@ pub const CodeGenFileType = enum(c_int) {
306319 ObjectFile,
307320};
308321
322pub const ABIType = enum(c_int) {
323 /// Target-specific (either soft or hard depending on triple, etc).
324 Default,
325 /// Soft float.
326 Soft,
327 // Hard float.
328 Hard,
329};
330
309331pub const Target = opaque {
310332 pub const getFromTriple = LLVMGetTargetFromTriple;
311333 extern fn LLVMGetTargetFromTriple(Triple: [*:0]const u8, T: **const Target, ErrorMessage: *[*:0]const u8) Bool;
src/link.zig+10-6
......@@ -191,7 +191,7 @@ pub const File = struct {
191191 const use_stage1 = build_options.is_stage1 and options.use_stage1;
192192 if (use_stage1 or options.emit == null) {
193193 return switch (options.object_format) {
194 .coff, .pe => &(try Coff.createEmpty(allocator, options)).base,
194 .coff => &(try Coff.createEmpty(allocator, options)).base,
195195 .elf => &(try Elf.createEmpty(allocator, options)).base,
196196 .macho => &(try MachO.createEmpty(allocator, options)).base,
197197 .wasm => &(try Wasm.createEmpty(allocator, options)).base,
......@@ -206,9 +206,10 @@ pub const File = struct {
206206 const use_lld = build_options.have_llvm and options.use_lld; // comptime known false when !have_llvm
207207 const sub_path = if (use_lld) blk: {
208208 if (options.module == null) {
209 // No point in opening a file, we would not write anything to it. Initialize with empty.
209 // No point in opening a file, we would not write anything to it.
210 // Initialize with empty.
210211 return switch (options.object_format) {
211 .coff, .pe => &(try Coff.createEmpty(allocator, options)).base,
212 .coff => &(try Coff.createEmpty(allocator, options)).base,
212213 .elf => &(try Elf.createEmpty(allocator, options)).base,
213214 .macho => &(try MachO.createEmpty(allocator, options)).base,
214215 .plan9 => &(try Plan9.createEmpty(allocator, options)).base,
......@@ -219,13 +220,16 @@ pub const File = struct {
219220 .raw => return error.RawObjectFormatUnimplemented,
220221 };
221222 }
222 // Open a temporary object file, not the final output file because we want to link with LLD.
223 break :blk try std.fmt.allocPrint(allocator, "{s}{s}", .{ emit.sub_path, options.target.oFileExt() });
223 // Open a temporary object file, not the final output file because we
224 // want to link with LLD.
225 break :blk try std.fmt.allocPrint(allocator, "{s}{s}", .{
226 emit.sub_path, options.object_format.fileExt(options.target.cpu.arch),
227 });
224228 } else emit.sub_path;
225229 errdefer if (use_lld) allocator.free(sub_path);
226230
227231 const file: *File = switch (options.object_format) {
228 .coff, .pe => &(try Coff.openPath(allocator, sub_path, options)).base,
232 .coff => &(try Coff.openPath(allocator, sub_path, options)).base,
229233 .elf => &(try Elf.openPath(allocator, sub_path, options)).base,
230234 .macho => &(try MachO.openPath(allocator, sub_path, options)).base,
231235 .plan9 => &(try Plan9.openPath(allocator, sub_path, options)).base,
src/link/Coff.zig+13-12
......@@ -17,9 +17,9 @@ const link = @import("../link.zig");
1717const build_options = @import("build_options");
1818const Cache = @import("../Cache.zig");
1919const mingw = @import("../mingw.zig");
20const llvm_backend = @import("../codegen/llvm.zig");
2120const Air = @import("../Air.zig");
2221const Liveness = @import("../Liveness.zig");
22const LlvmObject = @import("../codegen/llvm.zig").Object;
2323
2424const allocation_padding = 4 / 3;
2525const minimum_text_block_size = 64 * allocation_padding;
......@@ -37,7 +37,7 @@ pub const base_tag: link.File.Tag = .coff;
3737const msdos_stub = @embedFile("msdos-stub.bin");
3838
3939/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
40llvm_object: ?*llvm_backend.Object = null,
40llvm_object: ?*LlvmObject = null,
4141
4242base: link.File,
4343ptr_width: PtrWidth,
......@@ -132,7 +132,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
132132 const self = try createEmpty(allocator, options);
133133 errdefer self.base.destroy();
134134
135 self.llvm_object = try llvm_backend.Object.create(allocator, sub_path, options);
135 self.llvm_object = try LlvmObject.create(allocator, options);
136136 return self;
137137 }
138138
......@@ -657,10 +657,7 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {
657657}
658658
659659pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
660 if (build_options.skip_non_native and
661 builtin.object_format != .coff and
662 builtin.object_format != .pe)
663 {
660 if (build_options.skip_non_native and builtin.object_format != .coff) {
664661 @panic("Attempted to compile for object format that was disabled by build configuration");
665662 }
666663 if (build_options.have_llvm) {
......@@ -697,7 +694,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live
697694}
698695
699696pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
700 if (build_options.skip_non_native and builtin.object_format != .coff and builtin.object_format != .pe) {
697 if (build_options.skip_non_native and builtin.object_format != .coff) {
701698 @panic("Attempted to compile for object format that was disabled by build configuration");
702699 }
703700 if (build_options.have_llvm) {
......@@ -823,8 +820,11 @@ pub fn flushModule(self: *Coff, comp: *Compilation) !void {
823820 const tracy = trace(@src());
824821 defer tracy.end();
825822
826 if (build_options.have_llvm)
827 if (self.llvm_object) |llvm_object| return try llvm_object.flushModule(comp);
823 if (build_options.have_llvm) {
824 if (self.llvm_object) |llvm_object| {
825 return try llvm_object.flushModule(comp);
826 }
827 }
828828
829829 if (self.text_section_size_dirty) {
830830 // Write the new raw size in the .text header
......@@ -1398,8 +1398,9 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v
13981398}
13991399
14001400pub fn deinit(self: *Coff) void {
1401 if (build_options.have_llvm)
1402 if (self.llvm_object) |ir_module| ir_module.deinit(self.base.allocator);
1401 if (build_options.have_llvm) {
1402 if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);
1403 }
14031404
14041405 self.text_block_free_list.deinit(self.base.allocator);
14051406 self.offset_table.deinit(self.base.allocator);
src/link/Elf.zig+12-8
......@@ -25,9 +25,9 @@ const target_util = @import("../target.zig");
2525const glibc = @import("../glibc.zig");
2626const musl = @import("../musl.zig");
2727const Cache = @import("../Cache.zig");
28const llvm_backend = @import("../codegen/llvm.zig");
2928const Air = @import("../Air.zig");
3029const Liveness = @import("../Liveness.zig");
30const LlvmObject = @import("../codegen/llvm.zig").Object;
3131
3232const default_entry_addr = 0x8000000;
3333
......@@ -38,7 +38,7 @@ base: File,
3838ptr_width: PtrWidth,
3939
4040/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
41llvm_object: ?*llvm_backend.Object = null,
41llvm_object: ?*LlvmObject = null,
4242
4343/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
4444/// Same order as in the file.
......@@ -235,7 +235,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
235235 const self = try createEmpty(allocator, options);
236236 errdefer self.base.destroy();
237237
238 self.llvm_object = try llvm_backend.Object.create(allocator, sub_path, options);
238 self.llvm_object = try LlvmObject.create(allocator, options);
239239 return self;
240240 }
241241
......@@ -301,9 +301,9 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Elf {
301301}
302302
303303pub fn deinit(self: *Elf) void {
304 if (build_options.have_llvm)
305 if (self.llvm_object) |ir_module|
306 ir_module.deinit(self.base.allocator);
304 if (build_options.have_llvm) {
305 if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);
306 }
307307
308308 self.sections.deinit(self.base.allocator);
309309 self.program_headers.deinit(self.base.allocator);
......@@ -750,8 +750,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
750750 if (build_options.have_llvm)
751751 if (self.llvm_object) |llvm_object| return try llvm_object.flushModule(comp);
752752
753 // TODO This linker code currently assumes there is only 1 compilation unit and it corresponds to the
754 // Zig source code.
753 // TODO This linker code currently assumes there is only 1 compilation unit and it
754 // corresponds to the Zig source code.
755755 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
756756
757757 const target_endian = self.base.options.target.cpu.arch.endian();
......@@ -1289,6 +1289,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
12891289 // TODO: remove when stage2 can build compiler_rt.zig
12901290 if (!build_options.is_stage1) break :blk null;
12911291
1292 // In the case of build-obj we include the compiler-rt symbols directly alongside
1293 // the symbols of the root source file, in the same compilation unit.
1294 if (is_obj) break :blk null;
1295
12921296 if (is_exe_or_dyn_lib) {
12931297 break :blk comp.compiler_rt_static_lib.?.full_object_path;
12941298 } else {
src/link/MachO.zig+6-3
......@@ -30,7 +30,7 @@ const DebugSymbols = @import("MachO/DebugSymbols.zig");
3030const Trie = @import("MachO/Trie.zig");
3131const CodeSignature = @import("MachO/CodeSignature.zig");
3232const Zld = @import("MachO/Zld.zig");
33const llvm_backend = @import("../codegen/llvm.zig");
33const LlvmObject = @import("../codegen/llvm.zig").Object;
3434
3535usingnamespace @import("MachO/commands.zig");
3636
......@@ -39,7 +39,7 @@ pub const base_tag: File.Tag = File.Tag.macho;
3939base: File,
4040
4141/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
42llvm_object: ?*llvm_backend.Object = null,
42llvm_object: ?*LlvmObject = null,
4343
4444/// Debug symbols bundle (or dSym).
4545d_sym: ?DebugSymbols = null,
......@@ -355,7 +355,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
355355 const self = try createEmpty(allocator, options);
356356 errdefer self.base.destroy();
357357
358 self.llvm_object = try llvm_backend.Object.create(allocator, sub_path, options);
358 self.llvm_object = try LlvmObject.create(allocator, options);
359359 return self;
360360 }
361361
......@@ -989,6 +989,9 @@ fn darwinArchString(arch: std.Target.Cpu.Arch) []const u8 {
989989}
990990
991991pub fn deinit(self: *MachO) void {
992 if (build_options.have_llvm) {
993 if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);
994 }
992995 if (self.d_sym) |*ds| {
993996 ds.deinit(self.base.allocator);
994997 }
src/link/Wasm.zig+9-4
......@@ -19,7 +19,7 @@ const build_options = @import("build_options");
1919const wasi_libc = @import("../wasi_libc.zig");
2020const Cache = @import("../Cache.zig");
2121const TypedValue = @import("../TypedValue.zig");
22const llvm_backend = @import("../codegen/llvm.zig");
22const LlvmObject = @import("../codegen/llvm.zig").Object;
2323const Air = @import("../Air.zig");
2424const Liveness = @import("../Liveness.zig");
2525
......@@ -27,7 +27,7 @@ pub const base_tag = link.File.Tag.wasm;
2727
2828base: link.File,
2929/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
30llvm_object: ?*llvm_backend.Object = null,
30llvm_object: ?*LlvmObject = null,
3131/// List of all function Decls to be written to the output file. The index of
3232/// each Decl in this list at the time of writing the binary is used as the
3333/// function index. In the event where ext_funcs' size is not 0, the index of
......@@ -121,7 +121,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
121121 const self = try createEmpty(allocator, options);
122122 errdefer self.base.destroy();
123123
124 self.llvm_object = try llvm_backend.Object.create(allocator, sub_path, options);
124 self.llvm_object = try LlvmObject.create(allocator, options);
125125 return self;
126126 }
127127
......@@ -153,6 +153,9 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Wasm {
153153}
154154
155155pub fn deinit(self: *Wasm) void {
156 if (build_options.have_llvm) {
157 if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);
158 }
156159 for (self.symbols.items) |decl| {
157160 decl.fn_link.wasm.functype.deinit(self.base.allocator);
158161 decl.fn_link.wasm.code.deinit(self.base.allocator);
......@@ -642,7 +645,9 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
642645 break :blk full_obj_path;
643646 } else null;
644647
645 const compiler_rt_path: ?[]const u8 = if (self.base.options.include_compiler_rt)
648 const is_obj = self.base.options.output_mode == .Obj;
649
650 const compiler_rt_path: ?[]const u8 = if (self.base.options.include_compiler_rt and !is_obj)
646651 comp.compiler_rt_static_lib.?.full_object_path
647652 else
648653 null;
src/main.zig+40-22
......@@ -287,9 +287,9 @@ const usage_build_generic =
287287 \\ .s Target-specific assembly source code
288288 \\ .S Assembly with C preprocessor (requires LLVM extensions)
289289 \\ .c C source code (requires LLVM extensions)
290 \\ .cpp C++ source code (requires LLVM extensions)
291 \\ Other C++ extensions: .C .cc .cxx
290 \\ .cxx .cc .C .cpp C++ source code (requires LLVM extensions)
292291 \\ .m Objective-C source code (requires LLVM extensions)
292 \\ .bc LLVM IR Module (requires LLVM extensions)
293293 \\
294294 \\General Options:
295295 \\ -h, --help Print this help and exit
......@@ -301,6 +301,8 @@ const usage_build_generic =
301301 \\ -fno-emit-asm (default) Do not output .s (assembly code)
302302 \\ -femit-llvm-ir[=path] Produce a .ll file with LLVM IR (requires LLVM extensions)
303303 \\ -fno-emit-llvm-ir (default) Do not produce a .ll file with LLVM IR
304 \\ -femit-llvm-bc[=path] Produce a LLVM module as a .bc file (requires LLVM extensions)
305 \\ -fno-emit-llvm-bc (default) Do not produce a LLVM module as a .bc file
304306 \\ -femit-h[=path] Generate a C header file (.h)
305307 \\ -fno-emit-h (default) Do not generate a C header file (.h)
306308 \\ -femit-docs[=path] Create a docs/ dir with html documentation
......@@ -359,15 +361,14 @@ const usage_build_generic =
359361 \\ --single-threaded Code assumes it is only used single-threaded
360362 \\ -ofmt=[mode] Override target object format
361363 \\ elf Executable and Linking Format
362 \\ c Compile to C source code
364 \\ c C source code
363365 \\ wasm WebAssembly
364 \\ pe Portable Executable (Windows)
365366 \\ coff Common Object File Format (Windows)
366367 \\ macho macOS relocatables
367368 \\ spirv Standard, Portable Intermediate Representation V (SPIR-V)
368369 \\ plan9 Plan 9 from Bell Labs object format
369 \\ hex (planned) Intel IHEX
370 \\ raw (planned) Dump machine code directly
370 \\ hex (planned feature) Intel IHEX
371 \\ raw (planned feature) Dump machine code directly
371372 \\ -dirafter [dir] Add directory to AFTER include search path
372373 \\ -isystem [dir] Add directory to SYSTEM include search path
373374 \\ -I[dir] Add directory to include search path
......@@ -384,8 +385,8 @@ const usage_build_generic =
384385 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
385386 \\ --sysroot [path] Set the system root directory (usually /)
386387 \\ --version [ver] Dynamic library semver
387 \\ -fsoname[=name] (Linux) Override the default SONAME value
388 \\ -fno-soname (Linux) Disable emitting a SONAME
388 \\ -fsoname[=name] Override the default SONAME value
389 \\ -fno-soname Disable emitting a SONAME
389390 \\ -fLLD Force using LLD as the linker
390391 \\ -fno-LLD Prevent using LLD as the linker
391392 \\ -fcompiler-rt Always include compiler-rt symbols in output
......@@ -552,6 +553,7 @@ fn buildOutputType(
552553 var emit_bin: EmitBin = .yes_default_path;
553554 var emit_asm: Emit = .no;
554555 var emit_llvm_ir: Emit = .no;
556 var emit_llvm_bc: Emit = .no;
555557 var emit_docs: Emit = .no;
556558 var emit_analysis: Emit = .no;
557559 var target_arch_os_abi: []const u8 = "native";
......@@ -1011,6 +1013,12 @@ fn buildOutputType(
10111013 emit_llvm_ir = .{ .yes = arg["-femit-llvm-ir=".len..] };
10121014 } else if (mem.eql(u8, arg, "-fno-emit-llvm-ir")) {
10131015 emit_llvm_ir = .no;
1016 } else if (mem.eql(u8, arg, "-femit-llvm-bc")) {
1017 emit_llvm_bc = .yes_default_path;
1018 } else if (mem.startsWith(u8, arg, "-femit-llvm-bc=")) {
1019 emit_llvm_bc = .{ .yes = arg["-femit-llvm-bc=".len..] };
1020 } else if (mem.eql(u8, arg, "-fno-emit-llvm-bc")) {
1021 emit_llvm_bc = .no;
10141022 } else if (mem.eql(u8, arg, "-femit-docs")) {
10151023 emit_docs = .yes_default_path;
10161024 } else if (mem.startsWith(u8, arg, "-femit-docs=")) {
......@@ -1708,8 +1716,6 @@ fn buildOutputType(
17081716 break :blk .c;
17091717 } else if (mem.eql(u8, ofmt, "coff")) {
17101718 break :blk .coff;
1711 } else if (mem.eql(u8, ofmt, "pe")) {
1712 break :blk .pe;
17131719 } else if (mem.eql(u8, ofmt, "macho")) {
17141720 break :blk .macho;
17151721 } else if (mem.eql(u8, ofmt, "wasm")) {
......@@ -1753,7 +1759,7 @@ fn buildOutputType(
17531759 };
17541760
17551761 const a_out_basename = switch (object_format) {
1756 .pe, .coff => "a.exe",
1762 .coff => "a.exe",
17571763 else => "a.out",
17581764 };
17591765
......@@ -1818,10 +1824,10 @@ fn buildOutputType(
18181824 var emit_h_resolved = emit_h.resolve(default_h_basename) catch |err| {
18191825 switch (emit_h) {
18201826 .yes => {
1821 fatal("unable to open directory from argument 'femit-h', '{s}': {s}", .{ emit_h.yes, @errorName(err) });
1827 fatal("unable to open directory from argument '-femit-h', '{s}': {s}", .{ emit_h.yes, @errorName(err) });
18221828 },
18231829 .yes_default_path => {
1824 fatal("unable to open directory from arguments 'name' or 'soname', '{s}': {s}", .{ default_h_basename, @errorName(err) });
1830 fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ default_h_basename, @errorName(err) });
18251831 },
18261832 .no => unreachable,
18271833 }
......@@ -1832,10 +1838,10 @@ fn buildOutputType(
18321838 var emit_asm_resolved = emit_asm.resolve(default_asm_basename) catch |err| {
18331839 switch (emit_asm) {
18341840 .yes => {
1835 fatal("unable to open directory from argument 'femit-asm', '{s}': {s}", .{ emit_asm.yes, @errorName(err) });
1841 fatal("unable to open directory from argument '-femit-asm', '{s}': {s}", .{ emit_asm.yes, @errorName(err) });
18361842 },
18371843 .yes_default_path => {
1838 fatal("unable to open directory from arguments 'name' or 'soname', '{s}': {s}", .{ default_asm_basename, @errorName(err) });
1844 fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ default_asm_basename, @errorName(err) });
18391845 },
18401846 .no => unreachable,
18411847 }
......@@ -1846,16 +1852,30 @@ fn buildOutputType(
18461852 var emit_llvm_ir_resolved = emit_llvm_ir.resolve(default_llvm_ir_basename) catch |err| {
18471853 switch (emit_llvm_ir) {
18481854 .yes => {
1849 fatal("unable to open directory from argument 'femit-llvm-ir', '{s}': {s}", .{ emit_llvm_ir.yes, @errorName(err) });
1855 fatal("unable to open directory from argument '-femit-llvm-ir', '{s}': {s}", .{ emit_llvm_ir.yes, @errorName(err) });
18501856 },
18511857 .yes_default_path => {
1852 fatal("unable to open directory from arguments 'name' or 'soname', '{s}': {s}", .{ default_llvm_ir_basename, @errorName(err) });
1858 fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ default_llvm_ir_basename, @errorName(err) });
18531859 },
18541860 .no => unreachable,
18551861 }
18561862 };
18571863 defer emit_llvm_ir_resolved.deinit();
18581864
1865 const default_llvm_bc_basename = try std.fmt.allocPrint(arena, "{s}.bc", .{root_name});
1866 var emit_llvm_bc_resolved = emit_llvm_bc.resolve(default_llvm_bc_basename) catch |err| {
1867 switch (emit_llvm_bc) {
1868 .yes => {
1869 fatal("unable to open directory from argument '-femit-llvm-bc', '{s}': {s}", .{ emit_llvm_bc.yes, @errorName(err) });
1870 },
1871 .yes_default_path => {
1872 fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ default_llvm_bc_basename, @errorName(err) });
1873 },
1874 .no => unreachable,
1875 }
1876 };
1877 defer emit_llvm_bc_resolved.deinit();
1878
18591879 const default_analysis_basename = try std.fmt.allocPrint(arena, "{s}-analysis.json", .{root_name});
18601880 var emit_analysis_resolved = emit_analysis.resolve(default_analysis_basename) catch |err| {
18611881 switch (emit_analysis) {
......@@ -1991,6 +2011,7 @@ fn buildOutputType(
19912011 .emit_h = emit_h_resolved.data,
19922012 .emit_asm = emit_asm_resolved.data,
19932013 .emit_llvm_ir = emit_llvm_ir_resolved.data,
2014 .emit_llvm_bc = emit_llvm_bc_resolved.data,
19942015 .emit_docs = emit_docs_resolved.data,
19952016 .emit_analysis = emit_analysis_resolved.data,
19962017 .link_mode = link_mode,
......@@ -2396,11 +2417,8 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi
23962417
23972418 // If a .pdb file is part of the expected output, we must also copy
23982419 // it into place here.
2399 const coff_or_pe = switch (comp.bin_file.options.object_format) {
2400 .coff, .pe => true,
2401 else => false,
2402 };
2403 const have_pdb = coff_or_pe and !comp.bin_file.options.strip;
2420 const is_coff = comp.bin_file.options.object_format == .coff;
2421 const have_pdb = is_coff and !comp.bin_file.options.strip;
24042422 if (have_pdb) {
24052423 // Replace `.out` or `.exe` with `.pdb` on both the source and destination
24062424 const src_bin_ext = fs.path.extension(bin_sub_path);
src/stage1.zig+3-1
......@@ -21,7 +21,6 @@ comptime {
2121 assert(build_options.is_stage1);
2222 assert(build_options.have_llvm);
2323 if (!builtin.is_test) {
24 _ = @import("compiler_rt");
2524 @export(main, .{ .name = "main" });
2625 }
2726}
......@@ -95,6 +94,8 @@ pub const Module = extern struct {
9594 emit_asm_len: usize,
9695 emit_llvm_ir_ptr: [*]const u8,
9796 emit_llvm_ir_len: usize,
97 emit_bitcode_ptr: [*]const u8,
98 emit_bitcode_len: usize,
9899 emit_analysis_json_ptr: [*]const u8,
99100 emit_analysis_json_len: usize,
100101 emit_docs_ptr: [*]const u8,
......@@ -124,6 +125,7 @@ pub const Module = extern struct {
124125 valgrind_enabled: bool,
125126 tsan_enabled: bool,
126127 function_sections: bool,
128 include_compiler_rt: bool,
127129 enable_stack_probing: bool,
128130 red_zone: bool,
129131 enable_time_report: bool,
src/stage1/all_types.hpp+2
......@@ -2090,6 +2090,7 @@ struct CodeGen {
20902090 Buf h_file_output_path;
20912091 Buf asm_file_output_path;
20922092 Buf llvm_ir_file_output_path;
2093 Buf bitcode_file_output_path;
20932094 Buf analysis_json_output_path;
20942095 Buf docs_output_path;
20952096
......@@ -2149,6 +2150,7 @@ struct CodeGen {
21492150 bool have_stack_probing;
21502151 bool red_zone;
21512152 bool function_sections;
2153 bool include_compiler_rt;
21522154 bool test_is_evented;
21532155 bool valgrind_enabled;
21542156 bool tsan_enabled;
src/stage1/codegen.cpp+27-6
......@@ -8506,19 +8506,22 @@ static void zig_llvm_emit_output(CodeGen *g) {
85068506 const char *asm_filename = nullptr;
85078507 const char *bin_filename = nullptr;
85088508 const char *llvm_ir_filename = nullptr;
8509 const char *bitcode_filename = nullptr;
85098510
85108511 if (buf_len(&g->o_file_output_path) != 0) bin_filename = buf_ptr(&g->o_file_output_path);
85118512 if (buf_len(&g->asm_file_output_path) != 0) asm_filename = buf_ptr(&g->asm_file_output_path);
85128513 if (buf_len(&g->llvm_ir_file_output_path) != 0) llvm_ir_filename = buf_ptr(&g->llvm_ir_file_output_path);
8514 if (buf_len(&g->bitcode_file_output_path) != 0) bitcode_filename = buf_ptr(&g->bitcode_file_output_path);
85138515
8514 // Unfortunately, LLVM shits the bed when we ask for both binary and assembly. So we call the entire
8515 // pipeline multiple times if this is requested.
8516 // Unfortunately, LLVM shits the bed when we ask for both binary and assembly.
8517 // So we call the entire pipeline multiple times if this is requested.
85168518 if (asm_filename != nullptr && bin_filename != nullptr) {
85178519 if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg,
85188520 g->build_mode == BuildModeDebug, is_small, g->enable_time_report, g->tsan_enabled,
8519 g->have_lto, nullptr, bin_filename, llvm_ir_filename))
8521 g->have_lto, nullptr, bin_filename, llvm_ir_filename, nullptr))
85208522 {
8521 fprintf(stderr, "LLVM failed to emit file: %s\n", err_msg);
8523 fprintf(stderr, "LLVM failed to emit bin=%s, ir=%s: %s\n",
8524 bin_filename, llvm_ir_filename, err_msg);
85228525 exit(1);
85238526 }
85248527 bin_filename = nullptr;
......@@ -8527,9 +8530,11 @@ static void zig_llvm_emit_output(CodeGen *g) {
85278530
85288531 if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg,
85298532 g->build_mode == BuildModeDebug, is_small, g->enable_time_report, g->tsan_enabled,
8530 g->have_lto, asm_filename, bin_filename, llvm_ir_filename))
8533 g->have_lto, asm_filename, bin_filename, llvm_ir_filename, bitcode_filename))
85318534 {
8532 fprintf(stderr, "LLVM failed to emit file: %s\n", err_msg);
8535 fprintf(stderr, "LLVM failed to emit asm=%s, bin=%s, ir=%s, bc=%s: %s\n",
8536 asm_filename, bin_filename, llvm_ir_filename, bitcode_filename,
8537 err_msg);
85338538 exit(1);
85348539 }
85358540
......@@ -9537,6 +9542,22 @@ static void gen_root_source(CodeGen *g) {
95379542 g->panic_fn = panic_fn_val->data.x_ptr.data.fn.fn_entry;
95389543 assert(g->panic_fn != nullptr);
95399544
9545 if (g->include_compiler_rt) {
9546 Buf *import_target_path;
9547 Buf full_path = BUF_INIT;
9548 ZigType *compiler_rt_import;
9549 if ((err = analyze_import(g, std_import, buf_create_from_str("./special/compiler_rt.zig"),
9550 &compiler_rt_import, &import_target_path, &full_path)))
9551 {
9552 if (err == ErrorFileNotFound) {
9553 fprintf(stderr, "unable to find '%s'", buf_ptr(import_target_path));
9554 } else {
9555 fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(&full_path), err_str(err));
9556 }
9557 exit(1);
9558 }
9559 }
9560
95409561 if (!g->error_during_imports) {
95419562 semantic_analyze(g);
95429563 }
src/stage1/stage1.cpp+2
......@@ -73,6 +73,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
7373 buf_init_from_mem(&g->h_file_output_path, stage1->emit_h_ptr, stage1->emit_h_len);
7474 buf_init_from_mem(&g->asm_file_output_path, stage1->emit_asm_ptr, stage1->emit_asm_len);
7575 buf_init_from_mem(&g->llvm_ir_file_output_path, stage1->emit_llvm_ir_ptr, stage1->emit_llvm_ir_len);
76 buf_init_from_mem(&g->bitcode_file_output_path, stage1->emit_bitcode_ptr, stage1->emit_bitcode_len);
7677 buf_init_from_mem(&g->analysis_json_output_path, stage1->emit_analysis_json_ptr, stage1->emit_analysis_json_len);
7778 buf_init_from_mem(&g->docs_output_path, stage1->emit_docs_ptr, stage1->emit_docs_len);
7879
......@@ -100,6 +101,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
100101 g->link_libc = stage1->link_libc;
101102 g->link_libcpp = stage1->link_libcpp;
102103 g->function_sections = stage1->function_sections;
104 g->include_compiler_rt = stage1->include_compiler_rt;
103105
104106 g->subsystem = stage1->subsystem;
105107
src/stage1/stage1.h+4
......@@ -157,6 +157,9 @@ struct ZigStage1 {
157157 const char *emit_llvm_ir_ptr;
158158 size_t emit_llvm_ir_len;
159159
160 const char *emit_bitcode_ptr;
161 size_t emit_bitcode_len;
162
160163 const char *emit_analysis_json_ptr;
161164 size_t emit_analysis_json_len;
162165
......@@ -193,6 +196,7 @@ struct ZigStage1 {
193196 bool valgrind_enabled;
194197 bool tsan_enabled;
195198 bool function_sections;
199 bool include_compiler_rt;
196200 bool enable_stack_probing;
197201 bool red_zone;
198202 bool enable_time_report;
src/stage1/zig0.cpp+5
......@@ -39,6 +39,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
3939 " --color [auto|off|on] enable or disable colored error messages\n"
4040 " --name [name] override output name\n"
4141 " -femit-bin=[path] Output machine code\n"
42 " -fcompiler-rt Always include compiler-rt symbols in output\n"
4243 " --pkg-begin [name] [path] make pkg available to import and push current pkg\n"
4344 " --pkg-end pop current pkg\n"
4445 " -ODebug build with optimizations off and safety on\n"
......@@ -266,6 +267,7 @@ int main(int argc, char **argv) {
266267 const char *mcpu = nullptr;
267268 bool single_threaded = false;
268269 bool is_test_build = false;
270 bool include_compiler_rt = false;
269271
270272 for (int i = 1; i < argc; i += 1) {
271273 char *arg = argv[i];
......@@ -334,6 +336,8 @@ int main(int argc, char **argv) {
334336 mcpu = arg + strlen("-mcpu=");
335337 } else if (str_starts_with(arg, "-femit-bin=")) {
336338 emit_bin_path = arg + strlen("-femit-bin=");
339 } else if (strcmp(arg, "-fcompiler-rt") == 0) {
340 include_compiler_rt = true;
337341 } else if (i + 1 >= argc) {
338342 fprintf(stderr, "Expected another argument after %s\n", arg);
339343 return print_error_usage(arg0);
......@@ -468,6 +472,7 @@ int main(int argc, char **argv) {
468472 stage1->subsystem = subsystem;
469473 stage1->pic = true;
470474 stage1->is_single_threaded = single_threaded;
475 stage1->include_compiler_rt = include_compiler_rt;
471476
472477 zig_stage1_build_object(stage1);
473478
src/zig_llvm.cpp+17-2
......@@ -229,12 +229,14 @@ struct TimeTracerRAII {
229229bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
230230 char **error_message, bool is_debug,
231231 bool is_small, bool time_report, bool tsan, bool lto,
232 const char *asm_filename, const char *bin_filename, const char *llvm_ir_filename)
232 const char *asm_filename, const char *bin_filename,
233 const char *llvm_ir_filename, const char *bitcode_filename)
233234{
234235 TimePassesIsEnabled = time_report;
235236
236237 raw_fd_ostream *dest_asm_ptr = nullptr;
237238 raw_fd_ostream *dest_bin_ptr = nullptr;
239 raw_fd_ostream *dest_bitcode_ptr = nullptr;
238240
239241 if (asm_filename) {
240242 std::error_code EC;
......@@ -252,9 +254,19 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
252254 return true;
253255 }
254256 }
257 if (bitcode_filename) {
258 std::error_code EC;
259 dest_bitcode_ptr = new(std::nothrow) raw_fd_ostream(bitcode_filename, EC, sys::fs::F_None);
260 if (EC) {
261 *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin());
262 return true;
263 }
264 }
255265
256266 std::unique_ptr<raw_fd_ostream> dest_asm(dest_asm_ptr),
257 dest_bin(dest_bin_ptr);
267 dest_bin(dest_bin_ptr),
268 dest_bitcode(dest_bitcode_ptr);
269
258270
259271 auto PID = sys::Process::getProcessId();
260272 std::string ProcName = "zig-";
......@@ -389,6 +401,9 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
389401 if (dest_bin && lto) {
390402 WriteBitcodeToFile(module, *dest_bin);
391403 }
404 if (dest_bitcode) {
405 WriteBitcodeToFile(module, *dest_bitcode);
406 }
392407
393408 if (time_report) {
394409 TimerGroup::printAll(errs());
src/zig_llvm.h+2-1
......@@ -49,7 +49,8 @@ ZIG_EXTERN_C char *ZigLLVMGetNativeFeatures(void);
4949ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
5050 char **error_message, bool is_debug,
5151 bool is_small, bool time_report, bool tsan, bool lto,
52 const char *asm_filename, const char *bin_filename, const char *llvm_ir_filename);
52 const char *asm_filename, const char *bin_filename,
53 const char *llvm_ir_filename, const char *bitcode_filename);
5354
5455
5556enum ZigLLVMABIType {