| author | |
| committer | |
| log | e3fe3acce0fc65a7f0c7227085456e8d167ed2a7 |
| tree | 17b5feeab6232ed6bbeff5f5ea7026c6b1ec2235 |
| parent | a38a6914875ab3bda02fb1732467228ef876074e |
| parent | 80ba9f060d81e8c5674acb4eb07c833d26121462 |
| signature |
add -femit-llvm-bc CLI option and implement it, and improve -fcompiler-rt support22 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 zig1 | 796 | --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 | -lc | 802 | -lc |
doc/docgen.zig+4-4| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = std.builtin; | 2 | const builtin = @import("builtin"); |
| 3 | const io = std.io; | 3 | const io = std.io; |
| 4 | const fs = std.fs; | 4 | const fs = std.fs; |
| 5 | const process = std.process; | 5 | const process = std.process; |
| ... | @@ -13,7 +13,7 @@ const Allocator = std.mem.Allocator; | ... | @@ -13,7 +13,7 @@ const Allocator = std.mem.Allocator; |
| 13 | const max_doc_file_size = 10 * 1024 * 1024; | 13 | const max_doc_file_size = 10 * 1024 * 1024; |
| 14 | 14 | ||
| 15 | const exe_ext = @as(std.zig.CrossTarget, .{}).exeFileExt(); | 15 | const exe_ext = @as(std.zig.CrossTarget, .{}).exeFileExt(); |
| 16 | const obj_ext = @as(std.zig.CrossTarget, .{}).oFileExt(); | 16 | const obj_ext = builtin.object_format.fileExt(builtin.cpu.arch); |
| 17 | const tmp_dir_name = "docgen_tmp"; | 17 | const tmp_dir_name = "docgen_tmp"; |
| 18 | const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext; | 18 | const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext; |
| 19 | 19 | ||
| ... | @@ -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 | } |
| 533 | 533 | ||
| 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 | }; |
| 550 | 550 | ||
| 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 | }; |
| 563 | 583 | ||
| 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 | } |
| 1292 | 1312 | ||
| 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 | } |
| 1318 | 1324 | ||
| 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 | } |
| 1354 | 1360 | ||
| 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 | } |
| 1371 | 1373 | ||
| 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 { |
| 1677 | 1679 | ||
| 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 | }; |
| 1681 | 1707 | ||
| 1682 | test { | 1708 | test { |
lib/std/zig.zig+10-30| ... | @@ -108,8 +108,9 @@ pub const BinNameOptions = struct { | ... | @@ -108,8 +108,9 @@ pub const BinNameOptions = struct { |
| 108 | pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) error{OutOfMemory}![]u8 { | 108 | pub 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 family | 187 | }), |
| 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 | } |
| 210 | 190 |
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 | } |
| 475 | 475 | ||
| 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, |
| 143 | 143 | ||
| 144 | emit_asm: ?EmitLoc, | 144 | emit_asm: ?EmitLoc, |
| 145 | emit_llvm_ir: ?EmitLoc, | 145 | emit_llvm_ir: ?EmitLoc, |
| 146 | emit_llvm_bc: ?EmitLoc, | ||
| 146 | emit_analysis: ?EmitLoc, | 147 | emit_analysis: ?EmitLoc, |
| 147 | emit_docs: ?EmitLoc, | 148 | emit_docs: ?EmitLoc, |
| 148 | 149 | ||
| ... | @@ -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 | }; |
| 590 | 602 | ||
| 591 | pub const EmitLoc = struct { | 603 | pub 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(); |
| 813 | 827 | ||
| 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 | }; |
| 824 | 842 | ||
| ... | @@ -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; |
| 837 | 855 | ||
| 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 backend | 860 | // 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 | } |
| 857 | 882 | ||
| 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 | } |
| 1514 | 1540 | ||
| 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_name | 2749 | comp.bin_file.options.root_name |
| 2729 | else | 2750 | 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 | }); | ||
| 2732 | 2756 | ||
| 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"; |
| 3951 | 3975 | ||
| 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(); |
| 3954 | 3988 | ||
| ... | @@ -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; |
| 4084 | 4120 | ||
| 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 | }; |
| 79 | 79 | ||
| 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 | }; |
| 123 | 125 | ||
| 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); | ||
| 168 | 157 | ||
| 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); |
| 172 | 161 | 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 | } |
| 175 | 164 | ||
| 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(); |
| 178 | 168 | ||
| 179 | initializeLLVMTargets(); | 169 | initializeLLVMTargets(); |
| 180 | 170 | ||
| 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(); |
| 185 | 175 | ||
| 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); |
| 188 | 178 | ||
| 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); |
| 193 | 183 | ||
| 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 | } |
| 204 | 187 | ||
| 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(); |
| 216 | 238 | ||
| 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 | } |
| 225 | 245 | ||
| 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 | } | ||
| 230 | 252 | ||
| 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 | } |
| 234 | 257 | ||
| 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 | } |
| 242 | 265 | ||
| 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 | } |
| 251 | 281 | ||
| 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 error | 284 | // verifyModule always allocs the error_message even if there is no error |
| 255 | defer llvm.disposeMessage(error_message); | 285 | defer llvm.disposeMessage(error_message); |
| 256 | 286 | ||
| 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 | } |
| 263 | 292 | ||
| 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); |
| 272 | 332 | ||
| 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 { |
| 123 | 123 | ||
| 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 | }; |
| 127 | 130 | ||
| 128 | pub const lookupIntrinsicID = LLVMLookupIntrinsicID; | 131 | pub const lookupIntrinsicID = LLVMLookupIntrinsicID; |
| ... | @@ -250,31 +253,41 @@ pub const BasicBlock = opaque { | ... | @@ -250,31 +253,41 @@ pub const BasicBlock = opaque { |
| 250 | }; | 253 | }; |
| 251 | 254 | ||
| 252 | pub const TargetMachine = opaque { | 255 | pub 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; |
| 263 | 269 | ||
| 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; |
| 266 | 272 | ||
| 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 | }; |
| 276 | 289 | ||
| 277 | pub const CodeMode = enum(c_int) { | 290 | pub 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 | }; |
| 308 | 321 | ||
| 322 | pub 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 | |||
| 309 | pub const Target = opaque { | 331 | pub 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_llvm | 206 | 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); |
| 226 | 230 | ||
| 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"); |
| 17 | const build_options = @import("build_options"); | 17 | const build_options = @import("build_options"); |
| 18 | const Cache = @import("../Cache.zig"); | 18 | const Cache = @import("../Cache.zig"); |
| 19 | const mingw = @import("../mingw.zig"); | 19 | const mingw = @import("../mingw.zig"); |
| 20 | const llvm_backend = @import("../codegen/llvm.zig"); | ||
| 21 | const Air = @import("../Air.zig"); | 20 | const Air = @import("../Air.zig"); |
| 22 | const Liveness = @import("../Liveness.zig"); | 21 | const Liveness = @import("../Liveness.zig"); |
| 22 | const LlvmObject = @import("../codegen/llvm.zig").Object; | ||
| 23 | 23 | ||
| 24 | const allocation_padding = 4 / 3; | 24 | const allocation_padding = 4 / 3; |
| 25 | const minimum_text_block_size = 64 * allocation_padding; | 25 | const 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; |
| 37 | const msdos_stub = @embedFile("msdos-stub.bin"); | 37 | const msdos_stub = @embedFile("msdos-stub.bin"); |
| 38 | 38 | ||
| 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. |
| 40 | llvm_object: ?*llvm_backend.Object = null, | 40 | llvm_object: ?*LlvmObject = null, |
| 41 | 41 | ||
| 42 | base: link.File, | 42 | base: link.File, |
| 43 | ptr_width: PtrWidth, | 43 | ptr_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(); |
| 134 | 134 | ||
| 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 | } |
| 138 | 138 | ||
| ... | @@ -657,10 +657,7 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void { | ... | @@ -657,10 +657,7 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void { |
| 657 | } | 657 | } |
| 658 | 658 | ||
| 659 | pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { | 659 | pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void { |
| 660 | if (build_options.skip_non_native and | 660 | 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 | } |
| 698 | 695 | ||
| 699 | pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void { | 696 | pub 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(); |
| 825 | 822 | ||
| 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 | } | ||
| 828 | 828 | ||
| 829 | if (self.text_section_size_dirty) { | 829 | if (self.text_section_size_dirty) { |
| 830 | // Write the new raw size in the .text header | 830 | // 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 | } |
| 1399 | 1399 | ||
| 1400 | pub fn deinit(self: *Coff) void { | 1400 | pub 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 | } | ||
| 1403 | 1404 | ||
| 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"); |
| 25 | const glibc = @import("../glibc.zig"); | 25 | const glibc = @import("../glibc.zig"); |
| 26 | const musl = @import("../musl.zig"); | 26 | const musl = @import("../musl.zig"); |
| 27 | const Cache = @import("../Cache.zig"); | 27 | const Cache = @import("../Cache.zig"); |
| 28 | const llvm_backend = @import("../codegen/llvm.zig"); | ||
| 29 | const Air = @import("../Air.zig"); | 28 | const Air = @import("../Air.zig"); |
| 30 | const Liveness = @import("../Liveness.zig"); | 29 | const Liveness = @import("../Liveness.zig"); |
| 30 | const LlvmObject = @import("../codegen/llvm.zig").Object; | ||
| 31 | 31 | ||
| 32 | const default_entry_addr = 0x8000000; | 32 | const default_entry_addr = 0x8000000; |
| 33 | 33 | ||
| ... | @@ -38,7 +38,7 @@ base: File, | ... | @@ -38,7 +38,7 @@ base: File, |
| 38 | ptr_width: PtrWidth, | 38 | ptr_width: PtrWidth, |
| 39 | 39 | ||
| 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. |
| 41 | llvm_object: ?*llvm_backend.Object = null, | 41 | llvm_object: ?*LlvmObject = null, |
| 42 | 42 | ||
| 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(); |
| 237 | 237 | ||
| 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 | } |
| 241 | 241 | ||
| ... | @@ -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 | } |
| 302 | 302 | ||
| 303 | pub fn deinit(self: *Elf) void { | 303 | pub 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 | } |
| 307 | 307 | ||
| 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); |
| 752 | 752 | ||
| 753 | // TODO This linker code currently assumes there is only 1 compilation unit and it corresponds to the | 753 | // 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; |
| 756 | 756 | ||
| 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.zig | 1289 | // 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; |
| 1291 | 1291 | ||
| 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"); |
| 30 | const Trie = @import("MachO/Trie.zig"); | 30 | const Trie = @import("MachO/Trie.zig"); |
| 31 | const CodeSignature = @import("MachO/CodeSignature.zig"); | 31 | const CodeSignature = @import("MachO/CodeSignature.zig"); |
| 32 | const Zld = @import("MachO/Zld.zig"); | 32 | const Zld = @import("MachO/Zld.zig"); |
| 33 | const llvm_backend = @import("../codegen/llvm.zig"); | 33 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 34 | 34 | ||
| 35 | usingnamespace @import("MachO/commands.zig"); | 35 | usingnamespace @import("MachO/commands.zig"); |
| 36 | 36 | ||
| ... | @@ -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; |
| 39 | base: File, | 39 | base: File, |
| 40 | 40 | ||
| 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. |
| 42 | llvm_object: ?*llvm_backend.Object = null, | 42 | llvm_object: ?*LlvmObject = null, |
| 43 | 43 | ||
| 44 | /// Debug symbols bundle (or dSym). | 44 | /// Debug symbols bundle (or dSym). |
| 45 | d_sym: ?DebugSymbols = null, | 45 | d_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(); |
| 357 | 357 | ||
| 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 | } |
| 361 | 361 | ||
| ... | @@ -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 | } |
| 990 | 990 | ||
| 991 | pub fn deinit(self: *MachO) void { | 991 | pub 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"); |
| 19 | const wasi_libc = @import("../wasi_libc.zig"); | 19 | const wasi_libc = @import("../wasi_libc.zig"); |
| 20 | const Cache = @import("../Cache.zig"); | 20 | const Cache = @import("../Cache.zig"); |
| 21 | const TypedValue = @import("../TypedValue.zig"); | 21 | const TypedValue = @import("../TypedValue.zig"); |
| 22 | const llvm_backend = @import("../codegen/llvm.zig"); | 22 | const LlvmObject = @import("../codegen/llvm.zig").Object; |
| 23 | const Air = @import("../Air.zig"); | 23 | const Air = @import("../Air.zig"); |
| 24 | const Liveness = @import("../Liveness.zig"); | 24 | const Liveness = @import("../Liveness.zig"); |
| 25 | 25 | ||
| ... | @@ -27,7 +27,7 @@ pub const base_tag = link.File.Tag.wasm; | ... | @@ -27,7 +27,7 @@ pub const base_tag = link.File.Tag.wasm; |
| 27 | 27 | ||
| 28 | base: link.File, | 28 | base: 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. |
| 30 | llvm_object: ?*llvm_backend.Object = null, | 30 | llvm_object: ?*LlvmObject = null, |
| 31 | /// List of all function Decls to be written to the output file. The index of | 31 | /// 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 the | 32 | /// 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 of | 33 | /// 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(); |
| 123 | 123 | ||
| 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 | } |
| 127 | 127 | ||
| ... | @@ -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 | } |
| 154 | 154 | ||
| 155 | pub fn deinit(self: *Wasm) void { | 155 | pub 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; |
| 644 | 647 | ||
| 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_path | 651 | comp.compiler_rt_static_lib.?.full_object_path |
| 647 | else | 652 | 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 code | 287 | \\ .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 exit | 295 | \\ -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 IR | 303 | \\ -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 documentation | 308 | \\ -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-threaded | 361 | \\ --single-threaded Code assumes it is only used single-threaded |
| 360 | \\ -ofmt=[mode] Override target object format | 362 | \\ -ofmt=[mode] Override target object format |
| 361 | \\ elf Executable and Linking Format | 363 | \\ elf Executable and Linking Format |
| 362 | \\ c Compile to C source code | 364 | \\ c C source code |
| 363 | \\ wasm WebAssembly | 365 | \\ wasm WebAssembly |
| 364 | \\ pe Portable Executable (Windows) | ||
| 365 | \\ coff Common Object File Format (Windows) | 366 | \\ coff Common Object File Format (Windows) |
| 366 | \\ macho macOS relocatables | 367 | \\ 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 format | 369 | \\ plan9 Plan 9 from Bell Labs object format |
| 369 | \\ hex (planned) Intel IHEX | 370 | \\ hex (planned feature) Intel IHEX |
| 370 | \\ raw (planned) Dump machine code directly | 371 | \\ raw (planned feature) Dump machine code directly |
| 371 | \\ -dirafter [dir] Add directory to AFTER include search path | 372 | \\ -dirafter [dir] Add directory to AFTER include search path |
| 372 | \\ -isystem [dir] Add directory to SYSTEM include search path | 373 | \\ -isystem [dir] Add directory to SYSTEM include search path |
| 373 | \\ -I[dir] Add directory to include search path | 374 | \\ -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 semver | 387 | \\ --version [ver] Dynamic library semver |
| 387 | \\ -fsoname[=name] (Linux) Override the default SONAME value | 388 | \\ -fsoname[=name] Override the default SONAME value |
| 388 | \\ -fno-soname (Linux) Disable emitting a SONAME | 389 | \\ -fno-soname Disable emitting a SONAME |
| 389 | \\ -fLLD Force using LLD as the linker | 390 | \\ -fLLD Force using LLD as the linker |
| 390 | \\ -fno-LLD Prevent using LLD as the linker | 391 | \\ -fno-LLD Prevent using LLD as the linker |
| 391 | \\ -fcompiler-rt Always include compiler-rt symbols in output | 392 | \\ -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 | }; |
| 1754 | 1760 | ||
| 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 | }; |
| 1759 | 1765 | ||
| ... | @@ -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(); |
| 1858 | 1864 | ||
| 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 |
| 2396 | 2417 | ||
| 2397 | // If a .pdb file is part of the expected output, we must also copy | 2418 | // 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 destination | 2423 | // 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; |
| 2095 | 2096 | ||
| ... | @@ -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; | ||
| 8509 | 8510 | ||
| 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); | ||
| 8513 | 8515 | ||
| 8514 | // Unfortunately, LLVM shits the bed when we ask for both binary and assembly. So we call the entire | 8516 | // 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) { |
| 8527 | 8530 | ||
| 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 | } |
| 8535 | 8540 | ||
| ... | @@ -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); |
| 9539 | 9544 | ||
| 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); |
| 78 | 79 | ||
| ... | @@ -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; | ||
| 103 | 105 | ||
| 104 | g->subsystem = stage1->subsystem; | 106 | g->subsystem = stage1->subsystem; |
| 105 | 107 |
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; |
| 159 | 159 | ||
| 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; |
| 162 | 165 | ||
| ... | @@ -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; | ||
| 269 | 271 | ||
| 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; | ||
| 471 | 476 | ||
| 472 | zig_stage1_build_object(stage1); | 477 | zig_stage1_build_object(stage1); |
| 473 | 478 |
src/zig_llvm.cpp+17-2| ... | @@ -229,12 +229,14 @@ struct TimeTracerRAII { | ... | @@ -229,12 +229,14 @@ struct TimeTracerRAII { |
| 229 | bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, | 229 | bool 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; |
| 235 | 236 | ||
| 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; | ||
| 238 | 240 | ||
| 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 | } | ||
| 255 | 265 | ||
| 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 | |||
| 258 | 270 | ||
| 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 | } | ||
| 392 | 407 | ||
| 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); |
| 49 | ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, | 49 | ZIG_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); | ||
| 53 | 54 | ||
| 54 | 55 | ||
| 55 | enum ZigLLVMABIType { | 56 | enum ZigLLVMABIType { |