authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-23 17:06:19+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-07-23 17:06:19+02:00
log5533f77054acad376f2fce0d529569a7449e9949
treeeba6945383fefa59a8858f7eec8beee3cfca7731
parent1beda818e1c10bde98b35759b3c131a864be58d9
parente5b476209a1215a03164890d331e2013f20882a6

Merge remote-tracking branch 'origin/master' into zld-incremental-2


32 files changed, 963 insertions(+), 270 deletions(-)

CMakeLists.txt+1
...@@ -792,6 +792,7 @@ set(BUILD_ZIG1_ARGS...@@ -792,6 +792,7 @@ set(BUILD_ZIG1_ARGS
792 --name zig1792 --name zig1
793 --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib"793 --zig-lib-dir "${CMAKE_SOURCE_DIR}/lib"
794 "-femit-bin=${ZIG1_OBJECT}"794 "-femit-bin=${ZIG1_OBJECT}"
795 -fcompiler-rt
795 "${ZIG1_RELEASE_ARG}"796 "${ZIG1_RELEASE_ARG}"
796 "${ZIG1_SINGLE_THREADED_ARG}"797 "${ZIG1_SINGLE_THREADED_ARG}"
797 -lc798 -lc
doc/docgen.zig+4-4
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = std.builtin;2const builtin = @import("builtin");
3const io = std.io;3const io = std.io;
4const fs = std.fs;4const fs = std.fs;
5const process = std.process;5const process = std.process;
...@@ -13,7 +13,7 @@ const Allocator = std.mem.Allocator;...@@ -13,7 +13,7 @@ const Allocator = std.mem.Allocator;
13const max_doc_file_size = 10 * 1024 * 1024;13const max_doc_file_size = 10 * 1024 * 1024;
1414
15const exe_ext = @as(std.zig.CrossTarget, .{}).exeFileExt();15const exe_ext = @as(std.zig.CrossTarget, .{}).exeFileExt();
16const obj_ext = @as(std.zig.CrossTarget, .{}).oFileExt();16const obj_ext = builtin.object_format.fileExt(builtin.cpu.arch);
17const tmp_dir_name = "docgen_tmp";17const tmp_dir_name = "docgen_tmp";
18const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext;18const test_out_path = tmp_dir_name ++ fs.path.sep_str ++ "test" ++ exe_ext;
1919
...@@ -281,7 +281,7 @@ const Code = struct {...@@ -281,7 +281,7 @@ const Code = struct {
281 name: []const u8,281 name: []const u8,
282 source_token: Token,282 source_token: Token,
283 is_inline: bool,283 is_inline: bool,
284 mode: builtin.Mode,284 mode: std.builtin.Mode,
285 link_objects: []const []const u8,285 link_objects: []const []const u8,
286 target_str: ?[]const u8,286 target_str: ?[]const u8,
287 link_libc: bool,287 link_libc: bool,
...@@ -531,7 +531,7 @@ fn genToc(allocator: *Allocator, tokenizer: *Tokenizer) !Toc {...@@ -531,7 +531,7 @@ fn genToc(allocator: *Allocator, tokenizer: *Tokenizer) !Toc {
531 return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {s}", .{code_kind_str});531 return parseError(tokenizer, code_kind_tok, "unrecognized code kind: {s}", .{code_kind_str});
532 }532 }
533533
534 var mode: builtin.Mode = .Debug;534 var mode: std.builtin.Mode = .Debug;
535 var link_objects = std.ArrayList([]const u8).init(allocator);535 var link_objects = std.ArrayList([]const u8).init(allocator);
536 defer link_objects.deinit();536 defer link_objects.deinit();
537 var target_str: ?[]const u8 = null;537 var target_str: ?[]const u8 = null;
doc/langref.html.in+8-9
...@@ -5337,16 +5337,15 @@ test "implicit cast to comptime_int" {...@@ -5337,16 +5337,15 @@ test "implicit cast to comptime_int" {
5337}5337}
5338 {#code_end#}5338 {#code_end#}
5339 {#header_close#}5339 {#header_close#}
5340 {#header_open|Type Coercion: Arrays and Pointers#}5340 {#header_open|Type Coercion: Slices, Arrays and Pointers#}
5341 {#code_begin|test|coerce_arrays_and_ptrs#}5341 {#code_begin|test|coerce__slices_arrays_and_ptrs#}
5342const std = @import("std");5342const std = @import("std");
5343const expect = std.testing.expect;5343const expect = std.testing.expect;
53445344
5345// This cast exists primarily so that string literals can be5345// You can assign constant pointers to arrays to a slice with
5346// passed to functions that accept const slices. However5346// const modifier on the element type. Useful in particular for
5347// it is probably going to be removed from the language when5347// String literals.
5348// https://github.com/ziglang/zig/issues/265 is implemented.5348test "*const [N]T to []const T" {
5349test "[N]T to []const T" {
5350 var x1: []const u8 = "hello";5349 var x1: []const u8 = "hello";
5351 var x2: []const u8 = &[5]u8{ 'h', 'e', 'l', 'l', 111 };5350 var x2: []const u8 = &[5]u8{ 'h', 'e', 'l', 'l', 111 };
5352 try expect(std.mem.eql(u8, x1, x2));5351 try expect(std.mem.eql(u8, x1, x2));
...@@ -5356,7 +5355,7 @@ test "[N]T to []const T" {...@@ -5356,7 +5355,7 @@ test "[N]T to []const T" {
5356}5355}
53575356
5358// Likewise, it works when the destination type is an error union.5357// Likewise, it works when the destination type is an error union.
5359test "[N]T to E![]const T" {5358test "*const [N]T to E![]const T" {
5360 var x1: anyerror![]const u8 = "hello";5359 var x1: anyerror![]const u8 = "hello";
5361 var x2: anyerror![]const u8 = &[5]u8{ 'h', 'e', 'l', 'l', 111 };5360 var x2: anyerror![]const u8 = &[5]u8{ 'h', 'e', 'l', 'l', 111 };
5362 try expect(std.mem.eql(u8, try x1, try x2));5361 try expect(std.mem.eql(u8, try x1, try x2));
...@@ -5366,7 +5365,7 @@ test "[N]T to E![]const T" {...@@ -5366,7 +5365,7 @@ test "[N]T to E![]const T" {
5366}5365}
53675366
5368// Likewise, it works when the destination type is an optional.5367// Likewise, it works when the destination type is an optional.
5369test "[N]T to ?[]const T" {5368test "*const [N]T to ?[]const T" {
5370 var x1: ?[]const u8 = "hello";5369 var x1: ?[]const u8 = "hello";
5371 var x2: ?[]const u8 = &[5]u8{ 'h', 'e', 'l', 'l', 111 };5370 var x2: ?[]const u8 = &[5]u8{ 'h', 'e', 'l', 'l', 111 };
5372 try expect(std.mem.eql(u8, x1.?, x2.?));5371 try expect(std.mem.eql(u8, x1.?, x2.?));
lib/std/crypto/25519/field.zig+2-2
...@@ -93,7 +93,7 @@ pub const Fe = struct {...@@ -93,7 +93,7 @@ pub const Fe = struct {
93 return s;93 return s;
94 }94 }
9595
96 /// Map a 64-bit big endian string into a field element96 /// Map a 64 bytes big endian string into a field element
97 pub fn fromBytes64(s: [64]u8) Fe {97 pub fn fromBytes64(s: [64]u8) Fe {
98 var fl: [32]u8 = undefined;98 var fl: [32]u8 = undefined;
99 var gl: [32]u8 = undefined;99 var gl: [32]u8 = undefined;
...@@ -106,7 +106,7 @@ pub const Fe = struct {...@@ -106,7 +106,7 @@ pub const Fe = struct {
106 gl[31] &= 0x7f;106 gl[31] &= 0x7f;
107 var fe_f = fromBytes(fl);107 var fe_f = fromBytes(fl);
108 const fe_g = fromBytes(gl);108 const fe_g = fromBytes(gl);
109 fe_f.limbs[0] += (s[32] >> 7) * 19;109 fe_f.limbs[0] += (s[32] >> 7) * 19 + @as(u10, s[0] >> 7) * 722;
110 i = 0;110 i = 0;
111 while (i < 5) : (i += 1) {111 while (i < 5) : (i += 1) {
112 fe_f.limbs[i] += 38 * fe_g.limbs[i];112 fe_f.limbs[i] += 38 * fe_g.limbs[i];
lib/std/os/bits/linux.zig+5-5
...@@ -339,19 +339,19 @@ pub const O_RDWR = 0o2;...@@ -339,19 +339,19 @@ pub const O_RDWR = 0o2;
339pub const kernel_rwf = u32;339pub const kernel_rwf = u32;
340340
341/// high priority request, poll if possible341/// high priority request, poll if possible
342pub const RWF_HIPRI = kernel_rwf(0x00000001);342pub const RWF_HIPRI: kernel_rwf = 0x00000001;
343343
344/// per-IO O_DSYNC344/// per-IO O_DSYNC
345pub const RWF_DSYNC = kernel_rwf(0x00000002);345pub const RWF_DSYNC: kernel_rwf = 0x00000002;
346346
347/// per-IO O_SYNC347/// per-IO O_SYNC
348pub const RWF_SYNC = kernel_rwf(0x00000004);348pub const RWF_SYNC: kernel_rwf = 0x00000004;
349349
350/// per-IO, return -EAGAIN if operation would block350/// per-IO, return -EAGAIN if operation would block
351pub const RWF_NOWAIT = kernel_rwf(0x00000008);351pub const RWF_NOWAIT: kernel_rwf = 0x00000008;
352352
353/// per-IO O_APPEND353/// per-IO O_APPEND
354pub const RWF_APPEND = kernel_rwf(0x00000010);354pub const RWF_APPEND: kernel_rwf = 0x00000010;
355355
356pub const SEEK_SET = 0;356pub const SEEK_SET = 0;
357pub const SEEK_CUR = 1;357pub const SEEK_CUR = 1;
lib/std/os/windows/user32.zig+1-1
...@@ -1336,7 +1336,7 @@ pub extern "user32" fn AdjustWindowRectEx(lpRect: *RECT, dwStyle: DWORD, bMenu:...@@ -1336,7 +1336,7 @@ pub extern "user32" fn AdjustWindowRectEx(lpRect: *RECT, dwStyle: DWORD, bMenu:
1336pub fn adjustWindowRectEx(lpRect: *RECT, dwStyle: u32, bMenu: bool, dwExStyle: u32) !void {1336pub fn adjustWindowRectEx(lpRect: *RECT, dwStyle: u32, bMenu: bool, dwExStyle: u32) !void {
1337 assert(dwStyle & WS_OVERLAPPED == 0);1337 assert(dwStyle & WS_OVERLAPPED == 0);
13381338
1339 if (AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle) == 0) {1339 if (AdjustWindowRectEx(lpRect, dwStyle, @boolToInt(bMenu), dwExStyle) == 0) {
1340 switch (GetLastError()) {1340 switch (GetLastError()) {
1341 .INVALID_PARAMETER => unreachable,1341 .INVALID_PARAMETER => unreachable,
1342 else => |err| return windows.unexpectedError(err),1342 else => |err| return windows.unexpectedError(err),
lib/std/target.zig+63-37
...@@ -549,16 +549,36 @@ pub const Target = struct {...@@ -549,16 +549,36 @@ pub const Target = struct {
549 };549 };
550550
551 pub const ObjectFormat = enum {551 pub const ObjectFormat = enum {
552 /// Common Object File Format (Windows)
552 coff,553 coff,
553 pe,554 /// Executable and Linking Format
554 elf,555 elf,
556 /// macOS relocatables
555 macho,557 macho,
558 /// WebAssembly
556 wasm,559 wasm,
560 /// C source code
557 c,561 c,
562 /// Standard, Portable Intermediate Representation V
558 spirv,563 spirv,
564 /// Intel IHEX
559 hex,565 hex,
566 /// Machine code with no metadata.
560 raw,567 raw,
568 /// Plan 9 from Bell Labs
561 plan9,569 plan9,
570
571 pub fn fileExt(of: ObjectFormat, cpu_arch: Cpu.Arch) [:0]const u8 {
572 return switch (of) {
573 .coff => ".obj",
574 .elf, .macho, .wasm => ".o",
575 .c => ".c",
576 .spirv => ".spv",
577 .hex => ".ihex",
578 .raw => ".bin",
579 .plan9 => plan9Ext(cpu_arch),
580 };
581 }
562 };582 };
563583
564 pub const SubSystem = enum {584 pub const SubSystem = enum {
...@@ -1290,30 +1310,16 @@ pub const Target = struct {...@@ -1290,30 +1310,16 @@ pub const Target = struct {
1290 return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi);1310 return linuxTripleSimple(allocator, self.cpu.arch, self.os.tag, self.abi);
1291 }1311 }
12921312
1293 pub fn oFileExt_os_abi(os_tag: Os.Tag, abi: Abi) [:0]const u8 {
1294 if (abi == .msvc) {
1295 return ".obj";
1296 }
1297 switch (os_tag) {
1298 .windows, .uefi => return ".obj",
1299 else => return ".o",
1300 }
1301 }
1302
1303 pub fn oFileExt(self: Target) [:0]const u8 {
1304 return oFileExt_os_abi(self.os.tag, self.abi);
1305 }
1306
1307 pub fn exeFileExtSimple(cpu_arch: Cpu.Arch, os_tag: Os.Tag) [:0]const u8 {1313 pub fn exeFileExtSimple(cpu_arch: Cpu.Arch, os_tag: Os.Tag) [:0]const u8 {
1308 switch (os_tag) {1314 return switch (os_tag) {
1309 .windows => return ".exe",1315 .windows => ".exe",
1310 .uefi => return ".efi",1316 .uefi => ".efi",
1311 else => if (cpu_arch.isWasm()) {1317 .plan9 => plan9Ext(cpu_arch),
1312 return ".wasm";1318 else => switch (cpu_arch) {
1313 } else {1319 .wasm32, .wasm64 => ".wasm",
1314 return "";1320 else => "",
1315 },1321 },
1316 }1322 };
1317 }1323 }
13181324
1319 pub fn exeFileExt(self: Target) [:0]const u8 {1325 pub fn exeFileExt(self: Target) [:0]const u8 {
...@@ -1353,20 +1359,16 @@ pub const Target = struct {...@@ -1353,20 +1359,16 @@ pub const Target = struct {
1353 }1359 }
13541360
1355 pub fn getObjectFormatSimple(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat {1361 pub fn getObjectFormatSimple(os_tag: Os.Tag, cpu_arch: Cpu.Arch) ObjectFormat {
1356 if (os_tag == .windows or os_tag == .uefi) {1362 return switch (os_tag) {
1357 return .coff;1363 .windows, .uefi => .coff,
1358 } else if (os_tag.isDarwin()) {1364 .ios, .macos, .watchos, .tvos => .macho,
1359 return .macho;1365 .plan9 => .plan9,
1360 }1366 else => return switch (cpu_arch) {
1361 if (cpu_arch.isWasm()) {1367 .wasm32, .wasm64 => .wasm,
1362 return .wasm;1368 .spirv32, .spirv64 => .spirv,
1363 }1369 else => .elf,
1364 if (cpu_arch.isSPIRV()) {1370 },
1365 return .spirv;1371 };
1366 }
1367 if (os_tag == .plan9)
1368 return .plan9;
1369 return .elf;
1370 }1372 }
13711373
1372 pub fn getObjectFormat(self: Target) ObjectFormat {1374 pub fn getObjectFormat(self: Target) ObjectFormat {
...@@ -1677,6 +1679,30 @@ pub const Target = struct {...@@ -1677,6 +1679,30 @@ pub const Target = struct {
16771679
1678 return false;1680 return false;
1679 }1681 }
1682
1683 /// 0c spim little-endian MIPS 3000 family
1684 /// 1c 68000 Motorola MC68000
1685 /// 2c 68020 Motorola MC68020
1686 /// 5c arm little-endian ARM
1687 /// 6c amd64 AMD64 and compatibles (e.g., Intel EM64T)
1688 /// 7c arm64 ARM64 (ARMv8)
1689 /// 8c 386 Intel i386, i486, Pentium, etc.
1690 /// kc sparc Sun SPARC
1691 /// qc power Power PC
1692 /// vc mips big-endian MIPS 3000 family
1693 pub fn plan9Ext(cpu_arch: Cpu.Arch) [:0]const u8 {
1694 return switch (cpu_arch) {
1695 .arm => ".5",
1696 .x86_64 => ".6",
1697 .aarch64 => ".7",
1698 .i386 => ".8",
1699 .sparc => ".k",
1700 .powerpc, .powerpcle => ".q",
1701 .mips, .mipsel => ".v",
1702 // ISAs without designated characters get 'X' for lack of a better option.
1703 else => ".X",
1704 };
1705 }
1680};1706};
16811707
1682test {1708test {
lib/std/zig.zig+10-30
...@@ -108,8 +108,9 @@ pub const BinNameOptions = struct {...@@ -108,8 +108,9 @@ pub const BinNameOptions = struct {
108pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) error{OutOfMemory}![]u8 {108pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) error{OutOfMemory}![]u8 {
109 const root_name = options.root_name;109 const root_name = options.root_name;
110 const target = options.target;110 const target = options.target;
111 switch (options.object_format orelse target.getObjectFormat()) {111 const ofmt = options.object_format orelse target.getObjectFormat();
112 .coff, .pe => switch (options.output_mode) {112 switch (ofmt) {
113 .coff => switch (options.output_mode) {
113 .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.exeFileExt() }),114 .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.exeFileExt() }),
114 .Lib => {115 .Lib => {
115 const suffix = switch (options.link_mode orelse .Static) {116 const suffix = switch (options.link_mode orelse .Static) {
...@@ -118,7 +119,7 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro...@@ -118,7 +119,7 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro
118 };119 };
119 return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, suffix });120 return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, suffix });
120 },121 },
121 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.oFileExt() }),122 .Obj => return std.fmt.allocPrint(allocator, "{s}.obj", .{root_name}),
122 },123 },
123 .elf => switch (options.output_mode) {124 .elf => switch (options.output_mode) {
124 .Exe => return allocator.dupe(u8, root_name),125 .Exe => return allocator.dupe(u8, root_name),
...@@ -140,7 +141,7 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro...@@ -140,7 +141,7 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro
140 },141 },
141 }142 }
142 },143 },
143 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.oFileExt() }),144 .Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}),
144 },145 },
145 .macho => switch (options.output_mode) {146 .macho => switch (options.output_mode) {
146 .Exe => return allocator.dupe(u8, root_name),147 .Exe => return allocator.dupe(u8, root_name),
...@@ -163,7 +164,7 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro...@@ -163,7 +164,7 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro
163 }164 }
164 return std.fmt.allocPrint(allocator, "{s}{s}{s}", .{ target.libPrefix(), root_name, suffix });165 return std.fmt.allocPrint(allocator, "{s}{s}{s}", .{ target.libPrefix(), root_name, suffix });
165 },166 },
166 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.oFileExt() }),167 .Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}),
167 },168 },
168 .wasm => switch (options.output_mode) {169 .wasm => switch (options.output_mode) {
169 .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.exeFileExt() }),170 .Exe => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.exeFileExt() }),
...@@ -175,36 +176,15 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro...@@ -175,36 +176,15 @@ pub fn binNameAlloc(allocator: *std.mem.Allocator, options: BinNameOptions) erro
175 .Dynamic => return std.fmt.allocPrint(allocator, "{s}.wasm", .{root_name}),176 .Dynamic => return std.fmt.allocPrint(allocator, "{s}.wasm", .{root_name}),
176 }177 }
177 },178 },
178 .Obj => return std.fmt.allocPrint(allocator, "{s}{s}", .{ root_name, target.oFileExt() }),179 .Obj => return std.fmt.allocPrint(allocator, "{s}.o", .{root_name}),
179 },180 },
180 .c => return std.fmt.allocPrint(allocator, "{s}.c", .{root_name}),181 .c => return std.fmt.allocPrint(allocator, "{s}.c", .{root_name}),
181 .spirv => return std.fmt.allocPrint(allocator, "{s}.spv", .{root_name}),182 .spirv => return std.fmt.allocPrint(allocator, "{s}.spv", .{root_name}),
182 .hex => return std.fmt.allocPrint(allocator, "{s}.ihex", .{root_name}),183 .hex => return std.fmt.allocPrint(allocator, "{s}.ihex", .{root_name}),
183 .raw => return std.fmt.allocPrint(allocator, "{s}.bin", .{root_name}),184 .raw => return std.fmt.allocPrint(allocator, "{s}.bin", .{root_name}),
184 .plan9 => {185 .plan9 => return std.fmt.allocPrint(allocator, "{s}{s}", .{
185 // copied from 2c(1)186 root_name, ofmt.fileExt(target.cpu.arch),
186 // 0c spim little-endian MIPS 3000 family187 }),
187 // 1c 68000 Motorola MC68000
188 // 2c 68020 Motorola MC68020
189 // 5c arm little-endian ARM
190 // 6c amd64 AMD64 and compatibles (e.g., Intel EM64T)
191 // 7c arm64 ARM64 (ARMv8)
192 // 8c 386 Intel i386, i486, Pentium, etc.
193 // kc sparc Sun SPARC
194 // qc power Power PC
195 // vc mips big-endian MIPS 3000 family
196 const char: u8 = switch (target.cpu.arch) {
197 .arm => '5',
198 .x86_64 => '6',
199 .aarch64 => '7',
200 .i386 => '8',
201 .sparc => 'k',
202 .powerpc, .powerpcle => 'q',
203 .mips, .mipsel => 'v',
204 else => 'X', // this arch does not have a char or maybe was not ported to plan9 so we just use X
205 };
206 return std.fmt.allocPrint(allocator, "{s}.{c}", .{ root_name, char });
207 },
208 }188 }
209}189}
210190
lib/std/zig/c_translation.zig+132
...@@ -350,3 +350,135 @@ test "Flexible Array Type" {...@@ -350,3 +350,135 @@ test "Flexible Array Type" {
350 try testing.expectEqual(FlexibleArrayType(*volatile Container, c_int), [*c]volatile c_int);350 try testing.expectEqual(FlexibleArrayType(*volatile Container, c_int), [*c]volatile c_int);
351 try testing.expectEqual(FlexibleArrayType(*const volatile Container, c_int), [*c]const volatile c_int);351 try testing.expectEqual(FlexibleArrayType(*const volatile Container, c_int), [*c]const volatile c_int);
352}352}
353
354pub const Macros = struct {
355 pub fn U_SUFFIX(comptime n: comptime_int) @TypeOf(promoteIntLiteral(c_uint, n, .decimal)) {
356 return promoteIntLiteral(c_uint, n, .decimal);
357 }
358
359 fn L_SUFFIX_ReturnType(comptime number: anytype) type {
360 switch (@TypeOf(number)) {
361 comptime_int => return @TypeOf(promoteIntLiteral(c_long, number, .decimal)),
362 comptime_float => return c_longdouble,
363 else => @compileError("Invalid value for L suffix"),
364 }
365 }
366 pub fn L_SUFFIX(comptime number: anytype) L_SUFFIX_ReturnType(number) {
367 switch (@TypeOf(number)) {
368 comptime_int => return promoteIntLiteral(c_long, number, .decimal),
369 comptime_float => @compileError("TODO: c_longdouble initialization from comptime_float not supported"),
370 else => @compileError("Invalid value for L suffix"),
371 }
372 }
373
374 pub fn UL_SUFFIX(comptime n: comptime_int) @TypeOf(promoteIntLiteral(c_ulong, n, .decimal)) {
375 return promoteIntLiteral(c_ulong, n, .decimal);
376 }
377
378 pub fn LL_SUFFIX(comptime n: comptime_int) @TypeOf(promoteIntLiteral(c_longlong, n, .decimal)) {
379 return promoteIntLiteral(c_longlong, n, .decimal);
380 }
381
382 pub fn ULL_SUFFIX(comptime n: comptime_int) @TypeOf(promoteIntLiteral(c_ulonglong, n, .decimal)) {
383 return promoteIntLiteral(c_ulonglong, n, .decimal);
384 }
385
386 pub fn F_SUFFIX(comptime f: comptime_float) f32 {
387 return @as(f32, f);
388 }
389
390 pub fn WL_CONTAINER_OF(ptr: anytype, sample: anytype, comptime member: []const u8) @TypeOf(sample) {
391 return @fieldParentPtr(@TypeOf(sample.*), member, ptr);
392 }
393
394 /// A 2-argument function-like macro defined as #define FOO(A, B) (A)(B)
395 /// could be either: cast B to A, or call A with the value B.
396 pub fn CAST_OR_CALL(a: anytype, b: anytype) switch (@typeInfo(@TypeOf(a))) {
397 .Type => a,
398 .Fn => |fn_info| fn_info.return_type orelse void,
399 else => |info| @compileError("Unexpected argument type: " ++ @tagName(info)),
400 } {
401 switch (@typeInfo(@TypeOf(a))) {
402 .Type => return cast(a, b),
403 .Fn => return a(b),
404 else => unreachable, // return type will be a compile error otherwise
405 }
406 }
407};
408
409test "Macro suffix functions" {
410 try testing.expect(@TypeOf(Macros.F_SUFFIX(1)) == f32);
411
412 try testing.expect(@TypeOf(Macros.U_SUFFIX(1)) == c_uint);
413 if (math.maxInt(c_ulong) > math.maxInt(c_uint)) {
414 try testing.expect(@TypeOf(Macros.U_SUFFIX(math.maxInt(c_uint) + 1)) == c_ulong);
415 }
416 if (math.maxInt(c_ulonglong) > math.maxInt(c_ulong)) {
417 try testing.expect(@TypeOf(Macros.U_SUFFIX(math.maxInt(c_ulong) + 1)) == c_ulonglong);
418 }
419
420 try testing.expect(@TypeOf(Macros.L_SUFFIX(1)) == c_long);
421 if (math.maxInt(c_long) > math.maxInt(c_int)) {
422 try testing.expect(@TypeOf(Macros.L_SUFFIX(math.maxInt(c_int) + 1)) == c_long);
423 }
424 if (math.maxInt(c_longlong) > math.maxInt(c_long)) {
425 try testing.expect(@TypeOf(Macros.L_SUFFIX(math.maxInt(c_long) + 1)) == c_longlong);
426 }
427
428 try testing.expect(@TypeOf(Macros.UL_SUFFIX(1)) == c_ulong);
429 if (math.maxInt(c_ulonglong) > math.maxInt(c_ulong)) {
430 try testing.expect(@TypeOf(Macros.UL_SUFFIX(math.maxInt(c_ulong) + 1)) == c_ulonglong);
431 }
432
433 try testing.expect(@TypeOf(Macros.LL_SUFFIX(1)) == c_longlong);
434 try testing.expect(@TypeOf(Macros.ULL_SUFFIX(1)) == c_ulonglong);
435}
436
437test "WL_CONTAINER_OF" {
438 const S = struct {
439 a: u32 = 0,
440 b: u32 = 0,
441 };
442 var x = S{};
443 var y = S{};
444 var ptr = Macros.WL_CONTAINER_OF(&x.b, &y, "b");
445 try testing.expectEqual(&x, ptr);
446}
447
448test "CAST_OR_CALL casting" {
449 var arg = @as(c_int, 1000);
450 var casted = Macros.CAST_OR_CALL(u8, arg);
451 try testing.expectEqual(cast(u8, arg), casted);
452
453 const S = struct {
454 x: u32 = 0,
455 };
456 var s = S{};
457 var casted_ptr = Macros.CAST_OR_CALL(*u8, &s);
458 try testing.expectEqual(cast(*u8, &s), casted_ptr);
459}
460
461test "CAST_OR_CALL calling" {
462 const Helper = struct {
463 var last_val: bool = false;
464 fn returnsVoid(val: bool) void {
465 last_val = val;
466 }
467 fn returnsBool(f: f32) bool {
468 return f > 0;
469 }
470 fn identity(self: c_uint) c_uint {
471 return self;
472 }
473 };
474
475 Macros.CAST_OR_CALL(Helper.returnsVoid, true);
476 try testing.expectEqual(true, Helper.last_val);
477 Macros.CAST_OR_CALL(Helper.returnsVoid, false);
478 try testing.expectEqual(false, Helper.last_val);
479
480 try testing.expectEqual(Helper.returnsBool(1), Macros.CAST_OR_CALL(Helper.returnsBool, @as(f32, 1)));
481 try testing.expectEqual(Helper.returnsBool(-1), Macros.CAST_OR_CALL(Helper.returnsBool, @as(f32, -1)));
482
483 try testing.expectEqual(Helper.identity(@as(c_uint, 100)), Macros.CAST_OR_CALL(Helper.identity, @as(c_uint, 100)));
484}
lib/std/zig/cross_target.zig-4
...@@ -473,10 +473,6 @@ pub const CrossTarget = struct {...@@ -473,10 +473,6 @@ pub const CrossTarget = struct {
473 return self.getOsTag() == .windows;473 return self.getOsTag() == .windows;
474 }474 }
475475
476 pub fn oFileExt(self: CrossTarget) [:0]const u8 {
477 return Target.oFileExt_os_abi(self.getOsTag(), self.getAbi());
478 }
479
480 pub fn exeFileExt(self: CrossTarget) [:0]const u8 {476 pub fn exeFileExt(self: CrossTarget) [:0]const u8 {
481 return Target.exeFileExtSimple(self.getCpuArch(), self.getOsTag());477 return Target.exeFileExtSimple(self.getCpuArch(), self.getOsTag());
482 }478 }
src/AstGen.zig+10-1
...@@ -5009,6 +5009,7 @@ fn ifExpr(...@@ -5009,6 +5009,7 @@ fn ifExpr(
5009 const token_name_str = tree.tokenSlice(token_name_index);5009 const token_name_str = tree.tokenSlice(token_name_index);
5010 if (mem.eql(u8, "_", token_name_str))5010 if (mem.eql(u8, "_", token_name_str))
5011 break :s &then_scope.base;5011 break :s &then_scope.base;
5012 try astgen.detectLocalShadowing(&then_scope.base, ident_name, token_name_index);
5012 payload_val_scope = .{5013 payload_val_scope = .{
5013 .parent = &then_scope.base,5014 .parent = &then_scope.base,
5014 .gen_zir = &then_scope,5015 .gen_zir = &then_scope,
...@@ -5031,6 +5032,7 @@ fn ifExpr(...@@ -5031,6 +5032,7 @@ fn ifExpr(
5031 break :s &then_scope.base;5032 break :s &then_scope.base;
5032 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);5033 const payload_inst = try then_scope.addUnNode(tag, cond.inst, node);
5033 const ident_name = try astgen.identAsString(ident_token);5034 const ident_name = try astgen.identAsString(ident_token);
5035 try astgen.detectLocalShadowing(&then_scope.base, ident_name, ident_token);
5034 payload_val_scope = .{5036 payload_val_scope = .{
5035 .parent = &then_scope.base,5037 .parent = &then_scope.base,
5036 .gen_zir = &then_scope,5038 .gen_zir = &then_scope,
...@@ -5072,6 +5074,7 @@ fn ifExpr(...@@ -5072,6 +5074,7 @@ fn ifExpr(
5072 const error_token_str = tree.tokenSlice(error_token);5074 const error_token_str = tree.tokenSlice(error_token);
5073 if (mem.eql(u8, "_", error_token_str))5075 if (mem.eql(u8, "_", error_token_str))
5074 break :s &else_scope.base;5076 break :s &else_scope.base;
5077 try astgen.detectLocalShadowing(&else_scope.base, ident_name, error_token);
5075 payload_val_scope = .{5078 payload_val_scope = .{
5076 .parent = &else_scope.base,5079 .parent = &else_scope.base,
5077 .gen_zir = &else_scope,5080 .gen_zir = &else_scope,
...@@ -5265,7 +5268,9 @@ fn whileExpr(...@@ -5265,7 +5268,9 @@ fn whileExpr(
5265 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token;5268 const ident_token = if (payload_is_ref) payload_token + 1 else payload_token;
5266 if (mem.eql(u8, "_", tree.tokenSlice(ident_token)))5269 if (mem.eql(u8, "_", tree.tokenSlice(ident_token)))
5267 break :s &then_scope.base;5270 break :s &then_scope.base;
5268 const ident_name = try astgen.identAsString(payload_token + @boolToInt(payload_is_ref));5271 const payload_name_loc = payload_token + @boolToInt(payload_is_ref);
5272 const ident_name = try astgen.identAsString(payload_name_loc);
5273 try astgen.detectLocalShadowing(&then_scope.base, ident_name, payload_name_loc);
5269 payload_val_scope = .{5274 payload_val_scope = .{
5270 .parent = &then_scope.base,5275 .parent = &then_scope.base,
5271 .gen_zir = &then_scope,5276 .gen_zir = &then_scope,
...@@ -5288,6 +5293,7 @@ fn whileExpr(...@@ -5288,6 +5293,7 @@ fn whileExpr(
5288 const ident_name = try astgen.identAsString(ident_token);5293 const ident_name = try astgen.identAsString(ident_token);
5289 if (mem.eql(u8, "_", tree.tokenSlice(ident_token)))5294 if (mem.eql(u8, "_", tree.tokenSlice(ident_token)))
5290 break :s &then_scope.base;5295 break :s &then_scope.base;
5296 try astgen.detectLocalShadowing(&then_scope.base, ident_name, ident_token);
5291 payload_val_scope = .{5297 payload_val_scope = .{
5292 .parent = &then_scope.base,5298 .parent = &then_scope.base,
5293 .gen_zir = &then_scope,5299 .gen_zir = &then_scope,
...@@ -5345,6 +5351,7 @@ fn whileExpr(...@@ -5345,6 +5351,7 @@ fn whileExpr(
5345 const ident_name = try astgen.identAsString(error_token);5351 const ident_name = try astgen.identAsString(error_token);
5346 if (mem.eql(u8, tree.tokenSlice(error_token), "_"))5352 if (mem.eql(u8, tree.tokenSlice(error_token), "_"))
5347 break :s &else_scope.base;5353 break :s &else_scope.base;
5354 try astgen.detectLocalShadowing(&else_scope.base, ident_name, error_token);
5348 payload_val_scope = .{5355 payload_val_scope = .{
5349 .parent = &else_scope.base,5356 .parent = &else_scope.base,
5350 .gen_zir = &else_scope,5357 .gen_zir = &else_scope,
...@@ -5484,6 +5491,7 @@ fn forExpr(...@@ -5484,6 +5491,7 @@ fn forExpr(
5484 const name_str_index = try astgen.identAsString(ident);5491 const name_str_index = try astgen.identAsString(ident);
5485 const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val;5492 const tag: Zir.Inst.Tag = if (is_ptr) .elem_ptr else .elem_val;
5486 const payload_inst = try then_scope.addBin(tag, array_ptr, index);5493 const payload_inst = try then_scope.addBin(tag, array_ptr, index);
5494 try astgen.detectLocalShadowing(&then_scope.base, name_str_index, ident);
5487 payload_val_scope = .{5495 payload_val_scope = .{
5488 .parent = &then_scope.base,5496 .parent = &then_scope.base,
5489 .gen_zir = &then_scope,5497 .gen_zir = &then_scope,
...@@ -5507,6 +5515,7 @@ fn forExpr(...@@ -5507,6 +5515,7 @@ fn forExpr(
5507 return astgen.failTok(index_token, "discard of index capture; omit it instead", .{});5515 return astgen.failTok(index_token, "discard of index capture; omit it instead", .{});
5508 }5516 }
5509 const index_name = try astgen.identAsString(index_token);5517 const index_name = try astgen.identAsString(index_token);
5518 try astgen.detectLocalShadowing(payload_sub_scope, index_name, index_token);
5510 index_scope = .{5519 index_scope = .{
5511 .parent = payload_sub_scope,5520 .parent = payload_sub_scope,
5512 .gen_zir = &then_scope,5521 .gen_zir = &then_scope,
src/Compilation.zig+59-18
...@@ -143,6 +143,7 @@ debug_compiler_runtime_libs: bool,...@@ -143,6 +143,7 @@ debug_compiler_runtime_libs: bool,
143143
144emit_asm: ?EmitLoc,144emit_asm: ?EmitLoc,
145emit_llvm_ir: ?EmitLoc,145emit_llvm_ir: ?EmitLoc,
146emit_llvm_bc: ?EmitLoc,
146emit_analysis: ?EmitLoc,147emit_analysis: ?EmitLoc,
147emit_docs: ?EmitLoc,148emit_docs: ?EmitLoc,
148149
...@@ -586,6 +587,17 @@ pub const Directory = struct {...@@ -586,6 +587,17 @@ pub const Directory = struct {
586 return std.fs.path.join(allocator, paths);587 return std.fs.path.join(allocator, paths);
587 }588 }
588 }589 }
590
591 pub fn joinZ(self: Directory, allocator: *Allocator, paths: []const []const u8) ![:0]u8 {
592 if (self.path) |p| {
593 // TODO clean way to do this with only 1 allocation
594 const part2 = try std.fs.path.join(allocator, paths);
595 defer allocator.free(part2);
596 return std.fs.path.joinZ(allocator, &[_][]const u8{ p, part2 });
597 } else {
598 return std.fs.path.joinZ(allocator, paths);
599 }
600 }
589};601};
590602
591pub const EmitLoc = struct {603pub const EmitLoc = struct {
...@@ -623,6 +635,8 @@ pub const InitOptions = struct {...@@ -623,6 +635,8 @@ pub const InitOptions = struct {
623 emit_asm: ?EmitLoc = null,635 emit_asm: ?EmitLoc = null,
624 /// `null` means to not emit LLVM IR.636 /// `null` means to not emit LLVM IR.
625 emit_llvm_ir: ?EmitLoc = null,637 emit_llvm_ir: ?EmitLoc = null,
638 /// `null` means to not emit LLVM module bitcode.
639 emit_llvm_bc: ?EmitLoc = null,
626 /// `null` means to not emit semantic analysis JSON.640 /// `null` means to not emit semantic analysis JSON.
627 emit_analysis: ?EmitLoc = null,641 emit_analysis: ?EmitLoc = null,
628 /// `null` means to not emit docs.642 /// `null` means to not emit docs.
...@@ -812,6 +826,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -812,6 +826,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
812 const ofmt = options.object_format orelse options.target.getObjectFormat();826 const ofmt = options.object_format orelse options.target.getObjectFormat();
813827
814 const use_stage1 = options.use_stage1 orelse blk: {828 const use_stage1 = options.use_stage1 orelse blk: {
829 // Even though we may have no Zig code to compile (depending on `options.root_pkg`),
830 // we may need to use stage1 for building compiler-rt and other dependencies.
831
815 if (build_options.omit_stage2)832 if (build_options.omit_stage2)
816 break :blk true;833 break :blk true;
817 if (options.use_llvm) |use_llvm| {834 if (options.use_llvm) |use_llvm| {
...@@ -819,6 +836,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -819,6 +836,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
819 break :blk false;836 break :blk false;
820 }837 }
821 }838 }
839
822 break :blk build_options.is_stage1;840 break :blk build_options.is_stage1;
823 };841 };
824842
...@@ -835,6 +853,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -835,6 +853,10 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
835 if (ofmt == .c)853 if (ofmt == .c)
836 break :blk false;854 break :blk false;
837855
856 // If emitting to LLVM bitcode object format, must use LLVM backend.
857 if (options.emit_llvm_ir != null or options.emit_llvm_bc != null)
858 break :blk true;
859
838 // The stage1 compiler depends on the stage1 C++ LLVM backend860 // The stage1 compiler depends on the stage1 C++ LLVM backend
839 // to compile zig code.861 // to compile zig code.
840 if (use_stage1)862 if (use_stage1)
...@@ -853,6 +875,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -853,6 +875,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
853 if (options.machine_code_model != .default) {875 if (options.machine_code_model != .default) {
854 return error.MachineCodeModelNotSupportedWithoutLlvm;876 return error.MachineCodeModelNotSupportedWithoutLlvm;
855 }877 }
878 if (options.emit_llvm_ir != null or options.emit_llvm_bc != null) {
879 return error.EmittingLlvmModuleRequiresUsingLlvmBackend;
880 }
856 }881 }
857882
858 const tsan = options.want_tsan orelse false;883 const tsan = options.want_tsan orelse false;
...@@ -996,7 +1021,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -996,7 +1021,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
996 break :blk lm;1021 break :blk lm;
997 } else default_link_mode;1022 } else default_link_mode;
9981023
999 const dll_export_fns = if (options.dll_export_fns) |explicit| explicit else is_dyn_lib;1024 const dll_export_fns = if (options.dll_export_fns) |explicit| explicit else is_dyn_lib or options.rdynamic;
10001025
1001 const libc_dirs = try detectLibCIncludeDirs(1026 const libc_dirs = try detectLibCIncludeDirs(
1002 arena,1027 arena,
...@@ -1386,6 +1411,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -1386,6 +1411,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
1386 .bin_file = bin_file,1411 .bin_file = bin_file,
1387 .emit_asm = options.emit_asm,1412 .emit_asm = options.emit_asm,
1388 .emit_llvm_ir = options.emit_llvm_ir,1413 .emit_llvm_ir = options.emit_llvm_ir,
1414 .emit_llvm_bc = options.emit_llvm_bc,
1389 .emit_analysis = options.emit_analysis,1415 .emit_analysis = options.emit_analysis,
1390 .emit_docs = options.emit_docs,1416 .emit_docs = options.emit_docs,
1391 .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),1417 .work_queue = std.fifo.LinearFifo(Job, .Dynamic).init(gpa),
...@@ -1518,24 +1544,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -1518,24 +1544,19 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
1518 }1544 }
15191545
1520 // The `use_stage1` condition is here only because stage2 cannot yet build compiler-rt.1546 // The `use_stage1` condition is here only because stage2 cannot yet build compiler-rt.
1521 // Once it is capable this condition should be removed.1547 // Once it is capable this condition should be removed. When removing this condition,
1548 // also test the use case of `build-obj -fcompiler-rt` with the self-hosted compiler
1549 // and make sure the compiler-rt symbols are emitted. Currently this is hooked up for
1550 // stage1 but not stage2.
1522 if (comp.bin_file.options.use_stage1) {1551 if (comp.bin_file.options.use_stage1) {
1523 if (comp.bin_file.options.include_compiler_rt) {1552 if (comp.bin_file.options.include_compiler_rt) {
1524 if (is_exe_or_dyn_lib) {1553 if (is_exe_or_dyn_lib) {
1525 try comp.work_queue.writeItem(.{ .compiler_rt_lib = {} });1554 try comp.work_queue.writeItem(.{ .compiler_rt_lib = {} });
1526 } else {1555 } else if (options.output_mode != .Obj) {
1556 // If build-obj with -fcompiler-rt is requested, that is handled specially
1557 // elsewhere. In this case we are making a static library, so we ask
1558 // for a compiler-rt object to put in it.
1527 try comp.work_queue.writeItem(.{ .compiler_rt_obj = {} });1559 try comp.work_queue.writeItem(.{ .compiler_rt_obj = {} });
1528 if (comp.bin_file.options.object_format != .elf and
1529 comp.bin_file.options.output_mode == .Obj)
1530 {
1531 // For ELF we can rely on using -r to link multiple objects together into one,
1532 // but to truly support `build-obj -fcompiler-rt` will require virtually
1533 // injecting `_ = @import("compiler_rt.zig")` into the root source file of
1534 // the compilation.
1535 fatal("Embedding compiler-rt into {s} objects is not yet implemented.", .{
1536 @tagName(comp.bin_file.options.object_format),
1537 });
1538 }
1539 }1560 }
1540 }1561 }
1541 if (needs_c_symbols) {1562 if (needs_c_symbols) {
...@@ -2733,7 +2754,10 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P...@@ -2733,7 +2754,10 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
2733 comp.bin_file.options.root_name2754 comp.bin_file.options.root_name
2734 else2755 else
2735 c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len];2756 c_source_basename[0 .. c_source_basename.len - std.fs.path.extension(c_source_basename).len];
2736 const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{ o_basename_noext, comp.getTarget().oFileExt() });2757 const o_basename = try std.fmt.allocPrint(arena, "{s}{s}", .{
2758 o_basename_noext,
2759 comp.bin_file.options.object_format.fileExt(comp.bin_file.options.target.cpu.arch),
2760 });
27372761
2738 const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: {2762 const digest = if (!comp.disable_c_depfile and try man.hit()) man.final() else blk: {
2739 var argv = std.ArrayList([]const u8).init(comp.gpa);2763 var argv = std.ArrayList([]const u8).init(comp.gpa);
...@@ -3028,7 +3052,7 @@ pub fn addCCArgs(...@@ -3028,7 +3052,7 @@ pub fn addCCArgs(
3028 if (!comp.bin_file.options.strip) {3052 if (!comp.bin_file.options.strip) {
3029 try argv.append("-g");3053 try argv.append("-g");
3030 switch (comp.bin_file.options.object_format) {3054 switch (comp.bin_file.options.object_format) {
3031 .coff, .pe => try argv.append("-gcodeview"),3055 .coff => try argv.append("-gcodeview"),
3032 else => {},3056 else => {},
3033 }3057 }
3034 }3058 }
...@@ -3954,6 +3978,16 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -3954,6 +3978,16 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
3954 const id_symlink_basename = "stage1.id";3978 const id_symlink_basename = "stage1.id";
3955 const libs_txt_basename = "libs.txt";3979 const libs_txt_basename = "libs.txt";
39563980
3981 // The include_compiler_rt stored in the bin file options here means that we need
3982 // compiler-rt symbols *somehow*. However, in the context of using the stage1 backend
3983 // we need to tell stage1 to include compiler-rt only if stage1 is the place that
3984 // needs to provide those symbols. Otherwise the stage2 infrastructure will take care
3985 // of it in the linker, by putting compiler_rt.o into a static archive, or linking
3986 // compiler_rt.a against an executable. In other words we only want to set this flag
3987 // for stage1 if we are using build-obj.
3988 const include_compiler_rt = comp.bin_file.options.output_mode == .Obj and
3989 comp.bin_file.options.include_compiler_rt;
3990
3957 // We are about to obtain this lock, so here we give other processes a chance first.3991 // We are about to obtain this lock, so here we give other processes a chance first.
3958 comp.releaseStage1Lock();3992 comp.releaseStage1Lock();
39593993
...@@ -3975,6 +4009,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -3975,6 +4009,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
3975 man.hash.add(target.os.getVersionRange());4009 man.hash.add(target.os.getVersionRange());
3976 man.hash.add(comp.bin_file.options.dll_export_fns);4010 man.hash.add(comp.bin_file.options.dll_export_fns);
3977 man.hash.add(comp.bin_file.options.function_sections);4011 man.hash.add(comp.bin_file.options.function_sections);
4012 man.hash.add(include_compiler_rt);
3978 man.hash.add(comp.bin_file.options.is_test);4013 man.hash.add(comp.bin_file.options.is_test);
3979 man.hash.add(comp.bin_file.options.emit != null);4014 man.hash.add(comp.bin_file.options.emit != null);
3980 man.hash.add(mod.emit_h != null);4015 man.hash.add(mod.emit_h != null);
...@@ -3983,6 +4018,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -3983,6 +4018,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
3983 }4018 }
3984 man.hash.addOptionalEmitLoc(comp.emit_asm);4019 man.hash.addOptionalEmitLoc(comp.emit_asm);
3985 man.hash.addOptionalEmitLoc(comp.emit_llvm_ir);4020 man.hash.addOptionalEmitLoc(comp.emit_llvm_ir);
4021 man.hash.addOptionalEmitLoc(comp.emit_llvm_bc);
3986 man.hash.addOptionalEmitLoc(comp.emit_analysis);4022 man.hash.addOptionalEmitLoc(comp.emit_analysis);
3987 man.hash.addOptionalEmitLoc(comp.emit_docs);4023 man.hash.addOptionalEmitLoc(comp.emit_docs);
3988 man.hash.add(comp.test_evented_io);4024 man.hash.add(comp.test_evented_io);
...@@ -4088,13 +4124,14 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -4088,13 +4124,14 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
4088 ) orelse return error.OutOfMemory;4124 ) orelse return error.OutOfMemory;
40894125
4090 const emit_bin_path = if (comp.bin_file.options.emit != null) blk: {4126 const emit_bin_path = if (comp.bin_file.options.emit != null) blk: {
4091 const bin_basename = try std.zig.binNameAlloc(arena, .{4127 const obj_basename = try std.zig.binNameAlloc(arena, .{
4092 .root_name = comp.bin_file.options.root_name,4128 .root_name = comp.bin_file.options.root_name,
4093 .target = target,4129 .target = target,
4094 .output_mode = .Obj,4130 .output_mode = .Obj,
4095 });4131 });
4096 break :blk try directory.join(arena, &[_][]const u8{bin_basename});4132 break :blk try directory.join(arena, &[_][]const u8{obj_basename});
4097 } else "";4133 } else "";
4134
4098 if (mod.emit_h != null) {4135 if (mod.emit_h != null) {
4099 log.warn("-femit-h is not available in the stage1 backend; no .h file will be produced", .{});4136 log.warn("-femit-h is not available in the stage1 backend; no .h file will be produced", .{});
4100 }4137 }
...@@ -4102,6 +4139,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -4102,6 +4139,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
4102 const emit_h_path = try stage1LocPath(arena, emit_h_loc, directory);4139 const emit_h_path = try stage1LocPath(arena, emit_h_loc, directory);
4103 const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory);4140 const emit_asm_path = try stage1LocPath(arena, comp.emit_asm, directory);
4104 const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory);4141 const emit_llvm_ir_path = try stage1LocPath(arena, comp.emit_llvm_ir, directory);
4142 const emit_llvm_bc_path = try stage1LocPath(arena, comp.emit_llvm_bc, directory);
4105 const emit_analysis_path = try stage1LocPath(arena, comp.emit_analysis, directory);4143 const emit_analysis_path = try stage1LocPath(arena, comp.emit_analysis, directory);
4106 const emit_docs_path = try stage1LocPath(arena, comp.emit_docs, directory);4144 const emit_docs_path = try stage1LocPath(arena, comp.emit_docs, directory);
4107 const stage1_pkg = try createStage1Pkg(arena, "root", mod.root_pkg, null);4145 const stage1_pkg = try createStage1Pkg(arena, "root", mod.root_pkg, null);
...@@ -4122,6 +4160,8 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -4122,6 +4160,8 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
4122 .emit_asm_len = emit_asm_path.len,4160 .emit_asm_len = emit_asm_path.len,
4123 .emit_llvm_ir_ptr = emit_llvm_ir_path.ptr,4161 .emit_llvm_ir_ptr = emit_llvm_ir_path.ptr,
4124 .emit_llvm_ir_len = emit_llvm_ir_path.len,4162 .emit_llvm_ir_len = emit_llvm_ir_path.len,
4163 .emit_bitcode_ptr = emit_llvm_bc_path.ptr,
4164 .emit_bitcode_len = emit_llvm_bc_path.len,
4125 .emit_analysis_json_ptr = emit_analysis_path.ptr,4165 .emit_analysis_json_ptr = emit_analysis_path.ptr,
4126 .emit_analysis_json_len = emit_analysis_path.len,4166 .emit_analysis_json_len = emit_analysis_path.len,
4127 .emit_docs_ptr = emit_docs_path.ptr,4167 .emit_docs_ptr = emit_docs_path.ptr,
...@@ -4150,6 +4190,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node...@@ -4150,6 +4190,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
4150 .valgrind_enabled = comp.bin_file.options.valgrind,4190 .valgrind_enabled = comp.bin_file.options.valgrind,
4151 .tsan_enabled = comp.bin_file.options.tsan,4191 .tsan_enabled = comp.bin_file.options.tsan,
4152 .function_sections = comp.bin_file.options.function_sections,4192 .function_sections = comp.bin_file.options.function_sections,
4193 .include_compiler_rt = include_compiler_rt,
4153 .enable_stack_probing = comp.bin_file.options.stack_check,4194 .enable_stack_probing = comp.bin_file.options.stack_check,
4154 .red_zone = comp.bin_file.options.red_zone,4195 .red_zone = comp.bin_file.options.red_zone,
4155 .enable_time_report = comp.time_report,4196 .enable_time_report = comp.time_report,
src/codegen/llvm.zig+131-65
...@@ -72,9 +72,9 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {...@@ -72,9 +72,9 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {
72 .renderscript32 => "renderscript32",72 .renderscript32 => "renderscript32",
73 .renderscript64 => "renderscript64",73 .renderscript64 => "renderscript64",
74 .ve => "ve",74 .ve => "ve",
75 .spu_2 => return error.LLVMBackendDoesNotSupportSPUMarkII,75 .spu_2 => return error.@"LLVM backend does not support SPU Mark II",
76 .spirv32 => return error.LLVMBackendDoesNotSupportSPIRV,76 .spirv32 => return error.@"LLVM backend does not support SPIR-V",
77 .spirv64 => return error.LLVMBackendDoesNotSupportSPIRV,77 .spirv64 => return error.@"LLVM backend does not support SPIR-V",
78 };78 };
7979
80 const llvm_os = switch (target.os.tag) {80 const llvm_os = switch (target.os.tag) {
...@@ -114,11 +114,13 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {...@@ -114,11 +114,13 @@ pub fn targetTriple(allocator: *Allocator, target: std.Target) ![:0]u8 {
114 .wasi => "wasi",114 .wasi => "wasi",
115 .emscripten => "emscripten",115 .emscripten => "emscripten",
116 .uefi => "windows",116 .uefi => "windows",
117 .opencl => return error.LLVMBackendDoesNotSupportOpenCL,117
118 .glsl450 => return error.LLVMBackendDoesNotSupportGLSL450,118 .opencl,
119 .vulkan => return error.LLVMBackendDoesNotSupportVulkan,119 .glsl450,
120 .plan9 => return error.LLVMBackendDoesNotSupportPlan9,120 .vulkan,
121 .other => "unknown",121 .plan9,
122 .other,
123 => "unknown",
122 };124 };
123125
124 const llvm_abi = switch (target.abi) {126 const llvm_abi = switch (target.abi) {
...@@ -152,84 +154,105 @@ pub const Object = struct {...@@ -152,84 +154,105 @@ pub const Object = struct {
152 llvm_module: *const llvm.Module,154 llvm_module: *const llvm.Module,
153 context: *const llvm.Context,155 context: *const llvm.Context,
154 target_machine: *const llvm.TargetMachine,156 target_machine: *const llvm.TargetMachine,
155 object_pathZ: [:0]const u8,
156
157 pub fn create(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*Object {
158 _ = sub_path;
159 const self = try allocator.create(Object);
160 errdefer allocator.destroy(self);
161
162 const obj_basename = try std.zig.binNameAlloc(allocator, .{
163 .root_name = options.root_name,
164 .target = options.target,
165 .output_mode = .Obj,
166 });
167 defer allocator.free(obj_basename);
168157
169 const o_directory = options.module.?.zig_cache_artifact_directory;158 pub fn create(gpa: *Allocator, options: link.Options) !*Object {
170 const object_path = try o_directory.join(allocator, &[_][]const u8{obj_basename});159 const obj = try gpa.create(Object);
171 defer allocator.free(object_path);160 errdefer gpa.destroy(obj);
172161 obj.* = try Object.init(gpa, options);
173 const object_pathZ = try allocator.dupeZ(u8, object_path);162 return obj;
174 errdefer allocator.free(object_pathZ);163 }
175164
165 pub fn init(gpa: *Allocator, options: link.Options) !Object {
176 const context = llvm.Context.create();166 const context = llvm.Context.create();
177 errdefer context.dispose();167 errdefer context.dispose();
178168
179 initializeLLVMTargets();169 initializeLLVMTargets();
180170
181 const root_nameZ = try allocator.dupeZ(u8, options.root_name);171 const root_nameZ = try gpa.dupeZ(u8, options.root_name);
182 defer allocator.free(root_nameZ);172 defer gpa.free(root_nameZ);
183 const llvm_module = llvm.Module.createWithName(root_nameZ.ptr, context);173 const llvm_module = llvm.Module.createWithName(root_nameZ.ptr, context);
184 errdefer llvm_module.dispose();174 errdefer llvm_module.dispose();
185175
186 const llvm_target_triple = try targetTriple(allocator, options.target);176 const llvm_target_triple = try targetTriple(gpa, options.target);
187 defer allocator.free(llvm_target_triple);177 defer gpa.free(llvm_target_triple);
188178
189 var error_message: [*:0]const u8 = undefined;179 var error_message: [*:0]const u8 = undefined;
190 var target: *const llvm.Target = undefined;180 var target: *const llvm.Target = undefined;
191 if (llvm.Target.getFromTriple(llvm_target_triple.ptr, &target, &error_message).toBool()) {181 if (llvm.Target.getFromTriple(llvm_target_triple.ptr, &target, &error_message).toBool()) {
192 defer llvm.disposeMessage(error_message);182 defer llvm.disposeMessage(error_message);
193183
194 const stderr = std.io.getStdErr().writer();184 log.err("LLVM failed to parse '{s}': {s}", .{ llvm_target_triple, error_message });
195 try stderr.print(185 return error.InvalidLlvmTriple;
196 \\Zig is expecting LLVM to understand this target: '{s}'
197 \\However LLVM responded with: "{s}"
198 \\
199 ,
200 .{ llvm_target_triple, error_message },
201 );
202 return error.InvalidLLVMTriple;
203 }186 }
204187
205 const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug) .None else .Aggressive;188 const opt_level: llvm.CodeGenOptLevel = if (options.optimize_mode == .Debug)
189 .None
190 else
191 .Aggressive;
192
193 const reloc_mode: llvm.RelocMode = if (options.pic)
194 .PIC
195 else if (options.link_mode == .Dynamic)
196 llvm.RelocMode.DynamicNoPIC
197 else
198 .Static;
199
200 const code_model: llvm.CodeModel = switch (options.machine_code_model) {
201 .default => .Default,
202 .tiny => .Tiny,
203 .small => .Small,
204 .kernel => .Kernel,
205 .medium => .Medium,
206 .large => .Large,
207 };
208
209 // TODO handle float ABI better- it should depend on the ABI portion of std.Target
210 const float_abi: llvm.ABIType = .Default;
211
212 // TODO a way to override this as part of std.Target ABI?
213 const abi_name: ?[*:0]const u8 = switch (options.target.cpu.arch) {
214 .riscv32 => switch (options.target.os.tag) {
215 .linux => "ilp32d",
216 else => "ilp32",
217 },
218 .riscv64 => switch (options.target.os.tag) {
219 .linux => "lp64d",
220 else => "lp64",
221 },
222 else => null,
223 };
224
206 const target_machine = llvm.TargetMachine.create(225 const target_machine = llvm.TargetMachine.create(
207 target,226 target,
208 llvm_target_triple.ptr,227 llvm_target_triple.ptr,
209 "",228 if (options.target.cpu.model.llvm_name) |s| s.ptr else null,
210 "",229 options.llvm_cpu_features,
211 opt_level,230 opt_level,
212 .Static,231 reloc_mode,
213 .Default,232 code_model,
233 options.function_sections,
234 float_abi,
235 abi_name,
214 );236 );
215 errdefer target_machine.dispose();237 errdefer target_machine.dispose();
216238
217 self.* = .{239 return Object{
218 .llvm_module = llvm_module,240 .llvm_module = llvm_module,
219 .context = context,241 .context = context,
220 .target_machine = target_machine,242 .target_machine = target_machine,
221 .object_pathZ = object_pathZ,
222 };243 };
223 return self;
224 }244 }
225245
226 pub fn deinit(self: *Object, allocator: *Allocator) void {246 pub fn deinit(self: *Object) void {
227 self.target_machine.dispose();247 self.target_machine.dispose();
228 self.llvm_module.dispose();248 self.llvm_module.dispose();
229 self.context.dispose();249 self.context.dispose();
250 self.* = undefined;
251 }
230252
231 allocator.free(self.object_pathZ);253 pub fn destroy(self: *Object, gpa: *Allocator) void {
232 allocator.destroy(self);254 self.deinit();
255 gpa.destroy(self);
233 }256 }
234257
235 fn initializeLLVMTargets() void {258 fn initializeLLVMTargets() void {
...@@ -240,38 +263,81 @@ pub const Object = struct {...@@ -240,38 +263,81 @@ pub const Object = struct {
240 llvm.initializeAllAsmParsers();263 llvm.initializeAllAsmParsers();
241 }264 }
242265
266 fn locPath(
267 arena: *Allocator,
268 opt_loc: ?Compilation.EmitLoc,
269 cache_directory: Compilation.Directory,
270 ) !?[*:0]u8 {
271 const loc = opt_loc orelse return null;
272 const directory = loc.directory orelse cache_directory;
273 const slice = try directory.joinZ(arena, &[_][]const u8{loc.basename});
274 return slice.ptr;
275 }
276
243 pub fn flushModule(self: *Object, comp: *Compilation) !void {277 pub fn flushModule(self: *Object, comp: *Compilation) !void {
244 if (comp.verbose_llvm_ir) {278 if (comp.verbose_llvm_ir) {
245 const dump = self.llvm_module.printToString();279 self.llvm_module.dump();
246 defer llvm.disposeMessage(dump);
247
248 const stderr = std.io.getStdErr().writer();
249 try stderr.writeAll(std.mem.spanZ(dump));
250 }280 }
251281
252 {282 if (std.debug.runtime_safety) {
253 var error_message: [*:0]const u8 = undefined;283 var error_message: [*:0]const u8 = undefined;
254 // verifyModule always allocs the error_message even if there is no error284 // verifyModule always allocs the error_message even if there is no error
255 defer llvm.disposeMessage(error_message);285 defer llvm.disposeMessage(error_message);
256286
257 if (self.llvm_module.verify(.ReturnStatus, &error_message).toBool()) {287 if (self.llvm_module.verify(.ReturnStatus, &error_message).toBool()) {
258 const stderr = std.io.getStdErr().writer();288 std.debug.print("\n{s}\n", .{error_message});
259 try stderr.print("broken LLVM module found: {s}\nThis is a bug in the Zig compiler.", .{error_message});289 @panic("LLVM module verification failed");
260 return error.BrokenLLVMModule;
261 }290 }
262 }291 }
263292
293 var arena_allocator = std.heap.ArenaAllocator.init(comp.gpa);
294 defer arena_allocator.deinit();
295 const arena = &arena_allocator.allocator;
296
297 const mod = comp.bin_file.options.module.?;
298 const cache_dir = mod.zig_cache_artifact_directory;
299
300 const emit_bin_path: ?[*:0]const u8 = if (comp.bin_file.options.emit != null) blk: {
301 const obj_basename = try std.zig.binNameAlloc(arena, .{
302 .root_name = comp.bin_file.options.root_name,
303 .target = comp.bin_file.options.target,
304 .output_mode = .Obj,
305 });
306 if (cache_dir.joinZ(arena, &[_][]const u8{obj_basename})) |p| {
307 break :blk p.ptr;
308 } else |err| {
309 return err;
310 }
311 } else null;
312
313 const emit_asm_path = try locPath(arena, comp.emit_asm, cache_dir);
314 const emit_llvm_ir_path = try locPath(arena, comp.emit_llvm_ir, cache_dir);
315 const emit_llvm_bc_path = try locPath(arena, comp.emit_llvm_bc, cache_dir);
316
264 var error_message: [*:0]const u8 = undefined;317 var error_message: [*:0]const u8 = undefined;
265 if (self.target_machine.emitToFile(318 if (self.target_machine.emitToFile(
266 self.llvm_module,319 self.llvm_module,
267 self.object_pathZ.ptr,
268 .ObjectFile,
269 &error_message,320 &error_message,
270 ).toBool()) {321 comp.bin_file.options.optimize_mode == .Debug,
322 comp.bin_file.options.optimize_mode == .ReleaseSmall,
323 comp.time_report,
324 comp.bin_file.options.tsan,
325 comp.bin_file.options.lto,
326 emit_asm_path,
327 emit_bin_path,
328 emit_llvm_ir_path,
329 emit_llvm_bc_path,
330 )) {
271 defer llvm.disposeMessage(error_message);331 defer llvm.disposeMessage(error_message);
272332
273 const stderr = std.io.getStdErr().writer();333 const emit_asm_msg = emit_asm_path orelse "(none)";
274 try stderr.print("LLVM failed to emit file: {s}\n", .{error_message});334 const emit_bin_msg = emit_bin_path orelse "(none)";
335 const emit_llvm_ir_msg = emit_llvm_ir_path orelse "(none)";
336 const emit_llvm_bc_msg = emit_llvm_bc_path orelse "(none)";
337 log.err("LLVM failed to emit asm={s} bin={s} ir={s} bc={s}: {s}", .{
338 emit_asm_msg, emit_bin_msg, emit_llvm_ir_msg, emit_llvm_bc_msg,
339 error_message,
340 });
275 return error.FailedToEmit;341 return error.FailedToEmit;
276 }342 }
277 }343 }
src/codegen/llvm/bindings.zig+35-13
...@@ -123,6 +123,9 @@ pub const Module = opaque {...@@ -123,6 +123,9 @@ pub const Module = opaque {
123123
124 pub const getNamedGlobal = LLVMGetNamedGlobal;124 pub const getNamedGlobal = LLVMGetNamedGlobal;
125 extern fn LLVMGetNamedGlobal(M: *const Module, Name: [*:0]const u8) ?*const Value;125 extern fn LLVMGetNamedGlobal(M: *const Module, Name: [*:0]const u8) ?*const Value;
126
127 pub const dump = LLVMDumpModule;
128 extern fn LLVMDumpModule(M: *const Module) void;
126};129};
127130
128pub const lookupIntrinsicID = LLVMLookupIntrinsicID;131pub const lookupIntrinsicID = LLVMLookupIntrinsicID;
...@@ -250,31 +253,41 @@ pub const BasicBlock = opaque {...@@ -250,31 +253,41 @@ pub const BasicBlock = opaque {
250};253};
251254
252pub const TargetMachine = opaque {255pub const TargetMachine = opaque {
253 pub const create = LLVMCreateTargetMachine;256 pub const create = ZigLLVMCreateTargetMachine;
254 extern fn LLVMCreateTargetMachine(257 extern fn ZigLLVMCreateTargetMachine(
255 T: *const Target,258 T: *const Target,
256 Triple: [*:0]const u8,259 Triple: [*:0]const u8,
257 CPU: [*:0]const u8,260 CPU: ?[*:0]const u8,
258 Features: [*:0]const u8,261 Features: ?[*:0]const u8,
259 Level: CodeGenOptLevel,262 Level: CodeGenOptLevel,
260 Reloc: RelocMode,263 Reloc: RelocMode,
261 CodeModel: CodeMode,264 CodeModel: CodeModel,
265 function_sections: bool,
266 float_abi: ABIType,
267 abi_name: ?[*:0]const u8,
262 ) *const TargetMachine;268 ) *const TargetMachine;
263269
264 pub const dispose = LLVMDisposeTargetMachine;270 pub const dispose = LLVMDisposeTargetMachine;
265 extern fn LLVMDisposeTargetMachine(T: *const TargetMachine) void;271 extern fn LLVMDisposeTargetMachine(T: *const TargetMachine) void;
266272
267 pub const emitToFile = LLVMTargetMachineEmitToFile;273 pub const emitToFile = ZigLLVMTargetMachineEmitToFile;
268 extern fn LLVMTargetMachineEmitToFile(274 extern fn ZigLLVMTargetMachineEmitToFile(
269 *const TargetMachine,275 T: *const TargetMachine,
270 M: *const Module,276 M: *const Module,
271 Filename: [*:0]const u8,
272 codegen: CodeGenFileType,
273 ErrorMessage: *[*:0]const u8,277 ErrorMessage: *[*:0]const u8,
274 ) Bool;278 is_debug: bool,
279 is_small: bool,
280 time_report: bool,
281 tsan: bool,
282 lto: bool,
283 asm_filename: ?[*:0]const u8,
284 bin_filename: ?[*:0]const u8,
285 llvm_ir_filename: ?[*:0]const u8,
286 bitcode_filename: ?[*:0]const u8,
287 ) bool;
275};288};
276289
277pub const CodeMode = enum(c_int) {290pub const CodeModel = enum(c_int) {
278 Default,291 Default,
279 JITDefault,292 JITDefault,
280 Tiny,293 Tiny,
...@@ -295,7 +308,7 @@ pub const RelocMode = enum(c_int) {...@@ -295,7 +308,7 @@ pub const RelocMode = enum(c_int) {
295 Default,308 Default,
296 Static,309 Static,
297 PIC,310 PIC,
298 DynamicNoPic,311 DynamicNoPIC,
299 ROPI,312 ROPI,
300 RWPI,313 RWPI,
301 ROPI_RWPI,314 ROPI_RWPI,
...@@ -306,6 +319,15 @@ pub const CodeGenFileType = enum(c_int) {...@@ -306,6 +319,15 @@ pub const CodeGenFileType = enum(c_int) {
306 ObjectFile,319 ObjectFile,
307};320};
308321
322pub const ABIType = enum(c_int) {
323 /// Target-specific (either soft or hard depending on triple, etc).
324 Default,
325 /// Soft float.
326 Soft,
327 // Hard float.
328 Hard,
329};
330
309pub const Target = opaque {331pub const Target = opaque {
310 pub const getFromTriple = LLVMGetTargetFromTriple;332 pub const getFromTriple = LLVMGetTargetFromTriple;
311 extern fn LLVMGetTargetFromTriple(Triple: [*:0]const u8, T: **const Target, ErrorMessage: *[*:0]const u8) Bool;333 extern fn LLVMGetTargetFromTriple(Triple: [*:0]const u8, T: **const Target, ErrorMessage: *[*:0]const u8) Bool;
src/link.zig+10-6
...@@ -191,7 +191,7 @@ pub const File = struct {...@@ -191,7 +191,7 @@ pub const File = struct {
191 const use_stage1 = build_options.is_stage1 and options.use_stage1;191 const use_stage1 = build_options.is_stage1 and options.use_stage1;
192 if (use_stage1 or options.emit == null) {192 if (use_stage1 or options.emit == null) {
193 return switch (options.object_format) {193 return switch (options.object_format) {
194 .coff, .pe => &(try Coff.createEmpty(allocator, options)).base,194 .coff => &(try Coff.createEmpty(allocator, options)).base,
195 .elf => &(try Elf.createEmpty(allocator, options)).base,195 .elf => &(try Elf.createEmpty(allocator, options)).base,
196 .macho => &(try MachO.createEmpty(allocator, options)).base,196 .macho => &(try MachO.createEmpty(allocator, options)).base,
197 .wasm => &(try Wasm.createEmpty(allocator, options)).base,197 .wasm => &(try Wasm.createEmpty(allocator, options)).base,
...@@ -206,9 +206,10 @@ pub const File = struct {...@@ -206,9 +206,10 @@ pub const File = struct {
206 const use_lld = build_options.have_llvm and options.use_lld; // comptime known false when !have_llvm206 const use_lld = build_options.have_llvm and options.use_lld; // comptime known false when !have_llvm
207 const sub_path = if (use_lld) blk: {207 const sub_path = if (use_lld) blk: {
208 if (options.module == null) {208 if (options.module == null) {
209 // No point in opening a file, we would not write anything to it. Initialize with empty.209 // No point in opening a file, we would not write anything to it.
210 // Initialize with empty.
210 return switch (options.object_format) {211 return switch (options.object_format) {
211 .coff, .pe => &(try Coff.createEmpty(allocator, options)).base,212 .coff => &(try Coff.createEmpty(allocator, options)).base,
212 .elf => &(try Elf.createEmpty(allocator, options)).base,213 .elf => &(try Elf.createEmpty(allocator, options)).base,
213 .macho => &(try MachO.createEmpty(allocator, options)).base,214 .macho => &(try MachO.createEmpty(allocator, options)).base,
214 .plan9 => &(try Plan9.createEmpty(allocator, options)).base,215 .plan9 => &(try Plan9.createEmpty(allocator, options)).base,
...@@ -219,13 +220,16 @@ pub const File = struct {...@@ -219,13 +220,16 @@ pub const File = struct {
219 .raw => return error.RawObjectFormatUnimplemented,220 .raw => return error.RawObjectFormatUnimplemented,
220 };221 };
221 }222 }
222 // Open a temporary object file, not the final output file because we want to link with LLD.223 // Open a temporary object file, not the final output file because we
223 break :blk try std.fmt.allocPrint(allocator, "{s}{s}", .{ emit.sub_path, options.target.oFileExt() });224 // want to link with LLD.
225 break :blk try std.fmt.allocPrint(allocator, "{s}{s}", .{
226 emit.sub_path, options.object_format.fileExt(options.target.cpu.arch),
227 });
224 } else emit.sub_path;228 } else emit.sub_path;
225 errdefer if (use_lld) allocator.free(sub_path);229 errdefer if (use_lld) allocator.free(sub_path);
226230
227 const file: *File = switch (options.object_format) {231 const file: *File = switch (options.object_format) {
228 .coff, .pe => &(try Coff.openPath(allocator, sub_path, options)).base,232 .coff => &(try Coff.openPath(allocator, sub_path, options)).base,
229 .elf => &(try Elf.openPath(allocator, sub_path, options)).base,233 .elf => &(try Elf.openPath(allocator, sub_path, options)).base,
230 .macho => &(try MachO.openPath(allocator, sub_path, options)).base,234 .macho => &(try MachO.openPath(allocator, sub_path, options)).base,
231 .plan9 => &(try Plan9.openPath(allocator, sub_path, options)).base,235 .plan9 => &(try Plan9.openPath(allocator, sub_path, options)).base,
src/link/Coff.zig+13-12
...@@ -17,9 +17,9 @@ const link = @import("../link.zig");...@@ -17,9 +17,9 @@ const link = @import("../link.zig");
17const build_options = @import("build_options");17const build_options = @import("build_options");
18const Cache = @import("../Cache.zig");18const Cache = @import("../Cache.zig");
19const mingw = @import("../mingw.zig");19const mingw = @import("../mingw.zig");
20const llvm_backend = @import("../codegen/llvm.zig");
21const Air = @import("../Air.zig");20const Air = @import("../Air.zig");
22const Liveness = @import("../Liveness.zig");21const Liveness = @import("../Liveness.zig");
22const LlvmObject = @import("../codegen/llvm.zig").Object;
2323
24const allocation_padding = 4 / 3;24const allocation_padding = 4 / 3;
25const minimum_text_block_size = 64 * allocation_padding;25const minimum_text_block_size = 64 * allocation_padding;
...@@ -37,7 +37,7 @@ pub const base_tag: link.File.Tag = .coff;...@@ -37,7 +37,7 @@ pub const base_tag: link.File.Tag = .coff;
37const msdos_stub = @embedFile("msdos-stub.bin");37const msdos_stub = @embedFile("msdos-stub.bin");
3838
39/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.39/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
40llvm_object: ?*llvm_backend.Object = null,40llvm_object: ?*LlvmObject = null,
4141
42base: link.File,42base: link.File,
43ptr_width: PtrWidth,43ptr_width: PtrWidth,
...@@ -132,7 +132,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -132,7 +132,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
132 const self = try createEmpty(allocator, options);132 const self = try createEmpty(allocator, options);
133 errdefer self.base.destroy();133 errdefer self.base.destroy();
134134
135 self.llvm_object = try llvm_backend.Object.create(allocator, sub_path, options);135 self.llvm_object = try LlvmObject.create(allocator, options);
136 return self;136 return self;
137 }137 }
138138
...@@ -657,10 +657,7 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {...@@ -657,10 +657,7 @@ fn writeOffsetTableEntry(self: *Coff, index: usize) !void {
657}657}
658658
659pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {659pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, liveness: Liveness) !void {
660 if (build_options.skip_non_native and660 if (build_options.skip_non_native and builtin.object_format != .coff) {
661 builtin.object_format != .coff and
662 builtin.object_format != .pe)
663 {
664 @panic("Attempted to compile for object format that was disabled by build configuration");661 @panic("Attempted to compile for object format that was disabled by build configuration");
665 }662 }
666 if (build_options.have_llvm) {663 if (build_options.have_llvm) {
...@@ -697,7 +694,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live...@@ -697,7 +694,7 @@ pub fn updateFunc(self: *Coff, module: *Module, func: *Module.Fn, air: Air, live
697}694}
698695
699pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {696pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
700 if (build_options.skip_non_native and builtin.object_format != .coff and builtin.object_format != .pe) {697 if (build_options.skip_non_native and builtin.object_format != .coff) {
701 @panic("Attempted to compile for object format that was disabled by build configuration");698 @panic("Attempted to compile for object format that was disabled by build configuration");
702 }699 }
703 if (build_options.have_llvm) {700 if (build_options.have_llvm) {
...@@ -823,8 +820,11 @@ pub fn flushModule(self: *Coff, comp: *Compilation) !void {...@@ -823,8 +820,11 @@ pub fn flushModule(self: *Coff, comp: *Compilation) !void {
823 const tracy = trace(@src());820 const tracy = trace(@src());
824 defer tracy.end();821 defer tracy.end();
825822
826 if (build_options.have_llvm)823 if (build_options.have_llvm) {
827 if (self.llvm_object) |llvm_object| return try llvm_object.flushModule(comp);824 if (self.llvm_object) |llvm_object| {
825 return try llvm_object.flushModule(comp);
826 }
827 }
828828
829 if (self.text_section_size_dirty) {829 if (self.text_section_size_dirty) {
830 // Write the new raw size in the .text header830 // Write the new raw size in the .text header
...@@ -1398,8 +1398,9 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v...@@ -1398,8 +1398,9 @@ pub fn updateDeclLineNumber(self: *Coff, module: *Module, decl: *Module.Decl) !v
1398}1398}
13991399
1400pub fn deinit(self: *Coff) void {1400pub fn deinit(self: *Coff) void {
1401 if (build_options.have_llvm)1401 if (build_options.have_llvm) {
1402 if (self.llvm_object) |ir_module| ir_module.deinit(self.base.allocator);1402 if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);
1403 }
14031404
1404 self.text_block_free_list.deinit(self.base.allocator);1405 self.text_block_free_list.deinit(self.base.allocator);
1405 self.offset_table.deinit(self.base.allocator);1406 self.offset_table.deinit(self.base.allocator);
src/link/Elf.zig+12-8
...@@ -25,9 +25,9 @@ const target_util = @import("../target.zig");...@@ -25,9 +25,9 @@ const target_util = @import("../target.zig");
25const glibc = @import("../glibc.zig");25const glibc = @import("../glibc.zig");
26const musl = @import("../musl.zig");26const musl = @import("../musl.zig");
27const Cache = @import("../Cache.zig");27const Cache = @import("../Cache.zig");
28const llvm_backend = @import("../codegen/llvm.zig");
29const Air = @import("../Air.zig");28const Air = @import("../Air.zig");
30const Liveness = @import("../Liveness.zig");29const Liveness = @import("../Liveness.zig");
30const LlvmObject = @import("../codegen/llvm.zig").Object;
3131
32const default_entry_addr = 0x8000000;32const default_entry_addr = 0x8000000;
3333
...@@ -38,7 +38,7 @@ base: File,...@@ -38,7 +38,7 @@ base: File,
38ptr_width: PtrWidth,38ptr_width: PtrWidth,
3939
40/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.40/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
41llvm_object: ?*llvm_backend.Object = null,41llvm_object: ?*LlvmObject = null,
4242
43/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.43/// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
44/// Same order as in the file.44/// Same order as in the file.
...@@ -235,7 +235,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -235,7 +235,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
235 const self = try createEmpty(allocator, options);235 const self = try createEmpty(allocator, options);
236 errdefer self.base.destroy();236 errdefer self.base.destroy();
237237
238 self.llvm_object = try llvm_backend.Object.create(allocator, sub_path, options);238 self.llvm_object = try LlvmObject.create(allocator, options);
239 return self;239 return self;
240 }240 }
241241
...@@ -301,9 +301,9 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Elf {...@@ -301,9 +301,9 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Elf {
301}301}
302302
303pub fn deinit(self: *Elf) void {303pub fn deinit(self: *Elf) void {
304 if (build_options.have_llvm)304 if (build_options.have_llvm) {
305 if (self.llvm_object) |ir_module|305 if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);
306 ir_module.deinit(self.base.allocator);306 }
307307
308 self.sections.deinit(self.base.allocator);308 self.sections.deinit(self.base.allocator);
309 self.program_headers.deinit(self.base.allocator);309 self.program_headers.deinit(self.base.allocator);
...@@ -750,8 +750,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {...@@ -750,8 +750,8 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
750 if (build_options.have_llvm)750 if (build_options.have_llvm)
751 if (self.llvm_object) |llvm_object| return try llvm_object.flushModule(comp);751 if (self.llvm_object) |llvm_object| return try llvm_object.flushModule(comp);
752752
753 // TODO This linker code currently assumes there is only 1 compilation unit and it corresponds to the753 // TODO This linker code currently assumes there is only 1 compilation unit and it
754 // Zig source code.754 // corresponds to the Zig source code.
755 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;755 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
756756
757 const target_endian = self.base.options.target.cpu.arch.endian();757 const target_endian = self.base.options.target.cpu.arch.endian();
...@@ -1289,6 +1289,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1289,6 +1289,10 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1289 // TODO: remove when stage2 can build compiler_rt.zig1289 // TODO: remove when stage2 can build compiler_rt.zig
1290 if (!build_options.is_stage1) break :blk null;1290 if (!build_options.is_stage1) break :blk null;
12911291
1292 // In the case of build-obj we include the compiler-rt symbols directly alongside
1293 // the symbols of the root source file, in the same compilation unit.
1294 if (is_obj) break :blk null;
1295
1292 if (is_exe_or_dyn_lib) {1296 if (is_exe_or_dyn_lib) {
1293 break :blk comp.compiler_rt_static_lib.?.full_object_path;1297 break :blk comp.compiler_rt_static_lib.?.full_object_path;
1294 } else {1298 } else {
src/link/MachO.zig+9-4
...@@ -29,21 +29,22 @@ const CodeSignature = @import("MachO/CodeSignature.zig");...@@ -29,21 +29,22 @@ const CodeSignature = @import("MachO/CodeSignature.zig");
29const Compilation = @import("../Compilation.zig");29const Compilation = @import("../Compilation.zig");
30const DebugSymbols = @import("MachO/DebugSymbols.zig");30const DebugSymbols = @import("MachO/DebugSymbols.zig");
31const Dylib = @import("MachO/Dylib.zig");31const Dylib = @import("MachO/Dylib.zig");
32const File = link.File;
32const Object = @import("MachO/Object.zig");33const Object = @import("MachO/Object.zig");
33const Liveness = @import("../Liveness.zig");34const Liveness = @import("../Liveness.zig");
35const LlvmObject = @import("../codegen/llvm.zig").Object;
34const LoadCommand = commands.LoadCommand;36const LoadCommand = commands.LoadCommand;
35const Module = @import("../Module.zig");37const Module = @import("../Module.zig");
36const File = link.File;38const SegmentCommand = commands.SegmentCommand;
37pub const TextBlock = @import("MachO/TextBlock.zig");39pub const TextBlock = @import("MachO/TextBlock.zig");
38const Trie = @import("MachO/Trie.zig");40const Trie = @import("MachO/Trie.zig");
39const SegmentCommand = commands.SegmentCommand;
4041
41pub const base_tag: File.Tag = File.Tag.macho;42pub const base_tag: File.Tag = File.Tag.macho;
4243
43base: File,44base: File,
4445
45/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.46/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
46llvm_object: ?*llvm_backend.Object = null,47llvm_object: ?*LlvmObject = null,
4748
48/// Debug symbols bundle (or dSym).49/// Debug symbols bundle (or dSym).
49d_sym: ?DebugSymbols = null,50d_sym: ?DebugSymbols = null,
...@@ -333,7 +334,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -333,7 +334,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
333 const self = try createEmpty(allocator, options);334 const self = try createEmpty(allocator, options);
334 errdefer self.base.destroy();335 errdefer self.base.destroy();
335336
336 self.llvm_object = try llvm_backend.Object.create(allocator, sub_path, options);337 self.llvm_object = try LlvmObject.create(allocator, options);
337 return self;338 return self;
338 }339 }
339340
...@@ -3305,6 +3306,10 @@ fn writeSymbolTable(self: *MachO) !void {...@@ -3305,6 +3306,10 @@ fn writeSymbolTable(self: *MachO) !void {
3305}3306}
33063307
3307pub fn deinit(self: *MachO) void {3308pub fn deinit(self: *MachO) void {
3309 if (build_options.have_llvm) {
3310 if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);
3311 }
3312
3308 if (self.d_sym) |*ds| {3313 if (self.d_sym) |*ds| {
3309 ds.deinit(self.base.allocator);3314 ds.deinit(self.base.allocator);
3310 }3315 }
src/link/Wasm.zig+9-4
...@@ -19,7 +19,7 @@ const build_options = @import("build_options");...@@ -19,7 +19,7 @@ const build_options = @import("build_options");
19const wasi_libc = @import("../wasi_libc.zig");19const wasi_libc = @import("../wasi_libc.zig");
20const Cache = @import("../Cache.zig");20const Cache = @import("../Cache.zig");
21const TypedValue = @import("../TypedValue.zig");21const TypedValue = @import("../TypedValue.zig");
22const llvm_backend = @import("../codegen/llvm.zig");22const LlvmObject = @import("../codegen/llvm.zig").Object;
23const Air = @import("../Air.zig");23const Air = @import("../Air.zig");
24const Liveness = @import("../Liveness.zig");24const Liveness = @import("../Liveness.zig");
2525
...@@ -27,7 +27,7 @@ pub const base_tag = link.File.Tag.wasm;...@@ -27,7 +27,7 @@ pub const base_tag = link.File.Tag.wasm;
2727
28base: link.File,28base: link.File,
29/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.29/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
30llvm_object: ?*llvm_backend.Object = null,30llvm_object: ?*LlvmObject = null,
31/// List of all function Decls to be written to the output file. The index of31/// List of all function Decls to be written to the output file. The index of
32/// each Decl in this list at the time of writing the binary is used as the32/// each Decl in this list at the time of writing the binary is used as the
33/// function index. In the event where ext_funcs' size is not 0, the index of33/// function index. In the event where ext_funcs' size is not 0, the index of
...@@ -121,7 +121,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio...@@ -121,7 +121,7 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio
121 const self = try createEmpty(allocator, options);121 const self = try createEmpty(allocator, options);
122 errdefer self.base.destroy();122 errdefer self.base.destroy();
123123
124 self.llvm_object = try llvm_backend.Object.create(allocator, sub_path, options);124 self.llvm_object = try LlvmObject.create(allocator, options);
125 return self;125 return self;
126 }126 }
127127
...@@ -153,6 +153,9 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Wasm {...@@ -153,6 +153,9 @@ pub fn createEmpty(gpa: *Allocator, options: link.Options) !*Wasm {
153}153}
154154
155pub fn deinit(self: *Wasm) void {155pub fn deinit(self: *Wasm) void {
156 if (build_options.have_llvm) {
157 if (self.llvm_object) |llvm_object| llvm_object.destroy(self.base.allocator);
158 }
156 for (self.symbols.items) |decl| {159 for (self.symbols.items) |decl| {
157 decl.fn_link.wasm.functype.deinit(self.base.allocator);160 decl.fn_link.wasm.functype.deinit(self.base.allocator);
158 decl.fn_link.wasm.code.deinit(self.base.allocator);161 decl.fn_link.wasm.code.deinit(self.base.allocator);
...@@ -642,7 +645,9 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {...@@ -642,7 +645,9 @@ fn linkWithLLD(self: *Wasm, comp: *Compilation) !void {
642 break :blk full_obj_path;645 break :blk full_obj_path;
643 } else null;646 } else null;
644647
645 const compiler_rt_path: ?[]const u8 = if (self.base.options.include_compiler_rt)648 const is_obj = self.base.options.output_mode == .Obj;
649
650 const compiler_rt_path: ?[]const u8 = if (self.base.options.include_compiler_rt and !is_obj)
646 comp.compiler_rt_static_lib.?.full_object_path651 comp.compiler_rt_static_lib.?.full_object_path
647 else652 else
648 null;653 null;
src/main.zig+40-22
...@@ -287,9 +287,9 @@ const usage_build_generic =...@@ -287,9 +287,9 @@ const usage_build_generic =
287 \\ .s Target-specific assembly source code287 \\ .s Target-specific assembly source code
288 \\ .S Assembly with C preprocessor (requires LLVM extensions)288 \\ .S Assembly with C preprocessor (requires LLVM extensions)
289 \\ .c C source code (requires LLVM extensions)289 \\ .c C source code (requires LLVM extensions)
290 \\ .cpp C++ source code (requires LLVM extensions)290 \\ .cxx .cc .C .cpp C++ source code (requires LLVM extensions)
291 \\ Other C++ extensions: .C .cc .cxx
292 \\ .m Objective-C source code (requires LLVM extensions)291 \\ .m Objective-C source code (requires LLVM extensions)
292 \\ .bc LLVM IR Module (requires LLVM extensions)
293 \\293 \\
294 \\General Options:294 \\General Options:
295 \\ -h, --help Print this help and exit295 \\ -h, --help Print this help and exit
...@@ -301,6 +301,8 @@ const usage_build_generic =...@@ -301,6 +301,8 @@ const usage_build_generic =
301 \\ -fno-emit-asm (default) Do not output .s (assembly code)301 \\ -fno-emit-asm (default) Do not output .s (assembly code)
302 \\ -femit-llvm-ir[=path] Produce a .ll file with LLVM IR (requires LLVM extensions)302 \\ -femit-llvm-ir[=path] Produce a .ll file with LLVM IR (requires LLVM extensions)
303 \\ -fno-emit-llvm-ir (default) Do not produce a .ll file with LLVM IR303 \\ -fno-emit-llvm-ir (default) Do not produce a .ll file with LLVM IR
304 \\ -femit-llvm-bc[=path] Produce a LLVM module as a .bc file (requires LLVM extensions)
305 \\ -fno-emit-llvm-bc (default) Do not produce a LLVM module as a .bc file
304 \\ -femit-h[=path] Generate a C header file (.h)306 \\ -femit-h[=path] Generate a C header file (.h)
305 \\ -fno-emit-h (default) Do not generate a C header file (.h)307 \\ -fno-emit-h (default) Do not generate a C header file (.h)
306 \\ -femit-docs[=path] Create a docs/ dir with html documentation308 \\ -femit-docs[=path] Create a docs/ dir with html documentation
...@@ -359,15 +361,14 @@ const usage_build_generic =...@@ -359,15 +361,14 @@ const usage_build_generic =
359 \\ --single-threaded Code assumes it is only used single-threaded361 \\ --single-threaded Code assumes it is only used single-threaded
360 \\ -ofmt=[mode] Override target object format362 \\ -ofmt=[mode] Override target object format
361 \\ elf Executable and Linking Format363 \\ elf Executable and Linking Format
362 \\ c Compile to C source code364 \\ c C source code
363 \\ wasm WebAssembly365 \\ wasm WebAssembly
364 \\ pe Portable Executable (Windows)
365 \\ coff Common Object File Format (Windows)366 \\ coff Common Object File Format (Windows)
366 \\ macho macOS relocatables367 \\ macho macOS relocatables
367 \\ spirv Standard, Portable Intermediate Representation V (SPIR-V)368 \\ spirv Standard, Portable Intermediate Representation V (SPIR-V)
368 \\ plan9 Plan 9 from Bell Labs object format369 \\ plan9 Plan 9 from Bell Labs object format
369 \\ hex (planned) Intel IHEX370 \\ hex (planned feature) Intel IHEX
370 \\ raw (planned) Dump machine code directly371 \\ raw (planned feature) Dump machine code directly
371 \\ -dirafter [dir] Add directory to AFTER include search path372 \\ -dirafter [dir] Add directory to AFTER include search path
372 \\ -isystem [dir] Add directory to SYSTEM include search path373 \\ -isystem [dir] Add directory to SYSTEM include search path
373 \\ -I[dir] Add directory to include search path374 \\ -I[dir] Add directory to include search path
...@@ -384,8 +385,8 @@ const usage_build_generic =...@@ -384,8 +385,8 @@ const usage_build_generic =
384 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)385 \\ --dynamic-linker [path] Set the dynamic interpreter path (usually ld.so)
385 \\ --sysroot [path] Set the system root directory (usually /)386 \\ --sysroot [path] Set the system root directory (usually /)
386 \\ --version [ver] Dynamic library semver387 \\ --version [ver] Dynamic library semver
387 \\ -fsoname[=name] (Linux) Override the default SONAME value388 \\ -fsoname[=name] Override the default SONAME value
388 \\ -fno-soname (Linux) Disable emitting a SONAME389 \\ -fno-soname Disable emitting a SONAME
389 \\ -fLLD Force using LLD as the linker390 \\ -fLLD Force using LLD as the linker
390 \\ -fno-LLD Prevent using LLD as the linker391 \\ -fno-LLD Prevent using LLD as the linker
391 \\ -fcompiler-rt Always include compiler-rt symbols in output392 \\ -fcompiler-rt Always include compiler-rt symbols in output
...@@ -552,6 +553,7 @@ fn buildOutputType(...@@ -552,6 +553,7 @@ fn buildOutputType(
552 var emit_bin: EmitBin = .yes_default_path;553 var emit_bin: EmitBin = .yes_default_path;
553 var emit_asm: Emit = .no;554 var emit_asm: Emit = .no;
554 var emit_llvm_ir: Emit = .no;555 var emit_llvm_ir: Emit = .no;
556 var emit_llvm_bc: Emit = .no;
555 var emit_docs: Emit = .no;557 var emit_docs: Emit = .no;
556 var emit_analysis: Emit = .no;558 var emit_analysis: Emit = .no;
557 var target_arch_os_abi: []const u8 = "native";559 var target_arch_os_abi: []const u8 = "native";
...@@ -1011,6 +1013,12 @@ fn buildOutputType(...@@ -1011,6 +1013,12 @@ fn buildOutputType(
1011 emit_llvm_ir = .{ .yes = arg["-femit-llvm-ir=".len..] };1013 emit_llvm_ir = .{ .yes = arg["-femit-llvm-ir=".len..] };
1012 } else if (mem.eql(u8, arg, "-fno-emit-llvm-ir")) {1014 } else if (mem.eql(u8, arg, "-fno-emit-llvm-ir")) {
1013 emit_llvm_ir = .no;1015 emit_llvm_ir = .no;
1016 } else if (mem.eql(u8, arg, "-femit-llvm-bc")) {
1017 emit_llvm_bc = .yes_default_path;
1018 } else if (mem.startsWith(u8, arg, "-femit-llvm-bc=")) {
1019 emit_llvm_bc = .{ .yes = arg["-femit-llvm-bc=".len..] };
1020 } else if (mem.eql(u8, arg, "-fno-emit-llvm-bc")) {
1021 emit_llvm_bc = .no;
1014 } else if (mem.eql(u8, arg, "-femit-docs")) {1022 } else if (mem.eql(u8, arg, "-femit-docs")) {
1015 emit_docs = .yes_default_path;1023 emit_docs = .yes_default_path;
1016 } else if (mem.startsWith(u8, arg, "-femit-docs=")) {1024 } else if (mem.startsWith(u8, arg, "-femit-docs=")) {
...@@ -1720,8 +1728,6 @@ fn buildOutputType(...@@ -1720,8 +1728,6 @@ fn buildOutputType(
1720 break :blk .c;1728 break :blk .c;
1721 } else if (mem.eql(u8, ofmt, "coff")) {1729 } else if (mem.eql(u8, ofmt, "coff")) {
1722 break :blk .coff;1730 break :blk .coff;
1723 } else if (mem.eql(u8, ofmt, "pe")) {
1724 break :blk .pe;
1725 } else if (mem.eql(u8, ofmt, "macho")) {1731 } else if (mem.eql(u8, ofmt, "macho")) {
1726 break :blk .macho;1732 break :blk .macho;
1727 } else if (mem.eql(u8, ofmt, "wasm")) {1733 } else if (mem.eql(u8, ofmt, "wasm")) {
...@@ -1765,7 +1771,7 @@ fn buildOutputType(...@@ -1765,7 +1771,7 @@ fn buildOutputType(
1765 };1771 };
17661772
1767 const a_out_basename = switch (object_format) {1773 const a_out_basename = switch (object_format) {
1768 .pe, .coff => "a.exe",1774 .coff => "a.exe",
1769 else => "a.out",1775 else => "a.out",
1770 };1776 };
17711777
...@@ -1830,10 +1836,10 @@ fn buildOutputType(...@@ -1830,10 +1836,10 @@ fn buildOutputType(
1830 var emit_h_resolved = emit_h.resolve(default_h_basename) catch |err| {1836 var emit_h_resolved = emit_h.resolve(default_h_basename) catch |err| {
1831 switch (emit_h) {1837 switch (emit_h) {
1832 .yes => {1838 .yes => {
1833 fatal("unable to open directory from argument 'femit-h', '{s}': {s}", .{ emit_h.yes, @errorName(err) });1839 fatal("unable to open directory from argument '-femit-h', '{s}': {s}", .{ emit_h.yes, @errorName(err) });
1834 },1840 },
1835 .yes_default_path => {1841 .yes_default_path => {
1836 fatal("unable to open directory from arguments 'name' or 'soname', '{s}': {s}", .{ default_h_basename, @errorName(err) });1842 fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ default_h_basename, @errorName(err) });
1837 },1843 },
1838 .no => unreachable,1844 .no => unreachable,
1839 }1845 }
...@@ -1844,10 +1850,10 @@ fn buildOutputType(...@@ -1844,10 +1850,10 @@ fn buildOutputType(
1844 var emit_asm_resolved = emit_asm.resolve(default_asm_basename) catch |err| {1850 var emit_asm_resolved = emit_asm.resolve(default_asm_basename) catch |err| {
1845 switch (emit_asm) {1851 switch (emit_asm) {
1846 .yes => {1852 .yes => {
1847 fatal("unable to open directory from argument 'femit-asm', '{s}': {s}", .{ emit_asm.yes, @errorName(err) });1853 fatal("unable to open directory from argument '-femit-asm', '{s}': {s}", .{ emit_asm.yes, @errorName(err) });
1848 },1854 },
1849 .yes_default_path => {1855 .yes_default_path => {
1850 fatal("unable to open directory from arguments 'name' or 'soname', '{s}': {s}", .{ default_asm_basename, @errorName(err) });1856 fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ default_asm_basename, @errorName(err) });
1851 },1857 },
1852 .no => unreachable,1858 .no => unreachable,
1853 }1859 }
...@@ -1858,16 +1864,30 @@ fn buildOutputType(...@@ -1858,16 +1864,30 @@ fn buildOutputType(
1858 var emit_llvm_ir_resolved = emit_llvm_ir.resolve(default_llvm_ir_basename) catch |err| {1864 var emit_llvm_ir_resolved = emit_llvm_ir.resolve(default_llvm_ir_basename) catch |err| {
1859 switch (emit_llvm_ir) {1865 switch (emit_llvm_ir) {
1860 .yes => {1866 .yes => {
1861 fatal("unable to open directory from argument 'femit-llvm-ir', '{s}': {s}", .{ emit_llvm_ir.yes, @errorName(err) });1867 fatal("unable to open directory from argument '-femit-llvm-ir', '{s}': {s}", .{ emit_llvm_ir.yes, @errorName(err) });
1862 },1868 },
1863 .yes_default_path => {1869 .yes_default_path => {
1864 fatal("unable to open directory from arguments 'name' or 'soname', '{s}': {s}", .{ default_llvm_ir_basename, @errorName(err) });1870 fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ default_llvm_ir_basename, @errorName(err) });
1865 },1871 },
1866 .no => unreachable,1872 .no => unreachable,
1867 }1873 }
1868 };1874 };
1869 defer emit_llvm_ir_resolved.deinit();1875 defer emit_llvm_ir_resolved.deinit();
18701876
1877 const default_llvm_bc_basename = try std.fmt.allocPrint(arena, "{s}.bc", .{root_name});
1878 var emit_llvm_bc_resolved = emit_llvm_bc.resolve(default_llvm_bc_basename) catch |err| {
1879 switch (emit_llvm_bc) {
1880 .yes => {
1881 fatal("unable to open directory from argument '-femit-llvm-bc', '{s}': {s}", .{ emit_llvm_bc.yes, @errorName(err) });
1882 },
1883 .yes_default_path => {
1884 fatal("unable to open directory from arguments '--name' or '-fsoname', '{s}': {s}", .{ default_llvm_bc_basename, @errorName(err) });
1885 },
1886 .no => unreachable,
1887 }
1888 };
1889 defer emit_llvm_bc_resolved.deinit();
1890
1871 const default_analysis_basename = try std.fmt.allocPrint(arena, "{s}-analysis.json", .{root_name});1891 const default_analysis_basename = try std.fmt.allocPrint(arena, "{s}-analysis.json", .{root_name});
1872 var emit_analysis_resolved = emit_analysis.resolve(default_analysis_basename) catch |err| {1892 var emit_analysis_resolved = emit_analysis.resolve(default_analysis_basename) catch |err| {
1873 switch (emit_analysis) {1893 switch (emit_analysis) {
...@@ -2003,6 +2023,7 @@ fn buildOutputType(...@@ -2003,6 +2023,7 @@ fn buildOutputType(
2003 .emit_h = emit_h_resolved.data,2023 .emit_h = emit_h_resolved.data,
2004 .emit_asm = emit_asm_resolved.data,2024 .emit_asm = emit_asm_resolved.data,
2005 .emit_llvm_ir = emit_llvm_ir_resolved.data,2025 .emit_llvm_ir = emit_llvm_ir_resolved.data,
2026 .emit_llvm_bc = emit_llvm_bc_resolved.data,
2006 .emit_docs = emit_docs_resolved.data,2027 .emit_docs = emit_docs_resolved.data,
2007 .emit_analysis = emit_analysis_resolved.data,2028 .emit_analysis = emit_analysis_resolved.data,
2008 .link_mode = link_mode,2029 .link_mode = link_mode,
...@@ -2408,11 +2429,8 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi...@@ -2408,11 +2429,8 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi
24082429
2409 // If a .pdb file is part of the expected output, we must also copy2430 // If a .pdb file is part of the expected output, we must also copy
2410 // it into place here.2431 // it into place here.
2411 const coff_or_pe = switch (comp.bin_file.options.object_format) {2432 const is_coff = comp.bin_file.options.object_format == .coff;
2412 .coff, .pe => true,2433 const have_pdb = is_coff and !comp.bin_file.options.strip;
2413 else => false,
2414 };
2415 const have_pdb = coff_or_pe and !comp.bin_file.options.strip;
2416 if (have_pdb) {2434 if (have_pdb) {
2417 // Replace `.out` or `.exe` with `.pdb` on both the source and destination2435 // Replace `.out` or `.exe` with `.pdb` on both the source and destination
2418 const src_bin_ext = fs.path.extension(bin_sub_path);2436 const src_bin_ext = fs.path.extension(bin_sub_path);
src/stage1.zig+3-1
...@@ -21,7 +21,6 @@ comptime {...@@ -21,7 +21,6 @@ comptime {
21 assert(build_options.is_stage1);21 assert(build_options.is_stage1);
22 assert(build_options.have_llvm);22 assert(build_options.have_llvm);
23 if (!builtin.is_test) {23 if (!builtin.is_test) {
24 _ = @import("compiler_rt");
25 @export(main, .{ .name = "main" });24 @export(main, .{ .name = "main" });
26 }25 }
27}26}
...@@ -95,6 +94,8 @@ pub const Module = extern struct {...@@ -95,6 +94,8 @@ pub const Module = extern struct {
95 emit_asm_len: usize,94 emit_asm_len: usize,
96 emit_llvm_ir_ptr: [*]const u8,95 emit_llvm_ir_ptr: [*]const u8,
97 emit_llvm_ir_len: usize,96 emit_llvm_ir_len: usize,
97 emit_bitcode_ptr: [*]const u8,
98 emit_bitcode_len: usize,
98 emit_analysis_json_ptr: [*]const u8,99 emit_analysis_json_ptr: [*]const u8,
99 emit_analysis_json_len: usize,100 emit_analysis_json_len: usize,
100 emit_docs_ptr: [*]const u8,101 emit_docs_ptr: [*]const u8,
...@@ -124,6 +125,7 @@ pub const Module = extern struct {...@@ -124,6 +125,7 @@ pub const Module = extern struct {
124 valgrind_enabled: bool,125 valgrind_enabled: bool,
125 tsan_enabled: bool,126 tsan_enabled: bool,
126 function_sections: bool,127 function_sections: bool,
128 include_compiler_rt: bool,
127 enable_stack_probing: bool,129 enable_stack_probing: bool,
128 red_zone: bool,130 red_zone: bool,
129 enable_time_report: bool,131 enable_time_report: bool,
src/stage1/all_types.hpp+2
...@@ -2090,6 +2090,7 @@ struct CodeGen {...@@ -2090,6 +2090,7 @@ struct CodeGen {
2090 Buf h_file_output_path;2090 Buf h_file_output_path;
2091 Buf asm_file_output_path;2091 Buf asm_file_output_path;
2092 Buf llvm_ir_file_output_path;2092 Buf llvm_ir_file_output_path;
2093 Buf bitcode_file_output_path;
2093 Buf analysis_json_output_path;2094 Buf analysis_json_output_path;
2094 Buf docs_output_path;2095 Buf docs_output_path;
20952096
...@@ -2149,6 +2150,7 @@ struct CodeGen {...@@ -2149,6 +2150,7 @@ struct CodeGen {
2149 bool have_stack_probing;2150 bool have_stack_probing;
2150 bool red_zone;2151 bool red_zone;
2151 bool function_sections;2152 bool function_sections;
2153 bool include_compiler_rt;
2152 bool test_is_evented;2154 bool test_is_evented;
2153 bool valgrind_enabled;2155 bool valgrind_enabled;
2154 bool tsan_enabled;2156 bool tsan_enabled;
src/stage1/codegen.cpp+27-6
...@@ -8506,19 +8506,22 @@ static void zig_llvm_emit_output(CodeGen *g) {...@@ -8506,19 +8506,22 @@ static void zig_llvm_emit_output(CodeGen *g) {
8506 const char *asm_filename = nullptr;8506 const char *asm_filename = nullptr;
8507 const char *bin_filename = nullptr;8507 const char *bin_filename = nullptr;
8508 const char *llvm_ir_filename = nullptr;8508 const char *llvm_ir_filename = nullptr;
8509 const char *bitcode_filename = nullptr;
85098510
8510 if (buf_len(&g->o_file_output_path) != 0) bin_filename = buf_ptr(&g->o_file_output_path);8511 if (buf_len(&g->o_file_output_path) != 0) bin_filename = buf_ptr(&g->o_file_output_path);
8511 if (buf_len(&g->asm_file_output_path) != 0) asm_filename = buf_ptr(&g->asm_file_output_path);8512 if (buf_len(&g->asm_file_output_path) != 0) asm_filename = buf_ptr(&g->asm_file_output_path);
8512 if (buf_len(&g->llvm_ir_file_output_path) != 0) llvm_ir_filename = buf_ptr(&g->llvm_ir_file_output_path);8513 if (buf_len(&g->llvm_ir_file_output_path) != 0) llvm_ir_filename = buf_ptr(&g->llvm_ir_file_output_path);
8514 if (buf_len(&g->bitcode_file_output_path) != 0) bitcode_filename = buf_ptr(&g->bitcode_file_output_path);
85138515
8514 // Unfortunately, LLVM shits the bed when we ask for both binary and assembly. So we call the entire8516 // Unfortunately, LLVM shits the bed when we ask for both binary and assembly.
8515 // pipeline multiple times if this is requested.8517 // So we call the entire pipeline multiple times if this is requested.
8516 if (asm_filename != nullptr && bin_filename != nullptr) {8518 if (asm_filename != nullptr && bin_filename != nullptr) {
8517 if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg,8519 if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg,
8518 g->build_mode == BuildModeDebug, is_small, g->enable_time_report, g->tsan_enabled,8520 g->build_mode == BuildModeDebug, is_small, g->enable_time_report, g->tsan_enabled,
8519 g->have_lto, nullptr, bin_filename, llvm_ir_filename))8521 g->have_lto, nullptr, bin_filename, llvm_ir_filename, nullptr))
8520 {8522 {
8521 fprintf(stderr, "LLVM failed to emit file: %s\n", err_msg);8523 fprintf(stderr, "LLVM failed to emit bin=%s, ir=%s: %s\n",
8524 bin_filename, llvm_ir_filename, err_msg);
8522 exit(1);8525 exit(1);
8523 }8526 }
8524 bin_filename = nullptr;8527 bin_filename = nullptr;
...@@ -8527,9 +8530,11 @@ static void zig_llvm_emit_output(CodeGen *g) {...@@ -8527,9 +8530,11 @@ static void zig_llvm_emit_output(CodeGen *g) {
85278530
8528 if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg,8531 if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, &err_msg,
8529 g->build_mode == BuildModeDebug, is_small, g->enable_time_report, g->tsan_enabled,8532 g->build_mode == BuildModeDebug, is_small, g->enable_time_report, g->tsan_enabled,
8530 g->have_lto, asm_filename, bin_filename, llvm_ir_filename))8533 g->have_lto, asm_filename, bin_filename, llvm_ir_filename, bitcode_filename))
8531 {8534 {
8532 fprintf(stderr, "LLVM failed to emit file: %s\n", err_msg);8535 fprintf(stderr, "LLVM failed to emit asm=%s, bin=%s, ir=%s, bc=%s: %s\n",
8536 asm_filename, bin_filename, llvm_ir_filename, bitcode_filename,
8537 err_msg);
8533 exit(1);8538 exit(1);
8534 }8539 }
85358540
...@@ -9537,6 +9542,22 @@ static void gen_root_source(CodeGen *g) {...@@ -9537,6 +9542,22 @@ static void gen_root_source(CodeGen *g) {
9537 g->panic_fn = panic_fn_val->data.x_ptr.data.fn.fn_entry;9542 g->panic_fn = panic_fn_val->data.x_ptr.data.fn.fn_entry;
9538 assert(g->panic_fn != nullptr);9543 assert(g->panic_fn != nullptr);
95399544
9545 if (g->include_compiler_rt) {
9546 Buf *import_target_path;
9547 Buf full_path = BUF_INIT;
9548 ZigType *compiler_rt_import;
9549 if ((err = analyze_import(g, std_import, buf_create_from_str("./special/compiler_rt.zig"),
9550 &compiler_rt_import, &import_target_path, &full_path)))
9551 {
9552 if (err == ErrorFileNotFound) {
9553 fprintf(stderr, "unable to find '%s'", buf_ptr(import_target_path));
9554 } else {
9555 fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(&full_path), err_str(err));
9556 }
9557 exit(1);
9558 }
9559 }
9560
9540 if (!g->error_during_imports) {9561 if (!g->error_during_imports) {
9541 semantic_analyze(g);9562 semantic_analyze(g);
9542 }9563 }
src/stage1/stage1.cpp+2
...@@ -73,6 +73,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {...@@ -73,6 +73,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
73 buf_init_from_mem(&g->h_file_output_path, stage1->emit_h_ptr, stage1->emit_h_len);73 buf_init_from_mem(&g->h_file_output_path, stage1->emit_h_ptr, stage1->emit_h_len);
74 buf_init_from_mem(&g->asm_file_output_path, stage1->emit_asm_ptr, stage1->emit_asm_len);74 buf_init_from_mem(&g->asm_file_output_path, stage1->emit_asm_ptr, stage1->emit_asm_len);
75 buf_init_from_mem(&g->llvm_ir_file_output_path, stage1->emit_llvm_ir_ptr, stage1->emit_llvm_ir_len);75 buf_init_from_mem(&g->llvm_ir_file_output_path, stage1->emit_llvm_ir_ptr, stage1->emit_llvm_ir_len);
76 buf_init_from_mem(&g->bitcode_file_output_path, stage1->emit_bitcode_ptr, stage1->emit_bitcode_len);
76 buf_init_from_mem(&g->analysis_json_output_path, stage1->emit_analysis_json_ptr, stage1->emit_analysis_json_len);77 buf_init_from_mem(&g->analysis_json_output_path, stage1->emit_analysis_json_ptr, stage1->emit_analysis_json_len);
77 buf_init_from_mem(&g->docs_output_path, stage1->emit_docs_ptr, stage1->emit_docs_len);78 buf_init_from_mem(&g->docs_output_path, stage1->emit_docs_ptr, stage1->emit_docs_len);
7879
...@@ -100,6 +101,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {...@@ -100,6 +101,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
100 g->link_libc = stage1->link_libc;101 g->link_libc = stage1->link_libc;
101 g->link_libcpp = stage1->link_libcpp;102 g->link_libcpp = stage1->link_libcpp;
102 g->function_sections = stage1->function_sections;103 g->function_sections = stage1->function_sections;
104 g->include_compiler_rt = stage1->include_compiler_rt;
103105
104 g->subsystem = stage1->subsystem;106 g->subsystem = stage1->subsystem;
105107
src/stage1/stage1.h+4
...@@ -157,6 +157,9 @@ struct ZigStage1 {...@@ -157,6 +157,9 @@ struct ZigStage1 {
157 const char *emit_llvm_ir_ptr;157 const char *emit_llvm_ir_ptr;
158 size_t emit_llvm_ir_len;158 size_t emit_llvm_ir_len;
159159
160 const char *emit_bitcode_ptr;
161 size_t emit_bitcode_len;
162
160 const char *emit_analysis_json_ptr;163 const char *emit_analysis_json_ptr;
161 size_t emit_analysis_json_len;164 size_t emit_analysis_json_len;
162165
...@@ -193,6 +196,7 @@ struct ZigStage1 {...@@ -193,6 +196,7 @@ struct ZigStage1 {
193 bool valgrind_enabled;196 bool valgrind_enabled;
194 bool tsan_enabled;197 bool tsan_enabled;
195 bool function_sections;198 bool function_sections;
199 bool include_compiler_rt;
196 bool enable_stack_probing;200 bool enable_stack_probing;
197 bool red_zone;201 bool red_zone;
198 bool enable_time_report;202 bool enable_time_report;
src/stage1/zig0.cpp+5
...@@ -39,6 +39,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {...@@ -39,6 +39,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
39 " --color [auto|off|on] enable or disable colored error messages\n"39 " --color [auto|off|on] enable or disable colored error messages\n"
40 " --name [name] override output name\n"40 " --name [name] override output name\n"
41 " -femit-bin=[path] Output machine code\n"41 " -femit-bin=[path] Output machine code\n"
42 " -fcompiler-rt Always include compiler-rt symbols in output\n"
42 " --pkg-begin [name] [path] make pkg available to import and push current pkg\n"43 " --pkg-begin [name] [path] make pkg available to import and push current pkg\n"
43 " --pkg-end pop current pkg\n"44 " --pkg-end pop current pkg\n"
44 " -ODebug build with optimizations off and safety on\n"45 " -ODebug build with optimizations off and safety on\n"
...@@ -266,6 +267,7 @@ int main(int argc, char **argv) {...@@ -266,6 +267,7 @@ int main(int argc, char **argv) {
266 const char *mcpu = nullptr;267 const char *mcpu = nullptr;
267 bool single_threaded = false;268 bool single_threaded = false;
268 bool is_test_build = false;269 bool is_test_build = false;
270 bool include_compiler_rt = false;
269271
270 for (int i = 1; i < argc; i += 1) {272 for (int i = 1; i < argc; i += 1) {
271 char *arg = argv[i];273 char *arg = argv[i];
...@@ -334,6 +336,8 @@ int main(int argc, char **argv) {...@@ -334,6 +336,8 @@ int main(int argc, char **argv) {
334 mcpu = arg + strlen("-mcpu=");336 mcpu = arg + strlen("-mcpu=");
335 } else if (str_starts_with(arg, "-femit-bin=")) {337 } else if (str_starts_with(arg, "-femit-bin=")) {
336 emit_bin_path = arg + strlen("-femit-bin=");338 emit_bin_path = arg + strlen("-femit-bin=");
339 } else if (strcmp(arg, "-fcompiler-rt") == 0) {
340 include_compiler_rt = true;
337 } else if (i + 1 >= argc) {341 } else if (i + 1 >= argc) {
338 fprintf(stderr, "Expected another argument after %s\n", arg);342 fprintf(stderr, "Expected another argument after %s\n", arg);
339 return print_error_usage(arg0);343 return print_error_usage(arg0);
...@@ -468,6 +472,7 @@ int main(int argc, char **argv) {...@@ -468,6 +472,7 @@ int main(int argc, char **argv) {
468 stage1->subsystem = subsystem;472 stage1->subsystem = subsystem;
469 stage1->pic = true;473 stage1->pic = true;
470 stage1->is_single_threaded = single_threaded;474 stage1->is_single_threaded = single_threaded;
475 stage1->include_compiler_rt = include_compiler_rt;
471476
472 zig_stage1_build_object(stage1);477 zig_stage1_build_object(stage1);
473478
src/translate_c.zig+257-15
...@@ -2,6 +2,7 @@...@@ -2,6 +2,7 @@
2//! and stage2.2//! and stage2.
33
4const std = @import("std");4const std = @import("std");
5const testing = std.testing;
5const assert = std.debug.assert;6const assert = std.debug.assert;
6const clang = @import("clang.zig");7const clang = @import("clang.zig");
7const ctok = std.c.tokenizer;8const ctok = std.c.tokenizer;
...@@ -18,6 +19,7 @@ const CallingConvention = std.builtin.CallingConvention;...@@ -18,6 +19,7 @@ const CallingConvention = std.builtin.CallingConvention;
18pub const ClangErrMsg = clang.Stage2ErrorMsg;19pub const ClangErrMsg = clang.Stage2ErrorMsg;
1920
20pub const Error = std.mem.Allocator.Error;21pub const Error = std.mem.Allocator.Error;
22const MacroProcessingError = Error || error{UnexpectedMacroToken};
21const TypeError = Error || error{UnsupportedType};23const TypeError = Error || error{UnsupportedType};
22const TransError = TypeError || error{UnsupportedTranslation};24const TransError = TypeError || error{UnsupportedTranslation};
2325
...@@ -27,6 +29,10 @@ const AliasList = std.ArrayList(struct {...@@ -27,6 +29,10 @@ const AliasList = std.ArrayList(struct {
27 name: []const u8,29 name: []const u8,
28});30});
2931
32// Maps macro parameter names to token position, for determining if different
33// identifiers refer to the same positional argument in different macros.
34const ArgsPositionMap = std.StringArrayHashMapUnmanaged(usize);
35
30const Scope = struct {36const Scope = struct {
31 id: Id,37 id: Id,
32 parent: ?*Scope,38 parent: ?*Scope,
...@@ -322,6 +328,8 @@ pub const Context = struct {...@@ -322,6 +328,8 @@ pub const Context = struct {
322 /// up front in a pre-processing step.328 /// up front in a pre-processing step.
323 global_names: std.StringArrayHashMapUnmanaged(void) = .{},329 global_names: std.StringArrayHashMapUnmanaged(void) = .{},
324330
331 pattern_list: PatternList,
332
325 fn getMangle(c: *Context) u32 {333 fn getMangle(c: *Context) u32 {
326 c.mangle_count += 1;334 c.mangle_count += 1;
327 return c.mangle_count;335 return c.mangle_count;
...@@ -375,6 +383,7 @@ pub fn translate(...@@ -375,6 +383,7 @@ pub fn translate(
375 .alias_list = AliasList.init(gpa),383 .alias_list = AliasList.init(gpa),
376 .global_scope = try arena.allocator.create(Scope.Root),384 .global_scope = try arena.allocator.create(Scope.Root),
377 .clang_context = ast_unit.getASTContext(),385 .clang_context = ast_unit.getASTContext(),
386 .pattern_list = try PatternList.init(gpa),
378 };387 };
379 context.global_scope.* = Scope.Root.init(&context);388 context.global_scope.* = Scope.Root.init(&context);
380 defer {389 defer {
...@@ -385,6 +394,7 @@ pub fn translate(...@@ -385,6 +394,7 @@ pub fn translate(
385 context.unnamed_typedefs.deinit(gpa);394 context.unnamed_typedefs.deinit(gpa);
386 context.typedefs.deinit(gpa);395 context.typedefs.deinit(gpa);
387 context.global_scope.deinit();396 context.global_scope.deinit();
397 context.pattern_list.deinit(gpa);
388 }398 }
389399
390 try context.global_scope.nodes.append(Tag.usingnamespace_builtins.init());400 try context.global_scope.nodes.append(Tag.usingnamespace_builtins.init());
...@@ -4829,6 +4839,220 @@ fn isZigPrimitiveType(name: []const u8) bool {...@@ -4829,6 +4839,220 @@ fn isZigPrimitiveType(name: []const u8) bool {
4829 return @import("AstGen.zig").simple_types.has(name);4839 return @import("AstGen.zig").simple_types.has(name);
4830}4840}
48314841
4842const PatternList = struct {
4843 patterns: []Pattern,
4844
4845 /// Templates must be function-like macros
4846 /// first element is macro source, second element is the name of the function
4847 /// in std.lib.zig.c_translation.Macros which implements it
4848 const templates = [_][2][]const u8{
4849 [2][]const u8{ "f_SUFFIX(X) (X ## f)", "F_SUFFIX" },
4850 [2][]const u8{ "F_SUFFIX(X) (X ## F)", "F_SUFFIX" },
4851
4852 [2][]const u8{ "u_SUFFIX(X) (X ## u)", "U_SUFFIX" },
4853 [2][]const u8{ "U_SUFFIX(X) (X ## U)", "U_SUFFIX" },
4854
4855 [2][]const u8{ "l_SUFFIX(X) (X ## l)", "L_SUFFIX" },
4856 [2][]const u8{ "L_SUFFIX(X) (X ## L)", "L_SUFFIX" },
4857
4858 [2][]const u8{ "ul_SUFFIX(X) (X ## ul)", "UL_SUFFIX" },
4859 [2][]const u8{ "uL_SUFFIX(X) (X ## uL)", "UL_SUFFIX" },
4860 [2][]const u8{ "Ul_SUFFIX(X) (X ## Ul)", "UL_SUFFIX" },
4861 [2][]const u8{ "UL_SUFFIX(X) (X ## UL)", "UL_SUFFIX" },
4862
4863 [2][]const u8{ "ll_SUFFIX(X) (X ## ll)", "LL_SUFFIX" },
4864 [2][]const u8{ "LL_SUFFIX(X) (X ## LL)", "LL_SUFFIX" },
4865
4866 [2][]const u8{ "ull_SUFFIX(X) (X ## ull)", "ULL_SUFFIX" },
4867 [2][]const u8{ "uLL_SUFFIX(X) (X ## uLL)", "ULL_SUFFIX" },
4868 [2][]const u8{ "Ull_SUFFIX(X) (X ## Ull)", "ULL_SUFFIX" },
4869 [2][]const u8{ "ULL_SUFFIX(X) (X ## ULL)", "ULL_SUFFIX" },
4870
4871 [2][]const u8{ "CAST_OR_CALL(X, Y) (X)(Y)", "CAST_OR_CALL" },
4872
4873 [2][]const u8{
4874 \\wl_container_of(ptr, sample, member) \
4875 \\(__typeof__(sample))((char *)(ptr) - \
4876 \\ offsetof(__typeof__(*sample), member))
4877 ,
4878 "WL_CONTAINER_OF",
4879 },
4880 };
4881
4882 /// Assumes that `ms` represents a tokenized function-like macro.
4883 fn buildArgsHash(allocator: *mem.Allocator, ms: MacroSlicer, hash: *ArgsPositionMap) MacroProcessingError!void {
4884 assert(ms.tokens.len > 2);
4885 assert(ms.tokens[0].id == .Identifier);
4886 assert(ms.tokens[1].id == .LParen);
4887
4888 var i: usize = 2;
4889 while (true) : (i += 1) {
4890 const token = ms.tokens[i];
4891 switch (token.id) {
4892 .RParen => break,
4893 .Comma => continue,
4894 .Identifier => {
4895 const identifier = ms.slice(token);
4896 try hash.put(allocator, identifier, i);
4897 },
4898 else => return error.UnexpectedMacroToken,
4899 }
4900 }
4901 }
4902
4903 const Pattern = struct {
4904 tokens: []const CToken,
4905 source: []const u8,
4906 impl: []const u8,
4907 args_hash: ArgsPositionMap,
4908
4909 fn init(self: *Pattern, allocator: *mem.Allocator, template: [2][]const u8) Error!void {
4910 const source = template[0];
4911 const impl = template[1];
4912
4913 var tok_list = std.ArrayList(CToken).init(allocator);
4914 defer tok_list.deinit();
4915 try tokenizeMacro(source, &tok_list);
4916 const tokens = try allocator.dupe(CToken, tok_list.items);
4917
4918 self.* = .{
4919 .tokens = tokens,
4920 .source = source,
4921 .impl = impl,
4922 .args_hash = .{},
4923 };
4924 const ms = MacroSlicer{ .source = source, .tokens = tokens };
4925 buildArgsHash(allocator, ms, &self.args_hash) catch |err| switch (err) {
4926 error.UnexpectedMacroToken => unreachable,
4927 else => |e| return e,
4928 };
4929 }
4930
4931 fn deinit(self: *Pattern, allocator: *mem.Allocator) void {
4932 self.args_hash.deinit(allocator);
4933 allocator.free(self.tokens);
4934 }
4935
4936 /// This function assumes that `ms` has already been validated to contain a function-like
4937 /// macro, and that the parsed template macro in `self` also contains a function-like
4938 /// macro. Please review this logic carefully if changing that assumption. Two
4939 /// function-like macros are considered equivalent if and only if they contain the same
4940 /// list of tokens, modulo parameter names.
4941 fn isEquivalent(self: Pattern, ms: MacroSlicer, args_hash: ArgsPositionMap) bool {
4942 if (self.tokens.len != ms.tokens.len) return false;
4943 if (args_hash.count() != self.args_hash.count()) return false;
4944
4945 var i: usize = 2;
4946 while (self.tokens[i].id != .RParen) : (i += 1) {}
4947
4948 const pattern_slicer = MacroSlicer{ .source = self.source, .tokens = self.tokens };
4949 while (i < self.tokens.len) : (i += 1) {
4950 const pattern_token = self.tokens[i];
4951 const macro_token = ms.tokens[i];
4952 if (meta.activeTag(pattern_token.id) != meta.activeTag(macro_token.id)) return false;
4953
4954 const pattern_bytes = pattern_slicer.slice(pattern_token);
4955 const macro_bytes = ms.slice(macro_token);
4956 switch (pattern_token.id) {
4957 .Identifier => {
4958 const pattern_arg_index = self.args_hash.get(pattern_bytes);
4959 const macro_arg_index = args_hash.get(macro_bytes);
4960
4961 if (pattern_arg_index == null and macro_arg_index == null) {
4962 if (!mem.eql(u8, pattern_bytes, macro_bytes)) return false;
4963 } else if (pattern_arg_index != null and macro_arg_index != null) {
4964 if (pattern_arg_index.? != macro_arg_index.?) return false;
4965 } else {
4966 return false;
4967 }
4968 },
4969 .MacroString, .StringLiteral, .CharLiteral, .IntegerLiteral, .FloatLiteral => {
4970 if (!mem.eql(u8, pattern_bytes, macro_bytes)) return false;
4971 },
4972 else => {
4973 // other tags correspond to keywords and operators that do not contain a "payload"
4974 // that can vary
4975 },
4976 }
4977 }
4978 return true;
4979 }
4980 };
4981
4982 fn init(allocator: *mem.Allocator) Error!PatternList {
4983 const patterns = try allocator.alloc(Pattern, templates.len);
4984 for (templates) |template, i| {
4985 try patterns[i].init(allocator, template);
4986 }
4987 return PatternList{ .patterns = patterns };
4988 }
4989
4990 fn deinit(self: *PatternList, allocator: *mem.Allocator) void {
4991 for (self.patterns) |*pattern| pattern.deinit(allocator);
4992 allocator.free(self.patterns);
4993 }
4994
4995 fn match(self: PatternList, allocator: *mem.Allocator, ms: MacroSlicer) Error!?Pattern {
4996 var args_hash: ArgsPositionMap = .{};
4997 defer args_hash.deinit(allocator);
4998
4999 buildArgsHash(allocator, ms, &args_hash) catch |err| switch (err) {
5000 error.UnexpectedMacroToken => return null,
5001 else => |e| return e,
5002 };
5003
5004 for (self.patterns) |pattern| if (pattern.isEquivalent(ms, args_hash)) return pattern;
5005 return null;
5006 }
5007};
5008
5009const MacroSlicer = struct {
5010 source: []const u8,
5011 tokens: []const CToken,
5012 fn slice(self: MacroSlicer, token: CToken) []const u8 {
5013 return self.source[token.start..token.end];
5014 }
5015};
5016
5017// Testing here instead of test/translate_c.zig allows us to also test that the
5018// mapped function exists in `std.zig.c_translation.Macros`
5019test "Macro matching" {
5020 const helper = struct {
5021 const MacroFunctions = @import("std").zig.c_translation.Macros;
5022 fn checkMacro(allocator: *mem.Allocator, pattern_list: PatternList, source: []const u8, comptime expected_match: ?[]const u8) !void {
5023 var tok_list = std.ArrayList(CToken).init(allocator);
5024 defer tok_list.deinit();
5025 try tokenizeMacro(source, &tok_list);
5026 const macro_slicer = MacroSlicer{ .source = source, .tokens = tok_list.items };
5027 const matched = try pattern_list.match(allocator, macro_slicer);
5028 if (expected_match) |expected| {
5029 try testing.expectEqualStrings(expected, matched.?.impl);
5030 try testing.expect(@hasDecl(MacroFunctions, expected));
5031 } else {
5032 try testing.expectEqual(@as(@TypeOf(matched), null), matched);
5033 }
5034 }
5035 };
5036 const allocator = std.testing.allocator;
5037 var pattern_list = try PatternList.init(allocator);
5038 defer pattern_list.deinit(allocator);
5039
5040 try helper.checkMacro(allocator, pattern_list, "BAR(Z) (Z ## F)", "F_SUFFIX");
5041 try helper.checkMacro(allocator, pattern_list, "BAR(Z) (Z ## U)", "U_SUFFIX");
5042 try helper.checkMacro(allocator, pattern_list, "BAR(Z) (Z ## L)", "L_SUFFIX");
5043 try helper.checkMacro(allocator, pattern_list, "BAR(Z) (Z ## LL)", "LL_SUFFIX");
5044 try helper.checkMacro(allocator, pattern_list, "BAR(Z) (Z ## UL)", "UL_SUFFIX");
5045 try helper.checkMacro(allocator, pattern_list, "BAR(Z) (Z ## ULL)", "ULL_SUFFIX");
5046 try helper.checkMacro(allocator, pattern_list,
5047 \\container_of(a, b, c) \
5048 \\(__typeof__(b))((char *)(a) - \
5049 \\ offsetof(__typeof__(*b), c))
5050 , "WL_CONTAINER_OF");
5051
5052 try helper.checkMacro(allocator, pattern_list, "NO_MATCH(X, Y) (X + Y)", null);
5053 try helper.checkMacro(allocator, pattern_list, "CAST_OR_CALL(X, Y) (X)(Y)", "CAST_OR_CALL");
5054}
5055
4832const MacroCtx = struct {5056const MacroCtx = struct {
4833 source: []const u8,5057 source: []const u8,
4834 list: []const CToken,5058 list: []const CToken,
...@@ -4855,8 +5079,30 @@ const MacroCtx = struct {...@@ -4855,8 +5079,30 @@ const MacroCtx = struct {
4855 fn fail(self: *MacroCtx, c: *Context, comptime fmt: []const u8, args: anytype) !void {5079 fn fail(self: *MacroCtx, c: *Context, comptime fmt: []const u8, args: anytype) !void {
4856 return failDecl(c, self.loc, self.name, fmt, args);5080 return failDecl(c, self.loc, self.name, fmt, args);
4857 }5081 }
5082
5083 fn makeSlicer(self: *const MacroCtx) MacroSlicer {
5084 return MacroSlicer{ .source = self.source, .tokens = self.list };
5085 }
4858};5086};
48595087
5088fn tokenizeMacro(source: []const u8, tok_list: *std.ArrayList(CToken)) Error!void {
5089 var tokenizer = std.c.Tokenizer{
5090 .buffer = source,
5091 };
5092 while (true) {
5093 const tok = tokenizer.next();
5094 switch (tok.id) {
5095 .Nl, .Eof => {
5096 try tok_list.append(tok);
5097 break;
5098 },
5099 .LineComment, .MultiLineComment => continue,
5100 else => {},
5101 }
5102 try tok_list.append(tok);
5103 }
5104}
5105
4860fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {5106fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
4861 // TODO if we see #undef, delete it from the table5107 // TODO if we see #undef, delete it from the table
4862 var it = unit.getLocalPreprocessingEntities_begin();5108 var it = unit.getLocalPreprocessingEntities_begin();
...@@ -4888,21 +5134,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {...@@ -4888,21 +5134,7 @@ fn transPreprocessorEntities(c: *Context, unit: *clang.ASTUnit) Error!void {
4888 const slice_len = @ptrToInt(end_c) - @ptrToInt(begin_c);5134 const slice_len = @ptrToInt(end_c) - @ptrToInt(begin_c);
4889 const slice = begin_c[0..slice_len];5135 const slice = begin_c[0..slice_len];
48905136
4891 var tokenizer = std.c.Tokenizer{5137 try tokenizeMacro(slice, &tok_list);
4892 .buffer = slice,
4893 };
4894 while (true) {
4895 const tok = tokenizer.next();
4896 switch (tok.id) {
4897 .Nl, .Eof => {
4898 try tok_list.append(tok);
4899 break;
4900 },
4901 .LineComment, .MultiLineComment => continue,
4902 else => {},
4903 }
4904 try tok_list.append(tok);
4905 }
49065138
4907 var macro_ctx = MacroCtx{5139 var macro_ctx = MacroCtx{
4908 .source = slice,5140 .source = slice,
...@@ -4960,6 +5192,16 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {...@@ -4960,6 +5192,16 @@ fn transMacroDefine(c: *Context, m: *MacroCtx) ParseError!void {
4960}5192}
49615193
4962fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {5194fn transMacroFnDefine(c: *Context, m: *MacroCtx) ParseError!void {
5195 const macro_slicer = m.makeSlicer();
5196 if (try c.pattern_list.match(c.gpa, macro_slicer)) |pattern| {
5197 const decl = try Tag.pub_var_simple.create(c.arena, .{
5198 .name = m.name,
5199 .init = try Tag.helpers_macro.create(c.arena, pattern.impl),
5200 });
5201 try c.global_scope.macro_table.put(m.name, decl);
5202 return;
5203 }
5204
4963 var block_scope = try Scope.Block.init(c, &c.global_scope.base, false);5205 var block_scope = try Scope.Block.init(c, &c.global_scope.base, false);
4964 defer block_scope.deinit();5206 defer block_scope.deinit();
4965 const scope = &block_scope.base;5207 const scope = &block_scope.base;
src/translate_c/ast.zig+14
...@@ -193,6 +193,8 @@ pub const Node = extern union {...@@ -193,6 +193,8 @@ pub const Node = extern union {
193 helpers_flexible_array_type,193 helpers_flexible_array_type,
194 /// @import("std").zig.c_translation.shuffleVectorIndex(lhs, rhs)194 /// @import("std").zig.c_translation.shuffleVectorIndex(lhs, rhs)
195 helpers_shuffle_vector_index,195 helpers_shuffle_vector_index,
196 /// @import("std").zig.c_translation.Macro.<operand>
197 helpers_macro,
196 /// @import("std").meta.Vector(lhs, rhs)198 /// @import("std").meta.Vector(lhs, rhs)
197 std_meta_vector,199 std_meta_vector,
198 /// @import("std").mem.zeroes(operand)200 /// @import("std").mem.zeroes(operand)
...@@ -339,6 +341,7 @@ pub const Node = extern union {...@@ -339,6 +341,7 @@ pub const Node = extern union {
339 .identifier,341 .identifier,
340 .warning,342 .warning,
341 .type,343 .type,
344 .helpers_macro,
342 => Payload.Value,345 => Payload.Value,
343 .discard => Payload.Discard,346 .discard => Payload.Discard,
344 .@"if" => Payload.If,347 .@"if" => Payload.If,
...@@ -1112,6 +1115,16 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -1112,6 +1115,16 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
1112 .data = undefined,1115 .data = undefined,
1113 });1116 });
1114 },1117 },
1118 .helpers_macro => {
1119 const payload = node.castTag(.helpers_macro).?.data;
1120 const chain = [_][]const u8{
1121 "zig",
1122 "c_translation",
1123 "Macros",
1124 payload,
1125 };
1126 return renderStdImport(c, &chain);
1127 },
1115 .string_slice => {1128 .string_slice => {
1116 const payload = node.castTag(.string_slice).?.data;1129 const payload = node.castTag(.string_slice).?.data;
11171130
...@@ -2310,6 +2323,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {...@@ -2310,6 +2323,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
2310 .bit_or_assign,2323 .bit_or_assign,
2311 .bit_xor_assign,2324 .bit_xor_assign,
2312 .assign,2325 .assign,
2326 .helpers_macro,
2313 => {2327 => {
2314 // these should never appear in places where grouping might be needed.2328 // these should never appear in places where grouping might be needed.
2315 unreachable;2329 unreachable;
src/zig_llvm.cpp+17-2
...@@ -229,12 +229,14 @@ struct TimeTracerRAII {...@@ -229,12 +229,14 @@ struct TimeTracerRAII {
229bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,229bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
230 char **error_message, bool is_debug,230 char **error_message, bool is_debug,
231 bool is_small, bool time_report, bool tsan, bool lto,231 bool is_small, bool time_report, bool tsan, bool lto,
232 const char *asm_filename, const char *bin_filename, const char *llvm_ir_filename)232 const char *asm_filename, const char *bin_filename,
233 const char *llvm_ir_filename, const char *bitcode_filename)
233{234{
234 TimePassesIsEnabled = time_report;235 TimePassesIsEnabled = time_report;
235236
236 raw_fd_ostream *dest_asm_ptr = nullptr;237 raw_fd_ostream *dest_asm_ptr = nullptr;
237 raw_fd_ostream *dest_bin_ptr = nullptr;238 raw_fd_ostream *dest_bin_ptr = nullptr;
239 raw_fd_ostream *dest_bitcode_ptr = nullptr;
238240
239 if (asm_filename) {241 if (asm_filename) {
240 std::error_code EC;242 std::error_code EC;
...@@ -252,9 +254,19 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM...@@ -252,9 +254,19 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
252 return true;254 return true;
253 }255 }
254 }256 }
257 if (bitcode_filename) {
258 std::error_code EC;
259 dest_bitcode_ptr = new(std::nothrow) raw_fd_ostream(bitcode_filename, EC, sys::fs::F_None);
260 if (EC) {
261 *error_message = strdup((const char *)StringRef(EC.message()).bytes_begin());
262 return true;
263 }
264 }
255265
256 std::unique_ptr<raw_fd_ostream> dest_asm(dest_asm_ptr),266 std::unique_ptr<raw_fd_ostream> dest_asm(dest_asm_ptr),
257 dest_bin(dest_bin_ptr);267 dest_bin(dest_bin_ptr),
268 dest_bitcode(dest_bitcode_ptr);
269
258270
259 auto PID = sys::Process::getProcessId();271 auto PID = sys::Process::getProcessId();
260 std::string ProcName = "zig-";272 std::string ProcName = "zig-";
...@@ -389,6 +401,9 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM...@@ -389,6 +401,9 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM
389 if (dest_bin && lto) {401 if (dest_bin && lto) {
390 WriteBitcodeToFile(module, *dest_bin);402 WriteBitcodeToFile(module, *dest_bin);
391 }403 }
404 if (dest_bitcode) {
405 WriteBitcodeToFile(module, *dest_bitcode);
406 }
392407
393 if (time_report) {408 if (time_report) {
394 TimerGroup::printAll(errs());409 TimerGroup::printAll(errs());
src/zig_llvm.h+2-1
...@@ -49,7 +49,8 @@ ZIG_EXTERN_C char *ZigLLVMGetNativeFeatures(void);...@@ -49,7 +49,8 @@ ZIG_EXTERN_C char *ZigLLVMGetNativeFeatures(void);
49ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,49ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref,
50 char **error_message, bool is_debug,50 char **error_message, bool is_debug,
51 bool is_small, bool time_report, bool tsan, bool lto,51 bool is_small, bool time_report, bool tsan, bool lto,
52 const char *asm_filename, const char *bin_filename, const char *llvm_ir_filename);52 const char *asm_filename, const char *bin_filename,
53 const char *llvm_ir_filename, const char *bitcode_filename);
5354
5455
55enum ZigLLVMABIType {56enum ZigLLVMABIType {
test/cases.zig+70
...@@ -1065,6 +1065,76 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1065,6 +1065,76 @@ pub fn addCases(ctx: *TestContext) !void {
1065 ":5:19: error: redeclaration of local constant 'c'",1065 ":5:19: error: redeclaration of local constant 'c'",
1066 ":4:19: note: previous declaration here",1066 ":4:19: note: previous declaration here",
1067 });1067 });
1068 case.addError(
1069 \\pub fn main() void {
1070 \\ var i = 0;
1071 \\ for (n) |_, i| {
1072 \\ }
1073 \\}
1074 , &[_][]const u8{
1075 ":3:17: error: redeclaration of local variable 'i'",
1076 ":2:9: note: previous declaration here",
1077 });
1078 case.addError(
1079 \\pub fn main() void {
1080 \\ var i = 0;
1081 \\ for (n) |i| {
1082 \\ }
1083 \\}
1084 , &[_][]const u8{
1085 ":3:14: error: redeclaration of local variable 'i'",
1086 ":2:9: note: previous declaration here",
1087 });
1088 case.addError(
1089 \\pub fn main() void {
1090 \\ var i = 0;
1091 \\ while (n) |i| {
1092 \\ }
1093 \\}
1094 , &[_][]const u8{
1095 ":3:16: error: redeclaration of local variable 'i'",
1096 ":2:9: note: previous declaration here",
1097 });
1098 case.addError(
1099 \\pub fn main() void {
1100 \\ var i = 0;
1101 \\ while (n) |bruh| {
1102 \\ _ = bruh;
1103 \\ } else |i| {
1104 \\
1105 \\ }
1106 \\}
1107 , &[_][]const u8{
1108 ":5:13: error: redeclaration of local variable 'i'",
1109 ":2:9: note: previous declaration here",
1110 });
1111 case.addError(
1112 \\pub fn main() void {
1113 \\ var i = 0;
1114 \\ if (true) |i| {}
1115 \\}
1116 , &[_][]const u8{
1117 ":3:16: error: redeclaration of local variable 'i'",
1118 ":2:9: note: previous declaration here",
1119 });
1120 case.addError(
1121 \\pub fn main() void {
1122 \\ var i = 0;
1123 \\ if (true) |i| {} else |e| {}
1124 \\}
1125 , &[_][]const u8{
1126 ":3:16: error: redeclaration of local variable 'i'",
1127 ":2:9: note: previous declaration here",
1128 });
1129 case.addError(
1130 \\pub fn main() void {
1131 \\ var i = 0;
1132 \\ if (true) |_| {} else |i| {}
1133 \\}
1134 , &[_][]const u8{
1135 ":3:28: error: redeclaration of local variable 'i'",
1136 ":2:9: note: previous declaration here",
1137 });
1068 }1138 }
10691139
1070 {1140 {
test/translate_c.zig+6
...@@ -3624,4 +3624,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3624,4 +3624,10 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3624 ,3624 ,
3625 \\pub export var @"_": c_int = 42;3625 \\pub export var @"_": c_int = 42;
3626 });3626 });
3627
3628 cases.add("Macro matching",
3629 \\#define FOO(X) (X ## U)
3630 , &[_][]const u8{
3631 \\pub const FOO = @import("std").zig.c_translation.Macros.U_SUFFIX;
3632 });
3627}3633}