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...@@ -796,6 +796,7 @@ set(BUILD_ZIG1_ARGS
796 --name zig1796 --name zig1
797 --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib"797 --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib"
798 "-femit-bin=${ZIG1_OBJECT}"798 "-femit-bin=${ZIG1_OBJECT}"
799 -fcompiler-rt
799 "${ZIG1_RELEASE_ARG}"800 "${ZIG1_RELEASE_ARG}"
800 "${ZIG1_SINGLE_THREADED_ARG}"801 "${ZIG1_SINGLE_THREADED_ARG}"
801 -lc802 -lc
doc/docgen.zig+4-4
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = std.builtin;2const builtin = @import("builtin");
3const io = std.io;3const io = std.io;
4const fs = std.fs;4const fs = std.fs;
5const process = std.process;5const process = std.process;
...@@ -13,7 +13,7 @@ const Allocator = std.mem.Allocator;...@@ -13,7 +13,7 @@ const Allocator = std.mem.Allocator;
13const max_doc_file_size = 10 * 1024 * 1024;13const max_doc_file_size = 10 * 1024 * 1024;
1414
15const exe_ext = @as(std.zig.CrossTarget, .{}).exeFileExt();15const 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);
17const tmp_dir_name = "docgen_tmp";17const tmp_dir_name = "docgen_tmp";
18const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext;18const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext;
1919
...@@ -281,7 +281,7 @@ const Code = struct {...@@ -281,7 +281,7 @@ const Code = struct {
281 name: []const u8,281 name: []const u8,
282 source_token: Token,282 source_token: Token,
283 is_inline: bool,283 is_inline: bool,
284 mode: builtin.Mode,284 mode: std.builtin.Mode,
285 link_objects: []const []const u8,285 link_objects: []const []const u8,
286 target_str: ?[]const u8,286 target_str: ?[]const u8,
287 link_libc: bool,287 link_libc: bool,
...@@ -531,7 +531,7 @@ fn genToc(allocator: *Allocator, tokenizer: *Tokenizer) !Toc {...@@ -531,7 +531,7 @@ fn genToc(allocator: *Allocator, tokenizer: *Tokenizer) !Toc {
531 return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {s}", .{code_kind_str});531 return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {s}", .{code_kind_str});
532 }532 }
533533
534 var mode: builtin.Mode = .Debug;534 var mode: std.builtin.Mode = .Debug;
535 var link_objects = std.ArrayList([]const u8).init(allocator);535 var link_objects = std.ArrayList([]const u8).init(allocator);
536 defer link_objects.deinit();536 defer link_objects.deinit();
537 var target_str: ?[]const u8 = null;537 var target_str: ?[]const u8 = null;
lib/std/target.zig+63-37
...@@ -549,16 +549,36 @@ pub const Target = struct {...@@ -549,16 +549,36 @@ pub const Target = struct {
549 };549 };
550550
551 pub const ObjectFormat = enum {551 pub const ObjectFormat = enum {
552 /// Common Object File Format (Windows)
552 coff,553 coff,
553 pe,554 /// Executable and Linking Format
554 elf,555 elf,
556 /// macOS relocatables
555 macho,557 macho,
558 /// WebAssembly
556 wasm,559 wasm,
560 /// C source code
557 c,561 c,
562 /// Standard, Portable Intermediate Representation V
558 spirv,563 spirv,
564 /// Intel IHEX
559 hex,565 hex,
566 /// Machine code with no metadata.
560 raw,567 raw,
568 /// Plan 9 from Bell Labs
561 plan9,569 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 }
562 };582 };
563583
564 pub const SubSystem = enum {584 pub const SubSystem = enum {
...@@ -1290,30 +1310,16 @@ pub const Target = struct {...@@ -1290,30 +1310,16 @@ pub const Target = struct {
1290 return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi);1310 return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi);
1291 }1311 }
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
1307 pub fn exeFileExtSimple(cpu_arch: Cpu.Arch, os_tag: Os.Tag) [:0]const u8 {1313 pub fn exeFileExtSimple(cpu_arch: Cpu.Arch, os_tag: Os.Tag) [:0]const u8 {
1308 switch (os_tag) {1314 return switch (os_tag) {
1309 .windows => return ".exe",1315 .windows => ".exe",
1310 .uefi => return ".efi",1316 .uefi => ".efi",
1311 else => if (cpu_arch.isWasm()) {1317 .plan9 => plan9Ext(cpu_arch),
1312 return ".wasm";1318 else => switch (cpu_arch) {
1313 } else {1319 .wasm32, .wasm64 => ".wasm",
1314 return "";1320 else => "",
1315 },1321 },
1316 }1322 };
1317 }1323 }
13181324
1319 pub fn exeFileExt(self: Target) [:0]const u8 {1325 pub fn exeFileExt(self: Target) [:0]const u8 {
...@@ -1353,20 +1359,16 @@ pub const Target = struct {...@@ -1353,20 +1359,16 @@ pub const Target = struct {
1353 }1359 }
13541360
1355 pub fn getObjectFormatSimple(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat {1361 pub fn getObjectFormatSimple(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat {
1356 if (os_tag == .windows or os_tag == .uefi) {1362 return switch (os_tag) {
1357 return .coff;1363 .windows, .uefi => .coff,
1358 } else if (os_tag.isDarwin()) {1364 .ios, .macos, .watchos, .tvos => .macho,
1359 return .macho;1365 .plan9 => .plan9,
1360 }1366 else => return switch (cpu_arch) {
1361 if (cpu_arch.isWasm()) {1367 .wasm32, .wasm64 => .wasm,
1362 return .wasm;1368 .spirv32, .spirv64 => .spirv,
1363 }1369 else => .elf,
1364 if (cpu_arch.isSPIRV()) {1370 },
1365 return .spirv;1371 };
1366 }
1367 if (os_tag == .plan9)
1368 return .plan9;
1369 return .elf;
1370 }1372 }
13711373
1372 pub fn getObjectFormat(self: Target) ObjectFormat {1374 pub fn getObjectFormat(self: Target) ObjectFormat {
...@@ -1677,6 +1679,30 @@ pub const Target = struct {...@@ -1677,6 +1679,30 @@ pub const Target = struct {
16771679
1678 return false;1680 return false;
1679 }1681 }
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 }
1680};1706};
16811707
1682test {1708test {
lib/std/zig.zig+10-30
...@@ -108,8 +108,9 @@ pub const BinNameOptions = struct {...@@ -108,8 +108,9 @@ pub const BinNameOptions = struct {
108pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) error{OutOfMemory}![]u8 {108pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) error{OutOfMemory}![]u8 {
109 const root_name = options.root_name;109 const root_name = options.root_name;
110 const target = options.target;110 const target = options.target;
111 switch (options.object_format orelse target.getObjectFormat()) {111 const ofmt = options.object_format orelse target.getObjectFormat();
112 .coff, .pe => switch (options.output_mode) {112 switch (ofmt) {
113 .coff => switch (options.output_mode) {
113 .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.exeFileExt() }),114 .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.exeFileExt() }),
114 .Lib => {115 .Lib => {
115 const suffix = switch (options.link_mode orelse .Static) {116 const suffix = switch (options.link_mode orelse .Static) {
...@@ -118,7 +119,7 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro...@@ -118,7 +119,7 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro
118 };119 };
119 return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, suffix });120 return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, suffix });
120 },121 },
121 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.oFileExt() }),122 .Obj => return std.fmt.allocPrint(allocator, "{s}.obj", .{root_name}),
122 },123 },
123 .elf => switch (options.output_mode) {124 .elf => switch (options.output_mode) {
124 .Exe => return allocator.dupe(u8, root_name),125 .Exe => return allocator.dupe(u8, root_name),
...@@ -140,7 +141,7 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro...@@ -140,7 +141,7 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro
140 },141 },
141 }142 }
142 },143 },
143 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.oFileExt() }),144 .Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}),
144 },145 },
145 .macho => switch (options.output_mode) {146 .macho => switch (options.output_mode) {
146 .Exe => return allocator.dupe(u8, root_name),147 .Exe => return allocator.dupe(u8, root_name),
...@@ -163,7 +164,7 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro...@@ -163,7 +164,7 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro
163 }164 }
164 return std.fmt.allocPrint(allocator, "{s}{s}{s}", .{ target.libPrefix(), root_name, suffix });165 return std.fmt.allocPrint(allocator, "{s}{s}{s}", .{ target.libPrefix(), root_name, suffix });
165 },166 },
166 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.oFileExt() }),167 .Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}),
167 },168 },
168 .wasm => switch (options.output_mode) {169 .wasm => switch (options.output_mode) {
169 .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.exeFileExt() }),170 .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...@@ -175,36 +176,15 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro
175 .Dynamic => return std.fmt.allocPrint(allocator, "{s}.wasm", .{root_name}),176 .Dynamic => return std.fmt.allocPrint(allocator, "{s}.wasm", .{root_name}),
176 }177 }
177 },178 },
178 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.oFileExt() }),179 .Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}),
179 },180 },
180 .c => return std.fmt.allocPrint(allocator, "{s}.c", .{root_name}),181 .c => return std.fmt.allocPrint(allocator, "{s}.c", .{root_name}),
181 .spirv => return std.fmt.allocPrint(allocator, "{s}.spv", .{root_name}),182 .spirv => return std.fmt.allocPrint(allocator, "{s}.spv", .{root_name}),
182 .hex => return std.fmt.allocPrint(allocator, "{s}.ihex", .{root_name}),183 .hex => return std.fmt.allocPrint(allocator, "{s}.ihex", .{root_name}),
183 .raw => return std.fmt.allocPrint(allocator, "{s}.bin", .{root_name}),184 .raw => return std.fmt.allocPrint(allocator, "{s}.bin", .{root_name}),
184 .plan9 => {185 .plan9 => return std.fmt.allocPrint(allocator, "{s}{s}", .{
185 // copied from 2c(1)186 root_name, ofmt.fileExt(target.cpu.arch),
186 // 0c spim little-endian MIPS 3000 family187 }),
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 },
208 }188 }
209}189}
210190
lib/std/zig/cross_target.zig-4
...@@ -473,10 +473,6 @@ pub const CrossTarget = struct {...@@ -473,10 +473,6 @@ pub const CrossTarget = struct {
473 return self.getOsTag() == .windows;473 return self.getOsTag() == .windows;
474 }474 }
475475
476 pub fn oFileExt(self: CrossTarget) [:0]const u8 {
477 return Target.oFileExt_os_abi(self.getOsTag(), self.getAbi());
478 }
479
480 pub fn exeFileExt(self: CrossTarget) [:0]const u8 {476 pub fn exeFileExt(self: CrossTarget) [:0]const u8 {
481 return Target.exeFileExtSimple(self.getCpuArch(), self.getOsTag());477 return Target.exeFileExtSimple(self.getCpuArch(), self.getOsTag());
482 }478 }
src/Compilation.zig+58-17
...@@ -143,6 +143,7 @@ debug_compiler_runtime_libs: bool,...@@ -143,6 +143,7 @@ debug_compiler_runtime_libs: bool,
143143
144emit_asm: ?EmitLoc,144emit_asm: ?EmitLoc,
145emit_llvm_ir: ?EmitLoc,145emit_llvm_ir: ?EmitLoc,
146emit_llvm_bc: ?EmitLoc,
146emit_analysis: ?EmitLoc,147emit_analysis: ?EmitLoc,
147emit_docs: ?EmitLoc,148emit_docs: ?EmitLoc,
148149
...@@ -586,6 +587,17 @@ pub const Directory = struct {...@@ -586,6 +587,17 @@ pub const Directory = struct {
586 return std.fs.path.join(allocator, paths);587 return std.fs.path.join(allocator, paths);
587 }588 }
588 }589 }
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 }
589};601};
590602
591pub const EmitLoc = struct {603pub const EmitLoc = struct {
...@@ -623,6 +635,8 @@ pub const InitOptions = struct {...@@ -623,6 +635,8 @@ pub const InitOptions = struct {
623 emit_asm: ?EmitLoc = null,635 emit_asm: ?EmitLoc = null,
624 /// `null` means to not emit LLVM IR.636 /// `null` means to not emit LLVM IR.
625 emit_llvm_ir: ?EmitLoc = null,637 emit_llvm_ir: ?EmitLoc = null,
638 /// `null` means to not emit LLVM module bitcode.
639 emit_llvm_bc: ?EmitLoc = null,
626 /// `null` means to not emit semantic analysis JSON.640 /// `null` means to not emit semantic analysis JSON.
627 emit_analysis: ?EmitLoc = null,641 emit_analysis: ?EmitLoc = null,
628 /// `null` means to not emit docs.642 /// `null` means to not emit docs.
...@@ -812,6 +826,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -812,6 +826,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
812 const ofmt = options.object_format orelse options.target.getObjectFormat();826 const ofmt = options.object_format orelse options.target.getObjectFormat();
813827
814 const use_stage1 = options.use_stage1 orelse blk: {828 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
815 if (build_options.omit_stage2)832 if (build_options.omit_stage2)
816 break :blk true;833 break :blk true;
817 if (options.use_llvm) |use_llvm| {834 if (options.use_llvm) |use_llvm| {
...@@ -819,6 +836,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -819,6 +836,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
819 break :blk false;836 break :blk false;
820 }837 }
821 }838 }
839
822 break :blk build_options.is_stage1;840 break :blk build_options.is_stage1;
823 };841 };
824842
...@@ -835,6 +853,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -835,6 +853,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
835 if (ofmt == .c)853 if (ofmt == .c)
836 break :blk false;854 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
838 // The stage1 compiler depends on the stage1 C++ LLVM backend860 // The stage1 compiler depends on the stage1 C++ LLVM backend
839 // to compile zig code.861 // to compile zig code.
840 if (use_stage1)862 if (use_stage1)
...@@ -853,6 +875,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -853,6 +875,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
853 if (options.machine_code_model != .default) {875 if (options.machine_code_model != .default) {
854 return error.MachineCodeModelNotSupportedWithoutLlvm;876 return error.MachineCodeModelNotSupportedWithoutLlvm;
855 }877 }
878 if (options.emit_llvm_ir != null or options.emit_llvm_bc != null) {
879 return error.EmittingLlvmModuleRequiresUsingLlvmBackend;
880 }
856 }881 }
857882
858 const tsan = options.want_tsan orelse false;883 const tsan = options.want_tsan orelse false;
...@@ -1381,6 +1406,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -1381,6 +1406,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
1381 .bin_file = bin_file,1406 .bin_file = bin_file,
1382 .emit_asm = options.emit_asm,1407 .emit_asm = options.emit_asm,
1383 .emit_llvm_ir = options.emit_llvm_ir,1408 .emit_llvm_ir = options.emit_llvm_ir,
1409 .emit_llvm_bc = options.emit_llvm_bc,
1384 .emit_analysis = options.emit_analysis,1410 .emit_analysis = options.emit_analysis,
1385 .emit_docs = options.emit_docs,1411 .emit_docs = options.emit_docs,
1386 .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),1412 .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
...@@ -1513,24 +1539,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -1513,24 +1539,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
1513 }1539 }
15141540
1515 // The `use_stage1` condition is here only because stage2 cannot yet build compiler-rt.1541 // 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.
1517 if (comp.bin_file.options.use_stage1) {1546 if (comp.bin_file.options.use_stage1) {
1518 if (comp.bin_file.options.include_compiler_rt) {1547 if (comp.bin_file.options.include_compiler_rt) {
1519 if (is_exe_or_dyn_lib) {1548 if (is_exe_or_dyn_lib) {
1520 try comp.work_queue.writeItem(.{ .compiler_rt_lib = {} });1549 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.
1522 try comp.work_queue.writeItem(.{ .compiler_rt_obj = {} });1554 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 }
1534 }1555 }
1535 }1556 }
1536 if (needs_c_symbols) {1557 if (needs_c_symbols) {
...@@ -2728,7 +2749,10 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P...@@ -2728,7 +2749,10 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
2728 comp.bin_file.options.root_name2749 comp.bin_file.options.root_name
2729 else2750 else
2730 c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len];2751 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
2733 const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: {2757 const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: {
2734 var argv = std.ArrayList([]const u8).init(comp.gpa);2758 var argv = std.ArrayList([]const u8).init(comp.gpa);
...@@ -3023,7 +3047,7 @@ pub fn addCCArgs(...@@ -3023,7 +3047,7 @@ pub fn addCCArgs(
3023 if (!comp.bin_file.options.strip) {3047 if (!comp.bin_file.options.strip) {
3024 try argv.append("-g");3048 try argv.append("-g");
3025 switch (comp.bin_file.options.object_format) {3049 switch (comp.bin_file.options.object_format) {
3026 .coff, .pe => try argv.append("-gcodeview"),3050 .coff => try argv.append("-gcodeview"),
3027 else => {},3051 else => {},
3028 }3052 }
3029 }3053 }
...@@ -3949,6 +3973,16 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -3949,6 +3973,16 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
3949 const id_symlink_basename = "stage1.id";3973 const id_symlink_basename = "stage1.id";
3950 const libs_txt_basename = "libs.txt";3974 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
3952 // We are about to obtain this lock, so here we give other processes a chance first.3986 // We are about to obtain this lock, so here we give other processes a chance first.
3953 comp.releaseStage1Lock();3987 comp.releaseStage1Lock();
39543988
...@@ -3970,6 +4004,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -3970,6 +4004,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
3970 man.hash.add(target.os.getVersionRange());4004 man.hash.add(target.os.getVersionRange());
3971 man.hash.add(comp.bin_file.options.dll_export_fns);4005 man.hash.add(comp.bin_file.options.dll_export_fns);
3972 man.hash.add(comp.bin_file.options.function_sections);4006 man.hash.add(comp.bin_file.options.function_sections);
4007 man.hash.add(include_compiler_rt);
3973 man.hash.add(comp.bin_file.options.is_test);4008 man.hash.add(comp.bin_file.options.is_test);
3974 man.hash.add(comp.bin_file.options.emit != null);4009 man.hash.add(comp.bin_file.options.emit != null);
3975 man.hash.add(mod.emit_h != null);4010 man.hash.add(mod.emit_h != null);
...@@ -3978,6 +4013,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -3978,6 +4013,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
3978 }4013 }
3979 man.hash.addOptionalEmitLoc(comp.emit_asm);4014 man.hash.addOptionalEmitLoc(comp.emit_asm);
3980 man.hash.addOptionalEmitLoc(comp.emit_llvm_ir);4015 man.hash.addOptionalEmitLoc(comp.emit_llvm_ir);
4016 man.hash.addOptionalEmitLoc(comp.emit_llvm_bc);
3981 man.hash.addOptionalEmitLoc(comp.emit_analysis);4017 man.hash.addOptionalEmitLoc(comp.emit_analysis);
3982 man.hash.addOptionalEmitLoc(comp.emit_docs);4018 man.hash.addOptionalEmitLoc(comp.emit_docs);
3983 man.hash.add(comp.test_evented_io);4019 man.hash.add(comp.test_evented_io);
...@@ -4083,13 +4119,14 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -4083,13 +4119,14 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
4083 ) orelse return error.OutOfMemory;4119 ) orelse return error.OutOfMemory;
40844120
4085 const emit_bin_path = if (comp.bin_file.options.emit != null) blk: {4121 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, .{
4087 .root_name = comp.bin_file.options.root_name,4123 .root_name = comp.bin_file.options.root_name,
4088 .target = target,4124 .target = target,
4089 .output_mode = .Obj,4125 .output_mode = .Obj,
4090 });4126 });
4091 break :blk try directory.join(arena, &[_][]const u8{bin_basename});4127 break :blk try directory.join(arena, &[_][]const u8{obj_basename});
4092 } else "";4128 } else "";
4129
4093 if (mod.emit_h != null) {4130 if (mod.emit_h != null) {
4094 log.warn("-femit-h is not available in the stage1 backend; no .h file will be produced", .{});4131 log.warn("-femit-h is not available in the stage1 backend; no .h file will be produced", .{});
4095 }4132 }
...@@ -4097,6 +4134,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -4097,6 +4134,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
4097 const emit_h_path = try stage1LocPath(arena, emit_h_loc, directory);4134 const emit_h_path = try stage1LocPath(arena, emit_h_loc, directory);
4098 const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory);4135 const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory);
4099 const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory);4136 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);
4100 const emit_analysis_path = try stage1LocPath(arena, comp.emit_analysis, directory);4138 const emit_analysis_path = try stage1LocPath(arena, comp.emit_analysis, directory);
4101 const emit_docs_path = try stage1LocPath(arena, comp.emit_docs, directory);4139 const emit_docs_path = try stage1LocPath(arena, comp.emit_docs, directory);
4102 const stage1_pkg = try createStage1Pkg(arena, "root", mod.root_pkg, null);4140 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...@@ -4117,6 +4155,8 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
4117 .emit_asm_len = emit_asm_path.len,4155 .emit_asm_len = emit_asm_path.len,
4118 .emit_llvm_ir_ptr = emit_llvm_ir_path.ptr,4156 .emit_llvm_ir_ptr = emit_llvm_ir_path.ptr,
4119 .emit_llvm_ir_len = emit_llvm_ir_path.len,4157 .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,
4120 .emit_analysis_json_ptr = emit_analysis_path.ptr,4160 .emit_analysis_json_ptr = emit_analysis_path.ptr,
4121 .emit_analysis_json_len = emit_analysis_path.len,4161 .emit_analysis_json_len = emit_analysis_path.len,
4122 .emit_docs_ptr = emit_docs_path.ptr,4162 .emit_docs_ptr = emit_docs_path.ptr,
...@@ -4145,6 +4185,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -4145,6 +4185,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
4145 .valgrind_enabled = comp.bin_file.options.valgrind,4185 .valgrind_enabled = comp.bin_file.options.valgrind,
4146 .tsan_enabled = comp.bin_file.options.tsan,4186 .tsan_enabled = comp.bin_file.options.tsan,
4147 .function_sections = comp.bin_file.options.function_sections,4187 .function_sections = comp.bin_file.options.function_sections,
4188 .include_compiler_rt = include_compiler_rt,
4148 .enable_stack_probing = comp.bin_file.options.stack_check,4189 .enable_stack_probing = comp.bin_file.options.stack_check,
4149 .red_zone = comp.bin_file.options.red_zone,4190 .red_zone = comp.bin_file.options.red_zone,
4150 .enable_time_report = comp.time_report,4191 .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 {...@@ -72,9 +72,9 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {
72 .renderscript32 => "renderscript32",72 .renderscript32 => "renderscript32",
73 .renderscript64 => "renderscript64",73 .renderscript64 => "renderscript64",
74 .ve => "ve",74 .ve => "ve",
75 .spu_2 => return error.LLVMBackendDoesNotSupportSPUMarkII,75 .spu_2 => return error.@"LLVM backend does not support SPU Mark II",
76 .spirv32 => return error.LLVMBackendDoesNotSupportSPIRV,76 .spirv32 => return error.@"LLVM backend does not support SPIR-V",
77 .spirv64 => return error.LLVMBackendDoesNotSupportSPIRV,77 .spirv64 => return error.@"LLVM backend does not support SPIR-V",
78 };78 };
7979
80 const llvm_os = switch (target.os.tag) {80 const llvm_os = switch (target.os.tag) {
...@@ -114,11 +114,13 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {...@@ -114,11 +114,13 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {
114 .wasi => "wasi",114 .wasi => "wasi",
115 .emscripten => "emscripten",115 .emscripten => "emscripten",
116 .uefi => "windows",116 .uefi => "windows",
117 .opencl => return error.LLVMBackendDoesNotSupportOpenCL,117
118 .glsl450 => return error.LLVMBackendDoesNotSupportGLSL450,118 .opencl,
119 .vulkan => return error.LLVMBackendDoesNotSupportVulkan,119 .glsl450,
120 .plan9 => return error.LLVMBackendDoesNotSupportPlan9,120 .vulkan,
121 .other => "unknown",121 .plan9,
122 .other,
123 => "unknown",
122 };124 };
123125
124 const llvm_abi = switch (target.abi) {126 const llvm_abi = switch (target.abi) {
...@@ -152,84 +154,105 @@ pub const Object = struct {...@@ -152,84 +154,105 @@ pub const Object = struct {
152 llvm_module: *const llvm.Module,154 llvm_module: *const llvm.Module,
153 context: *const llvm.Context,155 context: *const llvm.Context,
154 target_machine: *const llvm.TargetMachine,156 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;158 pub fn create(gpa: *Allocator, options: link.Options) !*Object {
170 const object_path = try o_directory.join(allocator, &[_][]const u8{obj_basename});159 const obj = try gpa.create(Object);
171 defer allocator.free(object_path);160 errdefer gpa.destroy(obj);
172161 obj.* = try Object.init(gpa, options);
173 const object_pathZ = try allocator.dupeZ(u8, object_path);162 return obj;
174 errdefer allocator.free(object_pathZ);163 }
175164
165 pub fn init(gpa: *Allocator, options: link.Options) !Object {
176 const context = llvm.Context.create();166 const context = llvm.Context.create();
177 errdefer context.dispose();167 errdefer context.dispose();
178168
179 initializeLLVMTargets();169 initializeLLVMTargets();
180170
181 const root_nameZ = try allocator.dupeZ(u8, options.root_name);171 const root_nameZ = try gpa.dupeZ(u8, options.root_name);
182 defer allocator.free(root_nameZ);172 defer gpa.free(root_nameZ);
183 const llvm_module = llvm.Module.createWithName(root_nameZ.ptr, context);173 const llvm_module = llvm.Module.createWithName(root_nameZ.ptr, context);
184 errdefer llvm_module.dispose();174 errdefer llvm_module.dispose();
185175
186 const llvm_target_triple = try targetTriple(allocator, options.target);176 const llvm_target_triple = try targetTriple(gpa, options.target);
187 defer allocator.free(llvm_target_triple);177 defer gpa.free(llvm_target_triple);
188178
189 var error_message: [*:0]const u8 = undefined;179 var error_message: [*:0]const u8 = undefined;
190 var target: *const llvm.Target = undefined;180 var target: *const llvm.Target = undefined;
191 if (llvm.Target.getFromTriple(llvm_target_triple.ptr, &target, &error_message).toBool()) {181 if (llvm.Target.getFromTriple(llvm_target_triple.ptr, &target, &error_message).toBool()) {
192 defer llvm.disposeMessage(error_message);182 defer llvm.disposeMessage(error_message);
193183
194 const stderr = std.io.getStdErr().writer();184 log.err("LLVM failed to parse '{s}': {s}", .{ llvm_target_triple, error_message });
195 try stderr.print(185 return error.InvalidLlvmTriple;
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;
203 }186 }
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
206 const target_machine = llvm.TargetMachine.create(225 const target_machine = llvm.TargetMachine.create(
207 target,226 target,
208 llvm_target_triple.ptr,227 llvm_target_triple.ptr,
209 "",228 if (options.target.cpu.model.llvm_name) |s| s.ptr else null,
210 "",229 options.llvm_cpu_features,
211 opt_level,230 opt_level,
212 .Static,231 reloc_mode,
213 .Default,232 code_model,
233 options.function_sections,
234 float_abi,
235 abi_name,
214 );236 );
215 errdefer target_machine.dispose();237 errdefer target_machine.dispose();
216238
217 self.* = .{239 return Object{
218 .llvm_module = llvm_module,240 .llvm_module = llvm_module,
219 .context = context,241 .context = context,
220 .target_machine = target_machine,242 .target_machine = target_machine,
221 .object_pathZ = object_pathZ,
222 };243 };
223 return self;
224 }244 }
225245
226 pub fn deinit(self: *Object, allocator: *Allocator) void {246 pub fn deinit(self: *Object) void {
227 self.target_machine.dispose();247 self.target_machine.dispose();
228 self.llvm_module.dispose();248 self.llvm_module.dispose();
229 self.context.dispose();249 self.context.dispose();
250 self.* = undefined;
251 }
230252
231 allocator.free(self.object_pathZ);253 pub fn destroy(self: *Object, gpa: *Allocator) void {
232 allocator.destroy(self);254 self.deinit();
255 gpa.destroy(self);
233 }256 }
234257
235 fn initializeLLVMTargets() void {258 fn initializeLLVMTargets() void {
...@@ -240,38 +263,81 @@ pub const Object = struct {...@@ -240,38 +263,81 @@ pub const Object = struct {
240 llvm.initializeAllAsmParsers();263 llvm.initializeAllAsmParsers();
241 }264 }
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
243 pub fn flushModule(self: *Object, comp: *Compilation) !void {277 pub fn flushModule(self: *Object, comp: *Compilation) !void {
244 if (comp.verbose_llvm_ir) {278 if (comp.verbose_llvm_ir) {
245 const dump = self.llvm_module.printToString();279 self.llvm_module.dump();
246 defer llvm.disposeMessage(dump);
247
248 const stderr = std.io.getStdErr().writer();
249 try stderr.writeAll(std.mem.spanZ(dump));
250 }280 }
251281
252 {282 if (std.debug.runtime_safety) {
253 var error_message: [*:0]const u8 = undefined;283 var error_message: [*:0]const u8 = undefined;
254 // verifyModule always allocs the error_message even if there is no error284 // verifyModule always allocs the error_message even if there is no error
255 defer llvm.disposeMessage(error_message);285 defer llvm.disposeMessage(error_message);
256286
257 if (self.llvm_module.verify(.ReturnStatus, &error_message).toBool()) {287 if (self.llvm_module.verify(.ReturnStatus, &error_message).toBool()) {
258 const stderr = std.io.getStdErr().writer();288 std.debug.print("\n{s}\n", .{error_message});
259 try stderr.print("broken LLVM module found: {s}\nThis is a bug in the Zig compiler.", .{error_message});289 @panic("LLVM module verification failed");
260 return error.BrokenLLVMModule;
261 }290 }
262 }291 }
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
264 var error_message: [*:0]const u8 = undefined;317 var error_message: [*:0]const u8 = undefined;
265 if (self.target_machine.emitToFile(318 if (self.target_machine.emitToFile(
266 self.llvm_module,319 self.llvm_module,
267 self.object_pathZ.ptr,
268 .ObjectFile,
269 &error_message,320 &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 )) {
271 defer llvm.disposeMessage(error_message);331 defer llvm.disposeMessage(error_message);
272332
273 const stderr = std.io.getStdErr().writer();333 const emit_asm_msg = emit_asm_path orelse "(none)";
274 try stderr.print("LLVM failed to emit file: {s}\n", .{error_message});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 });
275 return error.FailedToEmit;341 return error.FailedToEmit;
276 }342 }
277 }343 }
src/codegen/llvm/bindings.zig+35-13
...@@ -123,6 +123,9 @@ pub const Module = opaque {...@@ -123,6 +123,9 @@ pub const Module = opaque {
123123
124 pub const getNamedGlobal = LLVMGetNamedGlobal;124 pub const getNamedGlobal = LLVMGetNamedGlobal;
125 extern fn LLVMGetNamedGlobal(M: *const Module, Name: [*:0]const u8) ?*const Value;125 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;
126};129};
127130
128pub const lookupIntrinsicID = LLVMLookupIntrinsicID;131pub const lookupIntrinsicID = LLVMLookupIntrinsicID;
...@@ -250,31 +253,41 @@ pub const BasicBlock = opaque {...@@ -250,31 +253,41 @@ pub const BasicBlock = opaque {
250};253};
251254
252pub const TargetMachine = opaque {255pub const TargetMachine = opaque {
253 pub const create = LLVMCreateTargetMachine;256 pub const create = ZigLLVMCreateTargetMachine;
254 extern fn LLVMCreateTargetMachine(257 extern fn ZigLLVMCreateTargetMachine(
255 T: *const Target,258 T: *const Target,
256 Triple: [*:0]const u8,259 Triple: [*:0]const u8,
257 CPU: [*:0]const u8,260 CPU: ?[*:0]const u8,
258 Features: [*:0]const u8,261 Features: ?[*:0]const u8,
259 Level: CodeGenOptLevel,262 Level: CodeGenOptLevel,
260 Reloc: RelocMode,263 Reloc: RelocMode,
261 CodeModel: CodeMode,264 CodeModel: CodeModel,
265 function_sections: bool,
266 float_abi: ABIType,
267 abi_name: ?[*:0]const u8,
262 ) *const TargetMachine;268 ) *const TargetMachine;
263269
264 pub const dispose = LLVMDisposeTargetMachine;270 pub const dispose = LLVMDisposeTargetMachine;
265 extern fn LLVMDisposeTargetMachine(T: *const TargetMachine) void;271 extern fn LLVMDisposeTargetMachine(T: *const TargetMachine) void;
266272
267 pub const emitToFile = LLVMTargetMachineEmitToFile;273 pub const emitToFile = ZigLLVMTargetMachineEmitToFile;
268 extern fn LLVMTargetMachineEmitToFile(274 extern fn ZigLLVMTargetMachineEmitToFile(
269 *const TargetMachine,275 T: *const TargetMachine,
270 M: *const Module,276 M: *const Module,
271 Filename: [*:0]const u8,
272 codegen: CodeGenFileType,
273 ErrorMessage: *[*:0]const u8,277 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;
275};288};
276289
277pub const CodeMode = enum(c_int) {290pub const CodeModel = enum(c_int) {
278 Default,291 Default,
279 JITDefault,292 JITDefault,
280 Tiny,293 Tiny,
...@@ -295,7 +308,7 @@ pub const RelocMode = enum(c_int) {...@@ -295,7 +308,7 @@ pub const RelocMode = enum(c_int) {
295 Default,308 Default,
296 Static,309 Static,
297 PIC,310 PIC,
298 DynamicNoPic,311 DynamicNoPIC,
299 ROPI,312 ROPI,
300 RWPI,313 RWPI,
301 ROPI_RWPI,314 ROPI_RWPI,
...@@ -306,6 +319,15 @@ pub const CodeGenFileType = enum(c_int) {...@@ -306,6 +319,15 @@ pub const CodeGenFileType = enum(c_int) {
306 ObjectFile,319 ObjectFile,
307};320};
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
309pub const Target = opaque {331pub const Target = opaque {
310 pub const getFromTriple = LLVMGetTargetFromTriple;332 pub const getFromTriple = LLVMGetTargetFromTriple;
311 extern fn LLVMGetTargetFromTriple(Triple: [*:0]const u8, T: **const Target, ErrorMessage: *[*:0]const u8) Bool;333 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 {...@@ -191,7 +191,7 @@ pub const File = struct {
191 const use_stage1 = build_options.is_stage1 and options.use_stage1;191 const use_stage1 = build_options.is_stage1 and options.use_stage1;
192 if (use_stage1 or options.emit == null) {192 if (use_stage1 or options.emit == null) {
193 return switch (options.object_format) {193 return switch (options.object_format) {
194 .coff, .pe => &(try Coff.createEmpty(allocator, options)).base,194 .coff => &(try Coff.createEmpty(allocator, options)).base,
195 .elf => &(try Elf.createEmpty(allocator, options)).base,195 .elf => &(try Elf.createEmpty(allocator, options)).base,
196 .macho => &(try MachO.createEmpty(allocator, options)).base,196 .macho => &(try MachO.createEmpty(allocator, options)).base,
197 .wasm => &(try Wasm.createEmpty(allocator, options)).base,197 .wasm => &(try Wasm.createEmpty(allocator, options)).base,
...@@ -206,9 +206,10 @@ pub const File = struct {...@@ -206,9 +206,10 @@ pub const File = struct {
206 const use_lld = build_options.have_llvm and options.use_lld; // comptime known false when !have_llvm206 const use_lld = build_options.have_llvm and options.use_lld; // comptime known false when !have_llvm
207 const sub_path = if (use_lld) blk: {207 const sub_path = if (use_lld) blk: {
208 if (options.module == null) {208 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.
210 return switch (options.object_format) {211 return switch (options.object_format) {
211 .coff, .pe => &(try Coff.createEmpty(allocator, options)).base,212 .coff => &(try Coff.createEmpty(allocator, options)).base,
212 .elf => &(try Elf.createEmpty(allocator, options)).base,213 .elf => &(try Elf.createEmpty(allocator, options)).base,
213 .macho => &(try MachO.createEmpty(allocator, options)).base,214 .macho => &(try MachO.createEmpty(allocator, options)).base,
214 .plan9 => &(try Plan9.createEmpty(allocator, options)).base,215 .plan9 => &(try Plan9.createEmpty(allocator, options)).base,
...@@ -219,13 +220,16 @@ pub const File = struct {...@@ -219,13 +220,16 @@ pub const File = struct {
219 .raw => return error.RawObjectFormatUnimplemented,220 .raw => return error.RawObjectFormatUnimplemented,
220 };221 };
221 }222 }
222 // Open a temporary object file, not the final output file because we want to link with LLD.223 // Open a temporary object file, not the final output file because we
223 break :blk try std.fmt.allocPrint(allocator, "{s}{s}", .{ emit.sub_path, options.target.oFileExt() });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 });
224 } else emit.sub_path;228 } else emit.sub_path;
225 errdefer if (use_lld) allocator.free(sub_path);229 errdefer if (use_lld) allocator.free(sub_path);
226230
227 const file: *File = switch (options.object_format) {231 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,
229 .elf => &(try Elf.openPath(allocator, sub_path, options)).base,233 .elf => &(try Elf.openPath(allocator, sub_path, options)).base,
230 .macho => &(try MachO.openPath(allocator, sub_path, options)).base,234 .macho => &(try MachO.openPath(allocator, sub_path, options)).base,
231 .plan9 => &(try Plan9.openPath(allocator, sub_path, options)).base,235 .plan9 => &(try Plan9.openPath(allocator, sub_path, options)).base,
src/link/Coff.zig+13-12
...@@ -17,9 +17,9 @@ const link = @import("../link.zig");...@@ -17,9 +17,9 @@ const link = @import("../link.zig");
17const build_options = @import("build_options");17const build_options = @import("build_options");
18const Cache = @import("../Cache.zig");18const Cache = @import("../Cache.zig");
19const mingw = @import("../mingw.zig");19const mingw = @import("../mingw.zig");
20const llvm_backend = @import("../codegen/llvm.zig");
21const Air = @import("../Air.zig");20const Air = @import("../Air.zig");
22const Liveness = @import("../Liveness.zig");21const Liveness = @import("../Liveness.zig");
22const LlvmObject = @import("../codegen/llvm.zig").Object;
2323
24const allocation_padding = 4 / 3;24const allocation_padding = 4 / 3;
25const minimum_text_block_size = 64 * allocation_padding;25const minimum_text_block_size = 64 * allocation_padding;
...@@ -37,7 +37,7 @@ pub const base_tag: link.File.Tag = .coff;...@@ -37,7 +37,7 @@ pub const base_tag: link.File.Tag = .coff;
37const msdos_stub = @embedFile("msdos-stub.bin");37const msdos_stub = @embedFile("msdos-stub.bin");
3838
39/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.39/// 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
42base: link.File,42base: link.File,
43ptr_width: PtrWidth,43ptr_width: PtrWidth,
...@@ -132,7 +132,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -132,7 +132,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
132 const self = try createEmpty(allocator, options);132 const self = try createEmpty(allocator, options);
133 errdefer self.base.destroy();133 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);
136 return self;136 return self;
137 }137 }
138138
...@@ -657,10 +657,7 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {...@@ -657,10 +657,7 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {
657}657}
658658
659pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {659pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
660 if (build_options.skip_non_native and660 if (build_options.skip_non_native and builtin.object_format != .coff) {
661 builtin.object_format != .coff and
662 builtin.object_format != .pe)
663 {
664 @panic("Attempted to compile for object format that was disabled by build configuration");661 @panic("Attempted to compile for object format that was disabled by build configuration");
665 }662 }
666 if (build_options.have_llvm) {663 if (build_options.have_llvm) {
...@@ -697,7 +694,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live...@@ -697,7 +694,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live
697}694}
698695
699pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {696pub 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) {
701 @panic("Attempted to compile for object format that was disabled by build configuration");698 @panic("Attempted to compile for object format that was disabled by build configuration");
702 }699 }
703 if (build_options.have_llvm) {700 if (build_options.have_llvm) {
...@@ -823,8 +820,11 @@ pub fn flushModule(self: *Coff, comp: *Compilation) !void {...@@ -823,8 +820,11 @@ pub fn flushModule(self: *Coff, comp: *Compilation) !void {
823 const tracy = trace(@src());820 const tracy = trace(@src());
824 defer tracy.end();821 defer tracy.end();
825822
826 if (build_options.have_llvm)823 if (build_options.have_llvm) {
827 if (self.llvm_object) |llvm_object| return try llvm_object.flushModule(comp);824 if (self.llvm_object) |llvm_object| {
825 return try llvm_object.flushModule(comp);
826 }
827 }
828828
829 if (self.text_section_size_dirty) {829 if (self.text_section_size_dirty) {
830 // Write the new raw size in the .text header830 // Write the new raw size in the .text header
...@@ -1398,8 +1398,9 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v...@@ -1398,8 +1398,9 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v
1398}1398}
13991399
1400pub fn deinit(self: *Coff) void {1400pub fn deinit(self: *Coff) void {
1401 if (build_options.have_llvm)1401 if (build_options.have_llvm) {
1402 if (self.llvm_object) |ir_module| ir_module.deinit(self.base.allocator);1402 if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);
1403 }
14031404
1404 self.text_block_free_list.deinit(self.base.allocator);1405 self.text_block_free_list.deinit(self.base.allocator);
1405 self.offset_table.deinit(self.base.allocator);1406 self.offset_table.deinit(self.base.allocator);
src/link/Elf.zig+12-8
...@@ -25,9 +25,9 @@ const target_util = @import("../target.zig");...@@ -25,9 +25,9 @@ const target_util = @import("../target.zig");
25const glibc = @import("../glibc.zig");25const glibc = @import("../glibc.zig");
26const musl = @import("../musl.zig");26const musl = @import("../musl.zig");
27const Cache = @import("../Cache.zig");27const Cache = @import("../Cache.zig");
28const llvm_backend = @import("../codegen/llvm.zig");
29const Air = @import("../Air.zig");28const Air = @import("../Air.zig");
30const Liveness = @import("../Liveness.zig");29const Liveness = @import("../Liveness.zig");
30const LlvmObject = @import("../codegen/llvm.zig").Object;
3131
32const default_entry_addr = 0x8000000;32const default_entry_addr = 0x8000000;
3333
...@@ -38,7 +38,7 @@ base: File,...@@ -38,7 +38,7 @@ base: File,
38ptr_width: PtrWidth,38ptr_width: PtrWidth,
3939
40/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.40/// 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
43/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.43/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
44/// Same order as in the file.44/// Same order as in the file.
...@@ -235,7 +235,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -235,7 +235,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
235 const self = try createEmpty(allocator, options);235 const self = try createEmpty(allocator, options);
236 errdefer self.base.destroy();236 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);
239 return self;239 return self;
240 }240 }
241241
...@@ -301,9 +301,9 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Elf {...@@ -301,9 +301,9 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Elf {
301}301}
302302
303pub fn deinit(self: *Elf) void {303pub fn deinit(self: *Elf) void {
304 if (build_options.have_llvm)304 if (build_options.have_llvm) {
305 if (self.llvm_object) |ir_module|305 if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);
306 ir_module.deinit(self.base.allocator);306 }
307307
308 self.sections.deinit(self.base.allocator);308 self.sections.deinit(self.base.allocator);
309 self.program_headers.deinit(self.base.allocator);309 self.program_headers.deinit(self.base.allocator);
...@@ -750,8 +750,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {...@@ -750,8 +750,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
750 if (build_options.have_llvm)750 if (build_options.have_llvm)
751 if (self.llvm_object) |llvm_object| return try llvm_object.flushModule(comp);751 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 the753 // TODO This linker code currently assumes there is only 1 compilation unit and it
754 // Zig source code.754 // corresponds to the Zig source code.
755 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;755 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
756756
757 const target_endian = self.base.options.target.cpu.arch.endian();757 const target_endian = self.base.options.target.cpu.arch.endian();
...@@ -1289,6 +1289,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1289,6 +1289,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1289 // TODO: remove when stage2 can build compiler_rt.zig1289 // TODO: remove when stage2 can build compiler_rt.zig
1290 if (!build_options.is_stage1) break :blk null;1290 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
1292 if (is_exe_or_dyn_lib) {1296 if (is_exe_or_dyn_lib) {
1293 break :blk comp.compiler_rt_static_lib.?.full_object_path;1297 break :blk comp.compiler_rt_static_lib.?.full_object_path;
1294 } else {1298 } else {
src/link/MachO.zig+6-3
...@@ -30,7 +30,7 @@ const DebugSymbols = @import("MachO/DebugSymbols.zig");...@@ -30,7 +30,7 @@ const DebugSymbols = @import("MachO/DebugSymbols.zig");
30const Trie = @import("MachO/Trie.zig");30const Trie = @import("MachO/Trie.zig");
31const CodeSignature = @import("MachO/CodeSignature.zig");31const CodeSignature = @import("MachO/CodeSignature.zig");
32const Zld = @import("MachO/Zld.zig");32const Zld = @import("MachO/Zld.zig");
33const llvm_backend = @import("../codegen/llvm.zig");33const LlvmObject = @import("../codegen/llvm.zig").Object;
3434
35usingnamespace @import("MachO/commands.zig");35usingnamespace @import("MachO/commands.zig");
3636
...@@ -39,7 +39,7 @@ pub const base_tag: File.Tag = File.Tag.macho;...@@ -39,7 +39,7 @@ pub const base_tag: File.Tag = File.Tag.macho;
39base: File,39base: File,
4040
41/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.41/// 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
44/// Debug symbols bundle (or dSym).44/// Debug symbols bundle (or dSym).
45d_sym: ?DebugSymbols = null,45d_sym: ?DebugSymbols = null,
...@@ -355,7 +355,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -355,7 +355,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
355 const self = try createEmpty(allocator, options);355 const self = try createEmpty(allocator, options);
356 errdefer self.base.destroy();356 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);
359 return self;359 return self;
360 }360 }
361361
...@@ -989,6 +989,9 @@ fn darwinArchString(arch: std.Target.Cpu.Arch) []const u8 {...@@ -989,6 +989,9 @@ fn darwinArchString(arch: std.Target.Cpu.Arch) []const u8 {
989}989}
990990
991pub fn deinit(self: *MachO) void {991pub 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 }
992 if (self.d_sym) |*ds| {995 if (self.d_sym) |*ds| {
993 ds.deinit(self.base.allocator);996 ds.deinit(self.base.allocator);
994 }997 }
src/link/Wasm.zig+9-4
...@@ -19,7 +19,7 @@ const build_options = @import("build_options");...@@ -19,7 +19,7 @@ const build_options = @import("build_options");
19const wasi_libc = @import("../wasi_libc.zig");19const wasi_libc = @import("../wasi_libc.zig");
20const Cache = @import("../Cache.zig");20const Cache = @import("../Cache.zig");
21const TypedValue = @import("../TypedValue.zig");21const TypedValue = @import("../TypedValue.zig");
22const llvm_backend = @import("../codegen/llvm.zig");22const LlvmObject = @import("../codegen/llvm.zig").Object;
23const Air = @import("../Air.zig");23const Air = @import("../Air.zig");
24const Liveness = @import("../Liveness.zig");24const Liveness = @import("../Liveness.zig");
2525
...@@ -27,7 +27,7 @@ pub const base_tag = link.File.Tag.wasm;...@@ -27,7 +27,7 @@ pub const base_tag = link.File.Tag.wasm;
2727
28base: link.File,28base: link.File,
29/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.29/// 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,
31/// List of all function Decls to be written to the output file. The index of31/// List of all function Decls to be written to the output file. The index of
32/// each Decl in this list at the time of writing the binary is used as the32/// each Decl in this list at the time of writing the binary is used as the
33/// function index. In the event where ext_funcs' size is not 0, the index of33/// 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...@@ -121,7 +121,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
121 const self = try createEmpty(allocator, options);121 const self = try createEmpty(allocator, options);
122 errdefer self.base.destroy();122 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);
125 return self;125 return self;
126 }126 }
127127
...@@ -153,6 +153,9 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Wasm {...@@ -153,6 +153,9 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Wasm {
153}153}
154154
155pub fn deinit(self: *Wasm) void {155pub 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 }
156 for (self.symbols.items) |decl| {159 for (self.symbols.items) |decl| {
157 decl.fn_link.wasm.functype.deinit(self.base.allocator);160 decl.fn_link.wasm.functype.deinit(self.base.allocator);
158 decl.fn_link.wasm.code.deinit(self.base.allocator);161 decl.fn_link.wasm.code.deinit(self.base.allocator);
...@@ -642,7 +645,9 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {...@@ -642,7 +645,9 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
642 break :blk full_obj_path;645 break :blk full_obj_path;
643 } else null;646 } 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)
646 comp.compiler_rt_static_lib.?.full_object_path651 comp.compiler_rt_static_lib.?.full_object_path
647 else652 else
648 null;653 null;
src/main.zig+40-22
...@@ -287,9 +287,9 @@ const usage_build_generic =...@@ -287,9 +287,9 @@ const usage_build_generic =
287 \\ .s Target-specific assembly source code287 \\ .s Target-specific assembly source code
288 \\ .S Assembly with C preprocessor (requires LLVM extensions)288 \\ .S Assembly with C preprocessor (requires LLVM extensions)
289 \\ .c C source code (requires LLVM extensions)289 \\ .c C source code (requires LLVM extensions)
290 \\ .cpp C++ source code (requires LLVM extensions)290 \\ .cxx .cc .C .cpp C++ source code (requires LLVM extensions)
291 \\ Other C++ extensions: .C .cc .cxx
292 \\ .m Objective-C source code (requires LLVM extensions)291 \\ .m Objective-C source code (requires LLVM extensions)
292 \\ .bc LLVM IR Module (requires LLVM extensions)
293 \\293 \\
294 \\General Options:294 \\General Options:
295 \\ -h, --help Print this help and exit295 \\ -h, --help Print this help and exit
...@@ -301,6 +301,8 @@ const usage_build_generic =...@@ -301,6 +301,8 @@ const usage_build_generic =
301 \\ -fno-emit-asm (default) Do not output .s (assembly code)301 \\ -fno-emit-asm (default) Do not output .s (assembly code)
302 \\ -femit-llvm-ir[=path] Produce a .ll file with LLVM IR (requires LLVM extensions)302 \\ -femit-llvm-ir[=path] Produce a .ll file with LLVM IR (requires LLVM extensions)
303 \\ -fno-emit-llvm-ir (default) Do not produce a .ll file with LLVM IR303 \\ -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
304 \\ -femit-h[=path] Generate a C header file (.h)306 \\ -femit-h[=path] Generate a C header file (.h)
305 \\ -fno-emit-h (default) Do not generate a C header file (.h)307 \\ -fno-emit-h (default) Do not generate a C header file (.h)
306 \\ -femit-docs[=path] Create a docs/ dir with html documentation308 \\ -femit-docs[=path] Create a docs/ dir with html documentation
...@@ -359,15 +361,14 @@ const usage_build_generic =...@@ -359,15 +361,14 @@ const usage_build_generic =
359 \\ --single-threaded Code assumes it is only used single-threaded361 \\ --single-threaded Code assumes it is only used single-threaded
360 \\ -ofmt=[mode] Override target object format362 \\ -ofmt=[mode] Override target object format
361 \\ elf Executable and Linking Format363 \\ elf Executable and Linking Format
362 \\ c Compile to C source code364 \\ c C source code
363 \\ wasm WebAssembly365 \\ wasm WebAssembly
364 \\ pe Portable Executable (Windows)
365 \\ coff Common Object File Format (Windows)366 \\ coff Common Object File Format (Windows)
366 \\ macho macOS relocatables367 \\ macho macOS relocatables
367 \\ spirv Standard, Portable Intermediate Representation V (SPIR-V)368 \\ spirv Standard, Portable Intermediate Representation V (SPIR-V)
368 \\ plan9 Plan 9 from Bell Labs object format369 \\ plan9 Plan 9 from Bell Labs object format
369 \\ hex (planned) Intel IHEX370 \\ hex (planned feature) Intel IHEX
370 \\ raw (planned) Dump machine code directly371 \\ raw (planned feature) Dump machine code directly
371 \\ -dirafter [dir] Add directory to AFTER include search path372 \\ -dirafter [dir] Add directory to AFTER include search path
372 \\ -isystem [dir] Add directory to SYSTEM include search path373 \\ -isystem [dir] Add directory to SYSTEM include search path
373 \\ -I[dir] Add directory to include search path374 \\ -I[dir] Add directory to include search path
...@@ -384,8 +385,8 @@ const usage_build_generic =...@@ -384,8 +385,8 @@ const usage_build_generic =
384 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)385 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
385 \\ --sysroot [path] Set the system root directory (usually /)386 \\ --sysroot [path] Set the system root directory (usually /)
386 \\ --version [ver] Dynamic library semver387 \\ --version [ver] Dynamic library semver
387 \\ -fsoname[=name] (Linux) Override the default SONAME value388 \\ -fsoname[=name] Override the default SONAME value
388 \\ -fno-soname (Linux) Disable emitting a SONAME389 \\ -fno-soname Disable emitting a SONAME
389 \\ -fLLD Force using LLD as the linker390 \\ -fLLD Force using LLD as the linker
390 \\ -fno-LLD Prevent using LLD as the linker391 \\ -fno-LLD Prevent using LLD as the linker
391 \\ -fcompiler-rt Always include compiler-rt symbols in output392 \\ -fcompiler-rt Always include compiler-rt symbols in output
...@@ -552,6 +553,7 @@ fn buildOutputType(...@@ -552,6 +553,7 @@ fn buildOutputType(
552 var emit_bin: EmitBin = .yes_default_path;553 var emit_bin: EmitBin = .yes_default_path;
553 var emit_asm: Emit = .no;554 var emit_asm: Emit = .no;
554 var emit_llvm_ir: Emit = .no;555 var emit_llvm_ir: Emit = .no;
556 var emit_llvm_bc: Emit = .no;
555 var emit_docs: Emit = .no;557 var emit_docs: Emit = .no;
556 var emit_analysis: Emit = .no;558 var emit_analysis: Emit = .no;
557 var target_arch_os_abi: []const u8 = "native";559 var target_arch_os_abi: []const u8 = "native";
...@@ -1011,6 +1013,12 @@ fn buildOutputType(...@@ -1011,6 +1013,12 @@ fn buildOutputType(
1011 emit_llvm_ir = .{ .yes = arg["-femit-llvm-ir=".len..] };1013 emit_llvm_ir = .{ .yes = arg["-femit-llvm-ir=".len..] };
1012 } else if (mem.eql(u8, arg, "-fno-emit-llvm-ir")) {1014 } else if (mem.eql(u8, arg, "-fno-emit-llvm-ir")) {
1013 emit_llvm_ir = .no;1015 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;
1014 } else if (mem.eql(u8, arg, "-femit-docs")) {1022 } else if (mem.eql(u8, arg, "-femit-docs")) {
1015 emit_docs = .yes_default_path;1023 emit_docs = .yes_default_path;
1016 } else if (mem.startsWith(u8, arg, "-femit-docs=")) {1024 } else if (mem.startsWith(u8, arg, "-femit-docs=")) {
...@@ -1708,8 +1716,6 @@ fn buildOutputType(...@@ -1708,8 +1716,6 @@ fn buildOutputType(
1708 break :blk .c;1716 break :blk .c;
1709 } else if (mem.eql(u8, ofmt, "coff")) {1717 } else if (mem.eql(u8, ofmt, "coff")) {
1710 break :blk .coff;1718 break :blk .coff;
1711 } else if (mem.eql(u8, ofmt, "pe")) {
1712 break :blk .pe;
1713 } else if (mem.eql(u8, ofmt, "macho")) {1719 } else if (mem.eql(u8, ofmt, "macho")) {
1714 break :blk .macho;1720 break :blk .macho;
1715 } else if (mem.eql(u8, ofmt, "wasm")) {1721 } else if (mem.eql(u8, ofmt, "wasm")) {
...@@ -1753,7 +1759,7 @@ fn buildOutputType(...@@ -1753,7 +1759,7 @@ fn buildOutputType(
1753 };1759 };
17541760
1755 const a_out_basename = switch (object_format) {1761 const a_out_basename = switch (object_format) {
1756 .pe, .coff => "a.exe",1762 .coff => "a.exe",
1757 else => "a.out",1763 else => "a.out",
1758 };1764 };
17591765
...@@ -1818,10 +1824,10 @@ fn buildOutputType(...@@ -1818,10 +1824,10 @@ fn buildOutputType(
1818 var emit_h_resolved = emit_h.resolve(default_h_basename) catch |err| {1824 var emit_h_resolved = emit_h.resolve(default_h_basename) catch |err| {
1819 switch (emit_h) {1825 switch (emit_h) {
1820 .yes => {1826 .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) });
1822 },1828 },
1823 .yes_default_path => {1829 .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) });
1825 },1831 },
1826 .no => unreachable,1832 .no => unreachable,
1827 }1833 }
...@@ -1832,10 +1838,10 @@ fn buildOutputType(...@@ -1832,10 +1838,10 @@ fn buildOutputType(
1832 var emit_asm_resolved = emit_asm.resolve(default_asm_basename) catch |err| {1838 var emit_asm_resolved = emit_asm.resolve(default_asm_basename) catch |err| {
1833 switch (emit_asm) {1839 switch (emit_asm) {
1834 .yes => {1840 .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) });
1836 },1842 },
1837 .yes_default_path => {1843 .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) });
1839 },1845 },
1840 .no => unreachable,1846 .no => unreachable,
1841 }1847 }
...@@ -1846,16 +1852,30 @@ fn buildOutputType(...@@ -1846,16 +1852,30 @@ fn buildOutputType(
1846 var emit_llvm_ir_resolved = emit_llvm_ir.resolve(default_llvm_ir_basename) catch |err| {1852 var emit_llvm_ir_resolved = emit_llvm_ir.resolve(default_llvm_ir_basename) catch |err| {
1847 switch (emit_llvm_ir) {1853 switch (emit_llvm_ir) {
1848 .yes => {1854 .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) });
1850 },1856 },
1851 .yes_default_path => {1857 .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) });
1853 },1859 },
1854 .no => unreachable,1860 .no => unreachable,
1855 }1861 }
1856 };1862 };
1857 defer emit_llvm_ir_resolved.deinit();1863 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
1859 const default_analysis_basename = try std.fmt.allocPrint(arena, "{s}-analysis.json", .{root_name});1879 const default_analysis_basename = try std.fmt.allocPrint(arena, "{s}-analysis.json", .{root_name});
1860 var emit_analysis_resolved = emit_analysis.resolve(default_analysis_basename) catch |err| {1880 var emit_analysis_resolved = emit_analysis.resolve(default_analysis_basename) catch |err| {
1861 switch (emit_analysis) {1881 switch (emit_analysis) {
...@@ -1991,6 +2011,7 @@ fn buildOutputType(...@@ -1991,6 +2011,7 @@ fn buildOutputType(
1991 .emit_h = emit_h_resolved.data,2011 .emit_h = emit_h_resolved.data,
1992 .emit_asm = emit_asm_resolved.data,2012 .emit_asm = emit_asm_resolved.data,
1993 .emit_llvm_ir = emit_llvm_ir_resolved.data,2013 .emit_llvm_ir = emit_llvm_ir_resolved.data,
2014 .emit_llvm_bc = emit_llvm_bc_resolved.data,
1994 .emit_docs = emit_docs_resolved.data,2015 .emit_docs = emit_docs_resolved.data,
1995 .emit_analysis = emit_analysis_resolved.data,2016 .emit_analysis = emit_analysis_resolved.data,
1996 .link_mode = link_mode,2017 .link_mode = link_mode,
...@@ -2396,11 +2417,8 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi...@@ -2396,11 +2417,8 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi
23962417
2397 // If a .pdb file is part of the expected output, we must also copy2418 // If a .pdb file is part of the expected output, we must also copy
2398 // it into place here.2419 // it into place here.
2399 const coff_or_pe = switch (comp.bin_file.options.object_format) {2420 const is_coff = comp.bin_file.options.object_format == .coff;
2400 .coff, .pe => true,2421 const have_pdb = is_coff and !comp.bin_file.options.strip;
2401 else => false,
2402 };
2403 const have_pdb = coff_or_pe and !comp.bin_file.options.strip;
2404 if (have_pdb) {2422 if (have_pdb) {
2405 // Replace `.out` or `.exe` with `.pdb` on both the source and destination2423 // Replace `.out` or `.exe` with `.pdb` on both the source and destination
2406 const src_bin_ext = fs.path.extension(bin_sub_path);2424 const src_bin_ext = fs.path.extension(bin_sub_path);
src/stage1.zig+3-1
...@@ -21,7 +21,6 @@ comptime {...@@ -21,7 +21,6 @@ comptime {
21 assert(build_options.is_stage1);21 assert(build_options.is_stage1);
22 assert(build_options.have_llvm);22 assert(build_options.have_llvm);
23 if (!builtin.is_test) {23 if (!builtin.is_test) {
24 _ = @import("compiler_rt");
25 @export(main, .{ .name = "main" });24 @export(main, .{ .name = "main" });
26 }25 }
27}26}
...@@ -95,6 +94,8 @@ pub const Module = extern struct {...@@ -95,6 +94,8 @@ pub const Module = extern struct {
95 emit_asm_len: usize,94 emit_asm_len: usize,
96 emit_llvm_ir_ptr: [*]const u8,95 emit_llvm_ir_ptr: [*]const u8,
97 emit_llvm_ir_len: usize,96 emit_llvm_ir_len: usize,
97 emit_bitcode_ptr: [*]const u8,
98 emit_bitcode_len: usize,
98 emit_analysis_json_ptr: [*]const u8,99 emit_analysis_json_ptr: [*]const u8,
99 emit_analysis_json_len: usize,100 emit_analysis_json_len: usize,
100 emit_docs_ptr: [*]const u8,101 emit_docs_ptr: [*]const u8,
...@@ -124,6 +125,7 @@ pub const Module = extern struct {...@@ -124,6 +125,7 @@ pub const Module = extern struct {
124 valgrind_enabled: bool,125 valgrind_enabled: bool,
125 tsan_enabled: bool,126 tsan_enabled: bool,
126 function_sections: bool,127 function_sections: bool,
128 include_compiler_rt: bool,
127 enable_stack_probing: bool,129 enable_stack_probing: bool,
128 red_zone: bool,130 red_zone: bool,
129 enable_time_report: bool,131 enable_time_report: bool,
src/stage1/all_types.hpp+2
...@@ -2090,6 +2090,7 @@ struct CodeGen {...@@ -2090,6 +2090,7 @@ struct CodeGen {
2090 Buf h_file_output_path;2090 Buf h_file_output_path;
2091 Buf asm_file_output_path;2091 Buf asm_file_output_path;
2092 Buf llvm_ir_file_output_path;2092 Buf llvm_ir_file_output_path;
2093 Buf bitcode_file_output_path;
2093 Buf analysis_json_output_path;2094 Buf analysis_json_output_path;
2094 Buf docs_output_path;2095 Buf docs_output_path;
20952096
...@@ -2149,6 +2150,7 @@ struct CodeGen {...@@ -2149,6 +2150,7 @@ struct CodeGen {
2149 bool have_stack_probing;2150 bool have_stack_probing;
2150 bool red_zone;2151 bool red_zone;
2151 bool function_sections;2152 bool function_sections;
2153 bool include_compiler_rt;
2152 bool test_is_evented;2154 bool test_is_evented;
2153 bool valgrind_enabled;2155 bool valgrind_enabled;
2154 bool tsan_enabled;2156 bool tsan_enabled;
src/stage1/codegen.cpp+27-6
...@@ -8506,19 +8506,22 @@ static void zig_llvm_emit_output(CodeGen *g) {...@@ -8506,19 +8506,22 @@ static void zig_llvm_emit_output(CodeGen *g) {
8506 const char *asm_filename = nullptr;8506 const char *asm_filename = nullptr;
8507 const char *bin_filename = nullptr;8507 const char *bin_filename = nullptr;
8508 const char *llvm_ir_filename = nullptr;8508 const char *llvm_ir_filename = nullptr;
8509 const char *bitcode_filename = nullptr;
85098510
8510 if (buf_len(&g->o_file_output_path) != 0) bin_filename = buf_ptr(&g->o_file_output_path);8511 if (buf_len(&g->o_file_output_path) != 0) bin_filename = buf_ptr(&g->o_file_output_path);
8511 if (buf_len(&g->asm_file_output_path) != 0) asm_filename = buf_ptr(&g->asm_file_output_path);8512 if (buf_len(&g->asm_file_output_path) != 0) asm_filename = buf_ptr(&g->asm_file_output_path);
8512 if (buf_len(&g->llvm_ir_file_output_path) != 0) llvm_ir_filename = buf_ptr(&g->llvm_ir_file_output_path);8513 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 entire8516 // Unfortunately, LLVM shits the bed when we ask for both binary and assembly.
8515 // pipeline multiple times if this is requested.8517 // So we call the entire pipeline multiple times if this is requested.
8516 if (asm_filename != nullptr && bin_filename != nullptr) {8518 if (asm_filename != nullptr && bin_filename != nullptr) {
8517 if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg,8519 if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg,
8518 g->build_mode == BuildModeDebug, is_small, g->enable_time_report, g->tsan_enabled,8520 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))
8520 {8522 {
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);
8522 exit(1);8525 exit(1);
8523 }8526 }
8524 bin_filename = nullptr;8527 bin_filename = nullptr;
...@@ -8527,9 +8530,11 @@ static void zig_llvm_emit_output(CodeGen *g) {...@@ -8527,9 +8530,11 @@ static void zig_llvm_emit_output(CodeGen *g) {
85278530
8528 if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg,8531 if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg,
8529 g->build_mode == BuildModeDebug, is_small, g->enable_time_report, g->tsan_enabled,8532 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))
8531 {8534 {
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);
8533 exit(1);8538 exit(1);
8534 }8539 }
85358540
...@@ -9537,6 +9542,22 @@ static void gen_root_source(CodeGen *g) {...@@ -9537,6 +9542,22 @@ static void gen_root_source(CodeGen *g) {
9537 g->panic_fn = panic_fn_val->data.x_ptr.data.fn.fn_entry;9542 g->panic_fn = panic_fn_val->data.x_ptr.data.fn.fn_entry;
9538 assert(g->panic_fn != nullptr);9543 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
9540 if (!g->error_during_imports) {9561 if (!g->error_during_imports) {
9541 semantic_analyze(g);9562 semantic_analyze(g);
9542 }9563 }
src/stage1/stage1.cpp+2
...@@ -73,6 +73,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {...@@ -73,6 +73,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
73 buf_init_from_mem(&g->h_file_output_path, stage1->emit_h_ptr, stage1->emit_h_len);73 buf_init_from_mem(&g->h_file_output_path, stage1->emit_h_ptr, stage1->emit_h_len);
74 buf_init_from_mem(&g->asm_file_output_path, stage1->emit_asm_ptr, stage1->emit_asm_len);74 buf_init_from_mem(&g->asm_file_output_path, stage1->emit_asm_ptr, stage1->emit_asm_len);
75 buf_init_from_mem(&g->llvm_ir_file_output_path, stage1->emit_llvm_ir_ptr, stage1->emit_llvm_ir_len);75 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);
76 buf_init_from_mem(&g->analysis_json_output_path, stage1->emit_analysis_json_ptr, stage1->emit_analysis_json_len);77 buf_init_from_mem(&g->analysis_json_output_path, stage1->emit_analysis_json_ptr, stage1->emit_analysis_json_len);
77 buf_init_from_mem(&g->docs_output_path, stage1->emit_docs_ptr, stage1->emit_docs_len);78 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) {...@@ -100,6 +101,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
100 g->link_libc = stage1->link_libc;101 g->link_libc = stage1->link_libc;
101 g->link_libcpp = stage1->link_libcpp;102 g->link_libcpp = stage1->link_libcpp;
102 g->function_sections = stage1->function_sections;103 g->function_sections = stage1->function_sections;
104 g->include_compiler_rt = stage1->include_compiler_rt;
103105
104 g->subsystem = stage1->subsystem;106 g->subsystem = stage1->subsystem;
105107
src/stage1/stage1.h+4
...@@ -157,6 +157,9 @@ struct ZigStage1 {...@@ -157,6 +157,9 @@ struct ZigStage1 {
157 const char *emit_llvm_ir_ptr;157 const char *emit_llvm_ir_ptr;
158 size_t emit_llvm_ir_len;158 size_t emit_llvm_ir_len;
159159
160 const char *emit_bitcode_ptr;
161 size_t emit_bitcode_len;
162
160 const char *emit_analysis_json_ptr;163 const char *emit_analysis_json_ptr;
161 size_t emit_analysis_json_len;164 size_t emit_analysis_json_len;
162165
...@@ -193,6 +196,7 @@ struct ZigStage1 {...@@ -193,6 +196,7 @@ struct ZigStage1 {
193 bool valgrind_enabled;196 bool valgrind_enabled;
194 bool tsan_enabled;197 bool tsan_enabled;
195 bool function_sections;198 bool function_sections;
199 bool include_compiler_rt;
196 bool enable_stack_probing;200 bool enable_stack_probing;
197 bool red_zone;201 bool red_zone;
198 bool enable_time_report;202 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) {...@@ -39,6 +39,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
39 " --color [auto|off|on] enable or disable colored error messages\n"39 " --color [auto|off|on] enable or disable colored error messages\n"
40 " --name [name] override output name\n"40 " --name [name] override output name\n"
41 " -femit-bin=[path] Output machine code\n"41 " -femit-bin=[path] Output machine code\n"
42 " -fcompiler-rt Always include compiler-rt symbols in output\n"
42 " --pkg-begin [name] [path] make pkg available to import and push current pkg\n"43 " --pkg-begin [name] [path] make pkg available to import and push current pkg\n"
43 " --pkg-end pop current pkg\n"44 " --pkg-end pop current pkg\n"
44 " -ODebug build with optimizations off and safety on\n"45 " -ODebug build with optimizations off and safety on\n"
...@@ -266,6 +267,7 @@ int main(int argc, char **argv) {...@@ -266,6 +267,7 @@ int main(int argc, char **argv) {
266 const char *mcpu = nullptr;267 const char *mcpu = nullptr;
267 bool single_threaded = false;268 bool single_threaded = false;
268 bool is_test_build = false;269 bool is_test_build = false;
270 bool include_compiler_rt = false;
269271
270 for (int i = 1; i < argc; i += 1) {272 for (int i = 1; i < argc; i += 1) {
271 char *arg = argv[i];273 char *arg = argv[i];
...@@ -334,6 +336,8 @@ int main(int argc, char **argv) {...@@ -334,6 +336,8 @@ int main(int argc, char **argv) {
334 mcpu = arg + strlen("-mcpu=");336 mcpu = arg + strlen("-mcpu=");
335 } else if (str_starts_with(arg, "-femit-bin=")) {337 } else if (str_starts_with(arg, "-femit-bin=")) {
336 emit_bin_path = arg + strlen("-femit-bin=");338 emit_bin_path = arg + strlen("-femit-bin=");
339 } else if (strcmp(arg, "-fcompiler-rt") == 0) {
340 include_compiler_rt = true;
337 } else if (i + 1 >= argc) {341 } else if (i + 1 >= argc) {
338 fprintf(stderr, "Expected another argument after %s\n", arg);342 fprintf(stderr, "Expected another argument after %s\n", arg);
339 return print_error_usage(arg0);343 return print_error_usage(arg0);
...@@ -468,6 +472,7 @@ int main(int argc, char **argv) {...@@ -468,6 +472,7 @@ int main(int argc, char **argv) {
468 stage1->subsystem = subsystem;472 stage1->subsystem = subsystem;
469 stage1->pic = true;473 stage1->pic = true;
470 stage1->is_single_threaded = single_threaded;474 stage1->is_single_threaded = single_threaded;
475 stage1->include_compiler_rt = include_compiler_rt;
471476
472 zig_stage1_build_object(stage1);477 zig_stage1_build_object(stage1);
473478
src/zig_llvm.cpp+17-2
...@@ -229,12 +229,14 @@ struct TimeTracerRAII {...@@ -229,12 +229,14 @@ struct TimeTracerRAII {
229bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,229bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
230 char **error_message, bool is_debug,230 char **error_message, bool is_debug,
231 bool is_small, bool time_report, bool tsan, bool lto,231 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)
233{234{
234 TimePassesIsEnabled = time_report;235 TimePassesIsEnabled = time_report;
235236
236 raw_fd_ostream *dest_asm_ptr = nullptr;237 raw_fd_ostream *dest_asm_ptr = nullptr;
237 raw_fd_ostream *dest_bin_ptr = nullptr;238 raw_fd_ostream *dest_bin_ptr = nullptr;
239 raw_fd_ostream *dest_bitcode_ptr = nullptr;
238240
239 if (asm_filename) {241 if (asm_filename) {
240 std::error_code EC;242 std::error_code EC;
...@@ -252,9 +254,19 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM...@@ -252,9 +254,19 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
252 return true;254 return true;
253 }255 }
254 }256 }
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
256 std::unique_ptr<raw_fd_ostream> dest_asm(dest_asm_ptr),266 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
259 auto PID = sys::Process::getProcessId();271 auto PID = sys::Process::getProcessId();
260 std::string ProcName = "zig-";272 std::string ProcName = "zig-";
...@@ -389,6 +401,9 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM...@@ -389,6 +401,9 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
389 if (dest_bin && lto) {401 if (dest_bin && lto) {
390 WriteBitcodeToFile(module, *dest_bin);402 WriteBitcodeToFile(module, *dest_bin);
391 }403 }
404 if (dest_bitcode) {
405 WriteBitcodeToFile(module, *dest_bitcode);
406 }
392407
393 if (time_report) {408 if (time_report) {
394 TimerGroup::printAll(errs());409 TimerGroup::printAll(errs());
src/zig_llvm.h+2-1
...@@ -49,7 +49,8 @@ ZIG_EXTERN_C char *ZigLLVMGetNativeFeatures(void);...@@ -49,7 +49,8 @@ ZIG_EXTERN_C char *ZigLLVMGetNativeFeatures(void);
49ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,49ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
50 char **error_message, bool is_debug,50 char **error_message, bool is_debug,
51 bool is_small, bool time_report, bool tsan, bool lto,51 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
55enum ZigLLVMABIType {56enum ZigLLVMABIType {