authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-06-07 13:08:22-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-06-07 13:08:22-04:00
log8b875b17ade95c4e0098c7c3b20134f03745aac3
tree02ee642b33451b453994f484a2204ddca42e4857
parent173bc4274446a14aca2eea128b70b35b0ba18ebe
parent5a52da1b7a8c467087da8f3a20ab902ec8c1e25d
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #24072 from jacobly0/x86_64-default

Compilation: enable the x86_64 backend by default for debug builds

65 files changed, 2280 insertions(+), 1737 deletions(-)

.github/workflows/ci.yaml+8
......@@ -20,6 +20,14 @@ jobs:
2020 uses: actions/checkout@v4
2121 - name: Build and Test
2222 run: sh ci/x86_64-linux-debug.sh
23 x86_64-linux-debug-llvm:
24 timeout-minutes: 540
25 runs-on: [self-hosted, Linux, x86_64]
26 steps:
27 - name: Checkout
28 uses: actions/checkout@v4
29 - name: Build and Test
30 run: sh ci/x86_64-linux-debug-llvm.sh
2331 x86_64-linux-release:
2432 timeout-minutes: 540
2533 runs-on: [self-hosted, Linux, x86_64]
CMakeLists.txt+1-1
......@@ -519,6 +519,7 @@ set(ZIG_STAGE2_SOURCES
519519 src/Air/Legalize.zig
520520 src/Air/Liveness.zig
521521 src/Air/Liveness/Verify.zig
522 src/Air/print.zig
522523 src/Air/types_resolved.zig
523524 src/Builtin.zig
524525 src/Compilation.zig
......@@ -675,7 +676,6 @@ set(ZIG_STAGE2_SOURCES
675676 src/libs/mingw.zig
676677 src/libs/musl.zig
677678 src/mutable_value.zig
678 src/print_air.zig
679679 src/print_env.zig
680680 src/print_targets.zig
681681 src/print_value.zig
build.zig+44-8
......@@ -92,6 +92,12 @@ pub fn build(b: *std.Build) !void {
9292 const skip_single_threaded = b.option(bool, "skip-single-threaded", "Main test suite skips tests that are single-threaded") orelse false;
9393 const skip_translate_c = b.option(bool, "skip-translate-c", "Main test suite skips translate-c tests") orelse false;
9494 const skip_run_translated_c = b.option(bool, "skip-run-translated-c", "Main test suite skips run-translated-c tests") orelse false;
95 const skip_freebsd = b.option(bool, "skip-freebsd", "Main test suite skips targets with freebsd OS") orelse false;
96 const skip_netbsd = b.option(bool, "skip-netbsd", "Main test suite skips targets with netbsd OS") orelse false;
97 const skip_windows = b.option(bool, "skip-windows", "Main test suite skips targets with windows OS") orelse false;
98 const skip_macos = b.option(bool, "skip-macos", "Main test suite skips targets with macos OS") orelse false;
99 const skip_linux = b.option(bool, "skip-linux", "Main test suite skips targets with linux OS") orelse false;
100 const skip_llvm = b.option(bool, "skip-llvm", "Main test suite skips targets that use LLVM backend") orelse false;
95101
96102 const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false;
97103
......@@ -435,10 +441,15 @@ pub fn build(b: *std.Build) !void {
435441 .include_paths = &.{},
436442 .skip_single_threaded = skip_single_threaded,
437443 .skip_non_native = skip_non_native,
444 .skip_freebsd = skip_freebsd,
445 .skip_netbsd = skip_netbsd,
446 .skip_windows = skip_windows,
447 .skip_macos = skip_macos,
448 .skip_linux = skip_linux,
449 .skip_llvm = skip_llvm,
438450 .skip_libc = skip_libc,
439 .use_llvm = use_llvm,
440 // 2520100864 was observed on an x86_64-linux-gnu host.
441 .max_rss = 2772110950,
451 // 2923515904 was observed on an x86_64-linux-gnu host.
452 .max_rss = 3100000000,
442453 }));
443454
444455 test_modules_step.dependOn(tests.addModuleTests(b, .{
......@@ -452,8 +463,13 @@ pub fn build(b: *std.Build) !void {
452463 .include_paths = &.{"test/c_import"},
453464 .skip_single_threaded = true,
454465 .skip_non_native = skip_non_native,
466 .skip_freebsd = skip_freebsd,
467 .skip_netbsd = skip_netbsd,
468 .skip_windows = skip_windows,
469 .skip_macos = skip_macos,
470 .skip_linux = skip_linux,
471 .skip_llvm = skip_llvm,
455472 .skip_libc = skip_libc,
456 .use_llvm = use_llvm,
457473 }));
458474
459475 test_modules_step.dependOn(tests.addModuleTests(b, .{
......@@ -467,8 +483,13 @@ pub fn build(b: *std.Build) !void {
467483 .include_paths = &.{},
468484 .skip_single_threaded = true,
469485 .skip_non_native = skip_non_native,
486 .skip_freebsd = skip_freebsd,
487 .skip_netbsd = skip_netbsd,
488 .skip_windows = skip_windows,
489 .skip_macos = skip_macos,
490 .skip_linux = skip_linux,
491 .skip_llvm = skip_llvm,
470492 .skip_libc = true,
471 .use_llvm = use_llvm,
472493 .no_builtin = true,
473494 }));
474495
......@@ -483,8 +504,13 @@ pub fn build(b: *std.Build) !void {
483504 .include_paths = &.{},
484505 .skip_single_threaded = true,
485506 .skip_non_native = skip_non_native,
507 .skip_freebsd = skip_freebsd,
508 .skip_netbsd = skip_netbsd,
509 .skip_windows = skip_windows,
510 .skip_macos = skip_macos,
511 .skip_linux = skip_linux,
512 .skip_llvm = skip_llvm,
486513 .skip_libc = true,
487 .use_llvm = use_llvm,
488514 .no_builtin = true,
489515 }));
490516
......@@ -499,8 +525,13 @@ pub fn build(b: *std.Build) !void {
499525 .include_paths = &.{},
500526 .skip_single_threaded = skip_single_threaded,
501527 .skip_non_native = skip_non_native,
528 .skip_freebsd = skip_freebsd,
529 .skip_netbsd = skip_netbsd,
530 .skip_windows = skip_windows,
531 .skip_macos = skip_macos,
532 .skip_linux = skip_linux,
533 .skip_llvm = skip_llvm,
502534 .skip_libc = skip_libc,
503 .use_llvm = use_llvm,
504535 // I observed a value of 5605064704 on the M2 CI.
505536 .max_rss = 6165571174,
506537 }));
......@@ -536,6 +567,12 @@ pub fn build(b: *std.Build) !void {
536567 test_step.dependOn(tests.addCAbiTests(b, .{
537568 .test_target_filters = test_target_filters,
538569 .skip_non_native = skip_non_native,
570 .skip_freebsd = skip_freebsd,
571 .skip_netbsd = skip_netbsd,
572 .skip_windows = skip_windows,
573 .skip_macos = skip_macos,
574 .skip_linux = skip_linux,
575 .skip_llvm = skip_llvm,
539576 .skip_release = skip_release,
540577 }));
541578 test_step.dependOn(tests.addLinkTests(b, enable_macos_sdk, enable_ios_sdk, enable_symlinks_windows));
......@@ -549,7 +586,6 @@ pub fn build(b: *std.Build) !void {
549586 .lldb = b.option([]const u8, "lldb", "path to lldb binary"),
550587 .optimize_modes = optimization_modes,
551588 .skip_single_threaded = skip_single_threaded,
552 .skip_non_native = skip_non_native,
553589 .skip_libc = skip_libc,
554590 })) |test_debugger_step| test_step.dependOn(test_debugger_step);
555591 if (tests.addLlvmIrTests(b, .{
ci/x86_64-linux-debug-llvm.sh created+70
......@@ -0,0 +1,70 @@
1#!/bin/sh
2
3# Requires cmake ninja-build
4
5set -x
6set -e
7
8ARCH="$(uname -m)"
9TARGET="$ARCH-linux-musl"
10MCPU="baseline"
11CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.15.0-dev.233+7c85dc460"
12PREFIX="$HOME/deps/$CACHE_BASENAME"
13ZIG="$PREFIX/bin/zig"
14
15export PATH="$HOME/deps/wasmtime-v29.0.0-$ARCH-linux:$HOME/deps/qemu-linux-x86_64-9.2.0-rc1/bin:$HOME/local/bin:$PATH"
16
17# Make the `zig version` number consistent.
18# This will affect the cmake command below.
19git fetch --unshallow || true
20git fetch --tags
21
22# Override the cache directories because they won't actually help other CI runs
23# which will be testing alternate versions of zig, and ultimately would just
24# fill up space on the hard drive for no reason.
25export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache"
26export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
27
28mkdir build-debug-llvm
29cd build-debug-llvm
30
31export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
32export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
33
34cmake .. \
35 -DCMAKE_INSTALL_PREFIX="stage3-debug" \
36 -DCMAKE_PREFIX_PATH="$PREFIX" \
37 -DCMAKE_BUILD_TYPE=Debug \
38 -DZIG_TARGET_TRIPLE="$TARGET" \
39 -DZIG_TARGET_MCPU="$MCPU" \
40 -DZIG_STATIC=ON \
41 -DZIG_NO_LIB=ON \
42 -DZIG_EXTRA_BUILD_ARGS="-Duse-llvm=true" \
43 -GNinja
44
45# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
46# so that installation and testing do not get affected by them.
47unset CC
48unset CXX
49
50ninja install
51
52# simultaneously test building self-hosted without LLVM and with 32-bit arm
53stage3-debug/bin/zig build \
54 -Dtarget=arm-linux-musleabihf \
55 -Dno-lib
56
57stage3-debug/bin/zig build test docs \
58 --maxrss 21000000000 \
59 -Dlldb=$HOME/deps/lldb-zig/Debug-e0a42bb34/bin/lldb \
60 -fqemu \
61 -fwasmtime \
62 -Dstatic-llvm \
63 -Dskip-freebsd \
64 -Dskip-netbsd \
65 -Dskip-windows \
66 -Dskip-macos \
67 -Dtarget=native-native-musl \
68 --search-prefix "$PREFIX" \
69 --zig-lib-dir "$PWD/../lib" \
70 -Denable-superhtml
ci/x86_64-linux-debug.sh+5-38
......@@ -25,12 +25,6 @@ git fetch --tags
2525export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache"
2626export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
2727
28# Test building from source without LLVM.
29cc -o bootstrap bootstrap.c
30./bootstrap
31./zig2 build -Dno-lib
32./zig-out/bin/zig test test/behavior.zig
33
3428mkdir build-debug
3529cd build-debug
3630
......@@ -65,39 +59,12 @@ stage3-debug/bin/zig build test docs \
6559 -fqemu \
6660 -fwasmtime \
6761 -Dstatic-llvm \
62 -Dskip-freebsd \
63 -Dskip-netbsd \
64 -Dskip-windows \
65 -Dskip-macos \
66 -Dskip-llvm \
6867 -Dtarget=native-native-musl \
6968 --search-prefix "$PREFIX" \
7069 --zig-lib-dir "$PWD/../lib" \
7170 -Denable-superhtml
72
73# Ensure that updating the wasm binary from this commit will result in a viable build.
74stage3-debug/bin/zig build update-zig1
75
76mkdir ../build-new
77cd ../build-new
78
79export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
80export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
81
82cmake .. \
83 -DCMAKE_PREFIX_PATH="$PREFIX" \
84 -DCMAKE_BUILD_TYPE=Debug \
85 -DZIG_TARGET_TRIPLE="$TARGET" \
86 -DZIG_TARGET_MCPU="$MCPU" \
87 -DZIG_STATIC=ON \
88 -DZIG_NO_LIB=ON \
89 -GNinja
90
91unset CC
92unset CXX
93
94ninja install
95
96stage3/bin/zig test ../test/behavior.zig
97stage3/bin/zig build -p stage4 \
98 -Dstatic-llvm \
99 -Dtarget=native-native-musl \
100 -Dno-lib \
101 --search-prefix "$PREFIX" \
102 --zig-lib-dir "$PWD/../lib"
103stage4/bin/zig test ../test/behavior.zig
doc/langref/test_global_assembly.zig+1
......@@ -19,3 +19,4 @@ test "global assembly" {
1919
2020// test
2121// target=x86_64-linux
22// llvm=true
lib/std/Target.zig+5-1
......@@ -2581,12 +2581,16 @@ pub fn standardDynamicLinkerPath(target: Target) DynamicLinker {
25812581}
25822582
25832583pub fn ptrBitWidth_cpu_abi(cpu: Cpu, abi: Abi) u16 {
2584 return ptrBitWidth_arch_abi(cpu.arch, abi);
2585}
2586
2587pub fn ptrBitWidth_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) u16 {
25842588 switch (abi) {
25852589 .gnux32, .muslx32, .gnuabin32, .muslabin32, .ilp32 => return 32,
25862590 .gnuabi64, .muslabi64 => return 64,
25872591 else => {},
25882592 }
2589 return switch (cpu.arch) {
2593 return switch (cpu_arch) {
25902594 .avr,
25912595 .msp430,
25922596 => 16,
lib/std/builtin.zig+13-2
......@@ -61,7 +61,7 @@ pub const StackTrace = struct {
6161
6262/// This data structure is used by the Zig language code generation and
6363/// therefore must be kept in sync with the compiler implementation.
64pub const GlobalLinkage = enum {
64pub const GlobalLinkage = enum(u2) {
6565 internal,
6666 strong,
6767 weak,
......@@ -70,7 +70,7 @@ pub const GlobalLinkage = enum {
7070
7171/// This data structure is used by the Zig language code generation and
7272/// therefore must be kept in sync with the compiler implementation.
73pub const SymbolVisibility = enum {
73pub const SymbolVisibility = enum(u2) {
7474 default,
7575 hidden,
7676 protected,
......@@ -1030,8 +1030,19 @@ pub const ExternOptions = struct {
10301030 name: []const u8,
10311031 library_name: ?[]const u8 = null,
10321032 linkage: GlobalLinkage = .strong,
1033 visibility: SymbolVisibility = .default,
1034 /// Setting this to `true` makes the `@extern` a runtime value.
10331035 is_thread_local: bool = false,
10341036 is_dll_import: bool = false,
1037 relocation: Relocation = .any,
1038
1039 pub const Relocation = enum(u1) {
1040 /// Any type of relocation is allowed.
1041 any,
1042 /// A program-counter-relative relocation is required.
1043 /// Using this value makes the `@extern` a runtime value.
1044 pcrel,
1045 };
10351046};
10361047
10371048/// This data structure is used by the Zig language code generation and
lib/std/dynamic_library.zig+8-5
......@@ -83,13 +83,16 @@ const RDebug = extern struct {
8383 r_ldbase: usize,
8484};
8585
86/// TODO make it possible to reference this same external symbol 2x so we don't need this
87/// helper function.
88pub fn get_DYNAMIC() ?[*]elf.Dyn {
89 return @extern([*]elf.Dyn, .{ .name = "_DYNAMIC", .linkage = .weak });
86/// TODO fix comparisons of extern symbol pointers so we don't need this helper function.
87pub fn get_DYNAMIC() ?[*]const elf.Dyn {
88 return @extern([*]const elf.Dyn, .{
89 .name = "_DYNAMIC",
90 .linkage = .weak,
91 .visibility = .hidden,
92 });
9093}
9194
92pub fn linkmap_iterator(phdrs: []elf.Phdr) error{InvalidExe}!LinkMap.Iterator {
95pub fn linkmap_iterator(phdrs: []const elf.Phdr) error{InvalidExe}!LinkMap.Iterator {
9396 _ = phdrs;
9497 const _DYNAMIC = get_DYNAMIC() orelse {
9598 // No PT_DYNAMIC means this is either a statically-linked program or a
lib/std/pie.zig+174-169
......@@ -39,167 +39,175 @@ const R_RELATIVE = switch (builtin.cpu.arch) {
3939// Obtain a pointer to the _DYNAMIC array.
4040// We have to compute its address as a PC-relative quantity not to require a
4141// relocation that, at this point, is not yet applied.
42inline fn getDynamicSymbol() [*]elf.Dyn {
43 return switch (builtin.cpu.arch) {
44 .x86 => asm volatile (
45 \\ .weak _DYNAMIC
46 \\ .hidden _DYNAMIC
47 \\ call 1f
48 \\ 1: pop %[ret]
49 \\ lea _DYNAMIC-1b(%[ret]), %[ret]
50 : [ret] "=r" (-> [*]elf.Dyn),
51 ),
52 .x86_64 => asm volatile (
53 \\ .weak _DYNAMIC
54 \\ .hidden _DYNAMIC
55 \\ lea _DYNAMIC(%%rip), %[ret]
56 : [ret] "=r" (-> [*]elf.Dyn),
57 ),
58 .arc => asm volatile (
59 \\ .weak _DYNAMIC
60 \\ .hidden _DYNAMIC
61 \\ add %[ret], pcl, _DYNAMIC@pcl
62 : [ret] "=r" (-> [*]elf.Dyn),
63 ),
64 // Work around the limited offset range of `ldr`
65 .arm, .armeb, .thumb, .thumbeb => asm volatile (
66 \\ .weak _DYNAMIC
67 \\ .hidden _DYNAMIC
68 \\ ldr %[ret], 1f
69 \\ add %[ret], pc
70 \\ b 2f
71 \\ 1: .word _DYNAMIC-1b
72 \\ 2:
73 : [ret] "=r" (-> [*]elf.Dyn),
74 ),
75 // A simple `adr` is not enough as it has a limited offset range
76 .aarch64, .aarch64_be => asm volatile (
77 \\ .weak _DYNAMIC
78 \\ .hidden _DYNAMIC
79 \\ adrp %[ret], _DYNAMIC
80 \\ add %[ret], %[ret], #:lo12:_DYNAMIC
81 : [ret] "=r" (-> [*]elf.Dyn),
82 ),
83 // The CSKY ABI requires the gb register to point to the GOT. Additionally, the first
84 // entry in the GOT is defined to hold the address of _DYNAMIC.
85 .csky => asm volatile (
86 \\ mov %[ret], gb
87 \\ ldw %[ret], %[ret]
88 : [ret] "=r" (-> [*]elf.Dyn),
89 ),
90 .hexagon => asm volatile (
91 \\ .weak _DYNAMIC
92 \\ .hidden _DYNAMIC
93 \\ jump 1f
94 \\ .word _DYNAMIC - .
95 \\ 1:
96 \\ r1 = pc
97 \\ r1 = add(r1, #-4)
98 \\ %[ret] = memw(r1)
99 \\ %[ret] = add(r1, %[ret])
100 : [ret] "=r" (-> [*]elf.Dyn),
101 :
102 : "r1"
103 ),
104 .loongarch32, .loongarch64 => asm volatile (
105 \\ .weak _DYNAMIC
106 \\ .hidden _DYNAMIC
107 \\ la.local %[ret], _DYNAMIC
108 : [ret] "=r" (-> [*]elf.Dyn),
109 ),
110 // Note that the - 8 is needed because pc in the second lea instruction points into the
111 // middle of that instruction. (The first lea is 6 bytes, the second is 4 bytes.)
112 .m68k => asm volatile (
113 \\ .weak _DYNAMIC
114 \\ .hidden _DYNAMIC
115 \\ lea _DYNAMIC - . - 8, %[ret]
116 \\ lea (%[ret], %%pc), %[ret]
117 : [ret] "=r" (-> [*]elf.Dyn),
118 ),
119 .mips, .mipsel => asm volatile (
120 \\ .weak _DYNAMIC
121 \\ .hidden _DYNAMIC
122 \\ bal 1f
123 \\ .gpword _DYNAMIC
124 \\ 1:
125 \\ lw %[ret], 0($ra)
126 \\ addu %[ret], %[ret], $gp
127 : [ret] "=r" (-> [*]elf.Dyn),
128 :
129 : "lr"
130 ),
131 .mips64, .mips64el => asm volatile (
132 \\ .weak _DYNAMIC
133 \\ .hidden _DYNAMIC
134 \\ .balign 8
135 \\ bal 1f
136 \\ .gpdword _DYNAMIC
137 \\ 1:
138 \\ ld %[ret], 0($ra)
139 \\ daddu %[ret], %[ret], $gp
140 : [ret] "=r" (-> [*]elf.Dyn),
141 :
142 : "lr"
143 ),
144 .powerpc, .powerpcle => asm volatile (
145 \\ .weak _DYNAMIC
146 \\ .hidden _DYNAMIC
147 \\ bl 1f
148 \\ .long _DYNAMIC - .
149 \\ 1:
150 \\ mflr %[ret]
151 \\ lwz 4, 0(%[ret])
152 \\ add %[ret], 4, %[ret]
153 : [ret] "=r" (-> [*]elf.Dyn),
154 :
155 : "lr", "r4"
156 ),
157 .powerpc64, .powerpc64le => asm volatile (
158 \\ .weak _DYNAMIC
159 \\ .hidden _DYNAMIC
160 \\ bl 1f
161 \\ .quad _DYNAMIC - .
162 \\ 1:
163 \\ mflr %[ret]
164 \\ ld 4, 0(%[ret])
165 \\ add %[ret], 4, %[ret]
166 : [ret] "=r" (-> [*]elf.Dyn),
167 :
168 : "lr", "r4"
169 ),
170 .riscv32, .riscv64 => asm volatile (
171 \\ .weak _DYNAMIC
172 \\ .hidden _DYNAMIC
173 \\ lla %[ret], _DYNAMIC
174 : [ret] "=r" (-> [*]elf.Dyn),
175 ),
176 .s390x => asm volatile (
177 \\ .weak _DYNAMIC
178 \\ .hidden _DYNAMIC
179 \\ larl %[ret], 1f
180 \\ ag %[ret], 0(%[ret])
181 \\ jg 2f
182 \\ 1: .quad _DYNAMIC - .
183 \\ 2:
184 : [ret] "=r" (-> [*]elf.Dyn),
185 ),
186 // The compiler does not necessarily have any obligation to load the `l7` register (pointing
187 // to the GOT), so do it ourselves just in case.
188 .sparc, .sparc64 => asm volatile (
189 \\ sethi %%hi(_GLOBAL_OFFSET_TABLE_ - 4), %%l7
190 \\ call 1f
191 \\ add %%l7, %%lo(_GLOBAL_OFFSET_TABLE_ + 4), %%l7
192 \\ 1:
193 \\ add %%l7, %%o7, %[ret]
194 : [ret] "=r" (-> [*]elf.Dyn),
195 ),
196 else => {
197 @compileError("PIE startup is not yet supported for this target!");
42inline fn getDynamicSymbol() [*]const elf.Dyn {
43 return switch (builtin.zig_backend) {
44 else => switch (builtin.cpu.arch) {
45 .x86 => asm volatile (
46 \\ .weak _DYNAMIC
47 \\ .hidden _DYNAMIC
48 \\ call 1f
49 \\ 1: pop %[ret]
50 \\ lea _DYNAMIC-1b(%[ret]), %[ret]
51 : [ret] "=r" (-> [*]const elf.Dyn),
52 ),
53 .x86_64 => asm volatile (
54 \\ .weak _DYNAMIC
55 \\ .hidden _DYNAMIC
56 \\ lea _DYNAMIC(%%rip), %[ret]
57 : [ret] "=r" (-> [*]const elf.Dyn),
58 ),
59 .arc => asm volatile (
60 \\ .weak _DYNAMIC
61 \\ .hidden _DYNAMIC
62 \\ add %[ret], pcl, _DYNAMIC@pcl
63 : [ret] "=r" (-> [*]const elf.Dyn),
64 ),
65 // Work around the limited offset range of `ldr`
66 .arm, .armeb, .thumb, .thumbeb => asm volatile (
67 \\ .weak _DYNAMIC
68 \\ .hidden _DYNAMIC
69 \\ ldr %[ret], 1f
70 \\ add %[ret], pc
71 \\ b 2f
72 \\ 1: .word _DYNAMIC-1b
73 \\ 2:
74 : [ret] "=r" (-> [*]const elf.Dyn),
75 ),
76 // A simple `adr` is not enough as it has a limited offset range
77 .aarch64, .aarch64_be => asm volatile (
78 \\ .weak _DYNAMIC
79 \\ .hidden _DYNAMIC
80 \\ adrp %[ret], _DYNAMIC
81 \\ add %[ret], %[ret], #:lo12:_DYNAMIC
82 : [ret] "=r" (-> [*]const elf.Dyn),
83 ),
84 // The CSKY ABI requires the gb register to point to the GOT. Additionally, the first
85 // entry in the GOT is defined to hold the address of _DYNAMIC.
86 .csky => asm volatile (
87 \\ mov %[ret], gb
88 \\ ldw %[ret], %[ret]
89 : [ret] "=r" (-> [*]const elf.Dyn),
90 ),
91 .hexagon => asm volatile (
92 \\ .weak _DYNAMIC
93 \\ .hidden _DYNAMIC
94 \\ jump 1f
95 \\ .word _DYNAMIC - .
96 \\ 1:
97 \\ r1 = pc
98 \\ r1 = add(r1, #-4)
99 \\ %[ret] = memw(r1)
100 \\ %[ret] = add(r1, %[ret])
101 : [ret] "=r" (-> [*]const elf.Dyn),
102 :
103 : "r1"
104 ),
105 .loongarch32, .loongarch64 => asm volatile (
106 \\ .weak _DYNAMIC
107 \\ .hidden _DYNAMIC
108 \\ la.local %[ret], _DYNAMIC
109 : [ret] "=r" (-> [*]const elf.Dyn),
110 ),
111 // Note that the - 8 is needed because pc in the second lea instruction points into the
112 // middle of that instruction. (The first lea is 6 bytes, the second is 4 bytes.)
113 .m68k => asm volatile (
114 \\ .weak _DYNAMIC
115 \\ .hidden _DYNAMIC
116 \\ lea _DYNAMIC - . - 8, %[ret]
117 \\ lea (%[ret], %%pc), %[ret]
118 : [ret] "=r" (-> [*]const elf.Dyn),
119 ),
120 .mips, .mipsel => asm volatile (
121 \\ .weak _DYNAMIC
122 \\ .hidden _DYNAMIC
123 \\ bal 1f
124 \\ .gpword _DYNAMIC
125 \\ 1:
126 \\ lw %[ret], 0($ra)
127 \\ addu %[ret], %[ret], $gp
128 : [ret] "=r" (-> [*]const elf.Dyn),
129 :
130 : "lr"
131 ),
132 .mips64, .mips64el => asm volatile (
133 \\ .weak _DYNAMIC
134 \\ .hidden _DYNAMIC
135 \\ .balign 8
136 \\ bal 1f
137 \\ .gpdword _DYNAMIC
138 \\ 1:
139 \\ ld %[ret], 0($ra)
140 \\ daddu %[ret], %[ret], $gp
141 : [ret] "=r" (-> [*]const elf.Dyn),
142 :
143 : "lr"
144 ),
145 .powerpc, .powerpcle => asm volatile (
146 \\ .weak _DYNAMIC
147 \\ .hidden _DYNAMIC
148 \\ bl 1f
149 \\ .long _DYNAMIC - .
150 \\ 1:
151 \\ mflr %[ret]
152 \\ lwz 4, 0(%[ret])
153 \\ add %[ret], 4, %[ret]
154 : [ret] "=r" (-> [*]const elf.Dyn),
155 :
156 : "lr", "r4"
157 ),
158 .powerpc64, .powerpc64le => asm volatile (
159 \\ .weak _DYNAMIC
160 \\ .hidden _DYNAMIC
161 \\ bl 1f
162 \\ .quad _DYNAMIC - .
163 \\ 1:
164 \\ mflr %[ret]
165 \\ ld 4, 0(%[ret])
166 \\ add %[ret], 4, %[ret]
167 : [ret] "=r" (-> [*]const elf.Dyn),
168 :
169 : "lr", "r4"
170 ),
171 .riscv32, .riscv64 => asm volatile (
172 \\ .weak _DYNAMIC
173 \\ .hidden _DYNAMIC
174 \\ lla %[ret], _DYNAMIC
175 : [ret] "=r" (-> [*]const elf.Dyn),
176 ),
177 .s390x => asm volatile (
178 \\ .weak _DYNAMIC
179 \\ .hidden _DYNAMIC
180 \\ larl %[ret], 1f
181 \\ ag %[ret], 0(%[ret])
182 \\ jg 2f
183 \\ 1: .quad _DYNAMIC - .
184 \\ 2:
185 : [ret] "=r" (-> [*]const elf.Dyn),
186 ),
187 // The compiler does not necessarily have any obligation to load the `l7` register (pointing
188 // to the GOT), so do it ourselves just in case.
189 .sparc, .sparc64 => asm volatile (
190 \\ sethi %%hi(_GLOBAL_OFFSET_TABLE_ - 4), %%l7
191 \\ call 1f
192 \\ add %%l7, %%lo(_GLOBAL_OFFSET_TABLE_ + 4), %%l7
193 \\ 1:
194 \\ add %%l7, %%o7, %[ret]
195 : [ret] "=r" (-> [*]const elf.Dyn),
196 ),
197 else => {
198 @compileError("PIE startup is not yet supported for this target!");
199 },
198200 },
201 .stage2_x86_64 => @extern([*]const elf.Dyn, .{
202 .name = "_DYNAMIC",
203 .linkage = .weak,
204 .visibility = .hidden,
205 .relocation = .pcrel,
206 }).?,
199207 };
200208}
201209
202pub fn relocate(phdrs: []elf.Phdr) void {
210pub fn relocate(phdrs: []const elf.Phdr) void {
203211 @setRuntimeSafety(false);
204212 @disableInstrumentation();
205213
......@@ -256,10 +264,9 @@ pub fn relocate(phdrs: []elf.Phdr) void {
256264
257265 const rel = sorted_dynv[elf.DT_REL];
258266 if (rel != 0) {
259 const rels = @call(.always_inline, std.mem.bytesAsSlice, .{
260 elf.Rel,
261 @as([*]u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]],
262 });
267 const rels: []const elf.Rel = @alignCast(@ptrCast(
268 @as([*]align(@alignOf(elf.Rel)) const u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]],
269 ));
263270 for (rels) |r| {
264271 if (r.r_type() != R_RELATIVE) continue;
265272 @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr;
......@@ -268,10 +275,9 @@ pub fn relocate(phdrs: []elf.Phdr) void {
268275
269276 const rela = sorted_dynv[elf.DT_RELA];
270277 if (rela != 0) {
271 const relas = @call(.always_inline, std.mem.bytesAsSlice, .{
272 elf.Rela,
273 @as([*]u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]],
274 });
278 const relas: []const elf.Rela = @alignCast(@ptrCast(
279 @as([*]align(@alignOf(elf.Rela)) const u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]],
280 ));
275281 for (relas) |r| {
276282 if (r.r_type() != R_RELATIVE) continue;
277283 @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* = base_addr + @as(usize, @bitCast(r.r_addend));
......@@ -280,10 +286,9 @@ pub fn relocate(phdrs: []elf.Phdr) void {
280286
281287 const relr = sorted_dynv[elf.DT_RELR];
282288 if (relr != 0) {
283 const relrs = @call(.always_inline, std.mem.bytesAsSlice, .{
284 elf.Relr,
285 @as([*]u8, @ptrFromInt(base_addr + relr))[0..sorted_dynv[elf.DT_RELRSZ]],
286 });
289 const relrs: []const elf.Relr = @ptrCast(
290 @as([*]align(@alignOf(elf.Relr)) const u8, @ptrFromInt(base_addr + relr))[0..sorted_dynv[elf.DT_RELRSZ]],
291 );
287292 var current: [*]usize = undefined;
288293 for (relrs) |r| {
289294 if ((r & 1) == 0) {
lib/std/start.zig+6-6
......@@ -163,7 +163,7 @@ fn exit2(code: usize) noreturn {
163163 // exits(0)
164164 .plan9 => std.os.plan9.exits(null),
165165 .windows => {
166 std.os.windows.ntdll.RtlExitUserProcess(@as(u32, @truncate(code)));
166 std.os.windows.ntdll.RtlExitUserProcess(@truncate(code));
167167 },
168168 else => @compileError("TODO"),
169169 }
......@@ -511,7 +511,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
511511 // Code coverage instrumentation might try to use thread local variables.
512512 @disableInstrumentation();
513513 const argc = argc_argv_ptr[0];
514 const argv = @as([*][*:0]u8, @ptrCast(argc_argv_ptr + 1));
514 const argv: [*][*:0]u8 = @ptrCast(argc_argv_ptr + 1);
515515
516516 const envp_optional: [*:null]?[*:0]u8 = @ptrCast(@alignCast(argv + argc + 1));
517517 var envp_count: usize = 0;
......@@ -573,11 +573,11 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
573573 expandStackSize(phdrs);
574574 }
575575
576 const opt_init_array_start = @extern([*]*const fn () callconv(.c) void, .{
576 const opt_init_array_start = @extern([*]const *const fn () callconv(.c) void, .{
577577 .name = "__init_array_start",
578578 .linkage = .weak,
579579 });
580 const opt_init_array_end = @extern([*]*const fn () callconv(.c) void, .{
580 const opt_init_array_end = @extern([*]const *const fn () callconv(.c) void, .{
581581 .name = "__init_array_end",
582582 .linkage = .weak,
583583 });
......@@ -651,7 +651,7 @@ fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) cal
651651}
652652
653653fn mainWithoutEnv(c_argc: c_int, c_argv: [*][*:0]c_char) callconv(.c) c_int {
654 std.os.argv = @as([*][*:0]u8, @ptrCast(c_argv))[0..@as(usize, @intCast(c_argc))];
654 std.os.argv = @as([*][*:0]u8, @ptrCast(c_argv))[0..@intCast(c_argc)];
655655 return callMain();
656656}
657657
......@@ -701,7 +701,7 @@ pub inline fn callMain() u8 {
701701pub fn call_wWinMain() std.os.windows.INT {
702702 const peb = std.os.windows.peb();
703703 const MAIN_HINSTANCE = @typeInfo(@TypeOf(root.wWinMain)).@"fn".params[0].type.?;
704 const hInstance = @as(MAIN_HINSTANCE, @ptrCast(peb.ImageBaseAddress));
704 const hInstance: MAIN_HINSTANCE = @ptrCast(peb.ImageBaseAddress);
705705 const lpCmdLine: [*:0]u16 = @ptrCast(peb.ProcessParameters.CommandLine.Buffer);
706706
707707 // There are various types used for the 'show window' variable through the Win32 APIs:
lib/std/zig/llvm/Builder.zig+12
......@@ -1823,6 +1823,14 @@ pub const Visibility = enum(u2) {
18231823 hidden = 1,
18241824 protected = 2,
18251825
1826 pub fn fromSymbolVisibility(sv: std.builtin.SymbolVisibility) Visibility {
1827 return switch (sv) {
1828 .default => .default,
1829 .hidden => .hidden,
1830 .protected => .protected,
1831 };
1832 }
1833
18261834 pub fn format(
18271835 self: Visibility,
18281836 comptime _: []const u8,
......@@ -2555,6 +2563,10 @@ pub const Variable = struct {
25552563 return self.ptrConst(builder).global.setLinkage(linkage, builder);
25562564 }
25572565
2566 pub fn setVisibility(self: Index, visibility: Visibility, builder: *Builder) void {
2567 return self.ptrConst(builder).global.setVisibility(visibility, builder);
2568 }
2569
25582570 pub fn setDllStorageClass(self: Index, class: DllStorageClass, builder: *Builder) void {
25592571 return self.ptrConst(builder).global.setDllStorageClass(class, builder);
25602572 }
lib/zig.h+9
......@@ -272,6 +272,15 @@
272272#define zig_linksection_fn zig_linksection
273273#endif
274274
275#if zig_has_attribute(visibility)
276#define zig_visibility(name) __attribute__((visibility(#name)))
277#else
278#define zig_visibility(name) zig_visibility_##name
279#define zig_visibility_default
280#define zig_visibility_hidden zig_visibility_hidden_unavailable
281#define zig_visibility_protected zig_visibility_protected_unavailable
282#endif
283
275284#if zig_has_builtin(unreachable) || defined(zig_gcc) || defined(zig_tinyc)
276285#define zig_unreachable() __builtin_unreachable()
277286#elif defined(zig_msvc)
src/Air.zig+10-4
......@@ -13,6 +13,7 @@ const InternPool = @import("InternPool.zig");
1313const Type = @import("Type.zig");
1414const Value = @import("Value.zig");
1515const Zcu = @import("Zcu.zig");
16const print = @import("Air/print.zig");
1617const types_resolved = @import("Air/types_resolved.zig");
1718
1819pub const Legalize = @import("Air/Legalize.zig");
......@@ -863,16 +864,17 @@ pub const Inst = struct {
863864 /// Uses the `vector_store_elem` field.
864865 vector_store_elem,
865866
866 /// Compute a pointer to a threadlocal or dllimport `Nav`, meaning one of:
867 /// Compute a pointer to a `Nav` at runtime, always one of:
867868 ///
868869 /// * `threadlocal var`
869870 /// * `extern threadlocal var` (or corresponding `@extern`)
870871 /// * `@extern` with `.is_dll_import = true`
872 /// * `@extern` with `.relocation = .pcrel`
871873 ///
872874 /// Such pointers are runtime values, so cannot be represented with an InternPool index.
873875 ///
874876 /// Uses the `ty_nav` field.
875 tlv_dllimport_ptr,
877 runtime_nav_ptr,
876878
877879 /// Implements @cVaArg builtin.
878880 /// Uses the `ty_op` field.
......@@ -1708,7 +1710,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
17081710 return .fromInterned(ip.indexToKey(err_union_ty.ip_index).error_union_type.payload_type);
17091711 },
17101712
1711 .tlv_dllimport_ptr => return .fromInterned(datas[@intFromEnum(inst)].ty_nav.ty),
1713 .runtime_nav_ptr => return .fromInterned(datas[@intFromEnum(inst)].ty_nav.ty),
17121714
17131715 .work_item_id,
17141716 .work_group_size,
......@@ -1983,7 +1985,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
19831985 .err_return_trace,
19841986 .addrspace_cast,
19851987 .save_err_return_trace_index,
1986 .tlv_dllimport_ptr,
1988 .runtime_nav_ptr,
19871989 .work_item_id,
19881990 .work_group_size,
19891991 .work_group_id,
......@@ -2141,6 +2143,10 @@ pub const typesFullyResolved = types_resolved.typesFullyResolved;
21412143pub const typeFullyResolved = types_resolved.checkType;
21422144pub const valFullyResolved = types_resolved.checkVal;
21432145pub const legalize = Legalize.legalize;
2146pub const write = print.write;
2147pub const writeInst = print.writeInst;
2148pub const dump = print.dump;
2149pub const dumpInst = print.dumpInst;
21442150
21452151pub const CoveragePoint = enum(u1) {
21462152 /// Indicates the block is not a place of interest corresponding to
src/Air/Legalize.zig+1-1
......@@ -622,7 +622,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
622622 .addrspace_cast,
623623 .save_err_return_trace_index,
624624 .vector_store_elem,
625 .tlv_dllimport_ptr,
625 .runtime_nav_ptr,
626626 .c_va_arg,
627627 .c_va_copy,
628628 .c_va_end,
src/Air/Liveness.zig+2-2
......@@ -339,7 +339,7 @@ pub fn categorizeOperand(
339339 .wasm_memory_size,
340340 .err_return_trace,
341341 .save_err_return_trace_index,
342 .tlv_dllimport_ptr,
342 .runtime_nav_ptr,
343343 .c_va_start,
344344 .work_item_id,
345345 .work_group_size,
......@@ -972,7 +972,7 @@ fn analyzeInst(
972972 .wasm_memory_size,
973973 .err_return_trace,
974974 .save_err_return_trace_index,
975 .tlv_dllimport_ptr,
975 .runtime_nav_ptr,
976976 .c_va_start,
977977 .work_item_id,
978978 .work_group_size,
src/Air/Liveness/Verify.zig+1-1
......@@ -63,7 +63,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
6363 .wasm_memory_size,
6464 .err_return_trace,
6565 .save_err_return_trace_index,
66 .tlv_dllimport_ptr,
66 .runtime_nav_ptr,
6767 .c_va_start,
6868 .work_item_id,
6969 .work_group_size,
src/Air/print.zig created+1041
......@@ -0,0 +1,1041 @@
1const std = @import("std");
2const Allocator = std.mem.Allocator;
3const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
4
5const build_options = @import("build_options");
6const Zcu = @import("../Zcu.zig");
7const Value = @import("../Value.zig");
8const Type = @import("../Type.zig");
9const Air = @import("../Air.zig");
10const InternPool = @import("../InternPool.zig");
11
12pub fn write(air: Air, stream: anytype, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
13 comptime std.debug.assert(build_options.enable_debug_extensions);
14 const instruction_bytes = air.instructions.len *
15 // Here we don't use @sizeOf(Air.Inst.Data) because it would include
16 // the debug safety tag but we want to measure release size.
17 (@sizeOf(Air.Inst.Tag) + 8);
18 const extra_bytes = air.extra.items.len * @sizeOf(u32);
19 const tomb_bytes = if (liveness) |l| l.tomb_bits.len * @sizeOf(usize) else 0;
20 const liveness_extra_bytes = if (liveness) |l| l.extra.len * @sizeOf(u32) else 0;
21 const liveness_special_bytes = if (liveness) |l| l.special.count() * 8 else 0;
22 const total_bytes = @sizeOf(Air) + instruction_bytes + extra_bytes +
23 @sizeOf(Air.Liveness) + liveness_extra_bytes +
24 liveness_special_bytes + tomb_bytes;
25
26 // zig fmt: off
27 stream.print(
28 \\# Total AIR+Liveness bytes: {}
29 \\# AIR Instructions: {d} ({})
30 \\# AIR Extra Data: {d} ({})
31 \\# Liveness tomb_bits: {}
32 \\# Liveness Extra Data: {d} ({})
33 \\# Liveness special table: {d} ({})
34 \\
35 , .{
36 fmtIntSizeBin(total_bytes),
37 air.instructions.len, fmtIntSizeBin(instruction_bytes),
38 air.extra.items.len, fmtIntSizeBin(extra_bytes),
39 fmtIntSizeBin(tomb_bytes),
40 if (liveness) |l| l.extra.len else 0, fmtIntSizeBin(liveness_extra_bytes),
41 if (liveness) |l| l.special.count() else 0, fmtIntSizeBin(liveness_special_bytes),
42 }) catch return;
43 // zig fmt: on
44
45 var writer: Writer = .{
46 .pt = pt,
47 .gpa = pt.zcu.gpa,
48 .air = air,
49 .liveness = liveness,
50 .indent = 2,
51 .skip_body = false,
52 };
53 writer.writeBody(stream, air.getMainBody()) catch return;
54}
55
56pub fn writeInst(
57 air: Air,
58 stream: anytype,
59 inst: Air.Inst.Index,
60 pt: Zcu.PerThread,
61 liveness: ?Air.Liveness,
62) void {
63 comptime std.debug.assert(build_options.enable_debug_extensions);
64 var writer: Writer = .{
65 .pt = pt,
66 .gpa = pt.zcu.gpa,
67 .air = air,
68 .liveness = liveness,
69 .indent = 2,
70 .skip_body = true,
71 };
72 writer.writeInst(stream, inst) catch return;
73}
74
75pub fn dump(air: Air, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
76 air.write(std.io.getStdErr().writer(), pt, liveness);
77}
78
79pub fn dumpInst(air: Air, inst: Air.Inst.Index, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
80 air.writeInst(std.io.getStdErr().writer(), inst, pt, liveness);
81}
82
83const Writer = struct {
84 pt: Zcu.PerThread,
85 gpa: Allocator,
86 air: Air,
87 liveness: ?Air.Liveness,
88 indent: usize,
89 skip_body: bool,
90
91 fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void {
92 for (body) |inst| {
93 try w.writeInst(s, inst);
94 try s.writeByte('\n');
95 }
96 }
97
98 fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
99 const tag = w.air.instructions.items(.tag)[@intFromEnum(inst)];
100 try s.writeByteNTimes(' ', w.indent);
101 try s.print("{}{c}= {s}(", .{
102 inst,
103 @as(u8, if (if (w.liveness) |liveness| liveness.isUnused(inst) else false) '!' else ' '),
104 @tagName(tag),
105 });
106 switch (tag) {
107 .add,
108 .add_optimized,
109 .add_safe,
110 .add_wrap,
111 .add_sat,
112 .sub,
113 .sub_optimized,
114 .sub_safe,
115 .sub_wrap,
116 .sub_sat,
117 .mul,
118 .mul_optimized,
119 .mul_safe,
120 .mul_wrap,
121 .mul_sat,
122 .div_float,
123 .div_trunc,
124 .div_floor,
125 .div_exact,
126 .rem,
127 .mod,
128 .bit_and,
129 .bit_or,
130 .xor,
131 .cmp_lt,
132 .cmp_lte,
133 .cmp_eq,
134 .cmp_gte,
135 .cmp_gt,
136 .cmp_neq,
137 .bool_and,
138 .bool_or,
139 .store,
140 .store_safe,
141 .array_elem_val,
142 .slice_elem_val,
143 .ptr_elem_val,
144 .shl,
145 .shl_exact,
146 .shl_sat,
147 .shr,
148 .shr_exact,
149 .set_union_tag,
150 .min,
151 .max,
152 .div_float_optimized,
153 .div_trunc_optimized,
154 .div_floor_optimized,
155 .div_exact_optimized,
156 .rem_optimized,
157 .mod_optimized,
158 .cmp_lt_optimized,
159 .cmp_lte_optimized,
160 .cmp_eq_optimized,
161 .cmp_gte_optimized,
162 .cmp_gt_optimized,
163 .cmp_neq_optimized,
164 .memcpy,
165 .memmove,
166 .memset,
167 .memset_safe,
168 => try w.writeBinOp(s, inst),
169
170 .is_null,
171 .is_non_null,
172 .is_null_ptr,
173 .is_non_null_ptr,
174 .is_err,
175 .is_non_err,
176 .is_err_ptr,
177 .is_non_err_ptr,
178 .ret,
179 .ret_safe,
180 .ret_load,
181 .is_named_enum_value,
182 .tag_name,
183 .error_name,
184 .sqrt,
185 .sin,
186 .cos,
187 .tan,
188 .exp,
189 .exp2,
190 .log,
191 .log2,
192 .log10,
193 .floor,
194 .ceil,
195 .round,
196 .trunc_float,
197 .neg,
198 .neg_optimized,
199 .cmp_lt_errors_len,
200 .set_err_return_trace,
201 .c_va_end,
202 => try w.writeUnOp(s, inst),
203
204 .trap,
205 .breakpoint,
206 .dbg_empty_stmt,
207 .unreach,
208 .ret_addr,
209 .frame_addr,
210 .save_err_return_trace_index,
211 => try w.writeNoOp(s, inst),
212
213 .alloc,
214 .ret_ptr,
215 .err_return_trace,
216 .c_va_start,
217 => try w.writeTy(s, inst),
218
219 .arg => try w.writeArg(s, inst),
220
221 .not,
222 .bitcast,
223 .load,
224 .fptrunc,
225 .fpext,
226 .intcast,
227 .intcast_safe,
228 .trunc,
229 .optional_payload,
230 .optional_payload_ptr,
231 .optional_payload_ptr_set,
232 .errunion_payload_ptr_set,
233 .wrap_optional,
234 .unwrap_errunion_payload,
235 .unwrap_errunion_err,
236 .unwrap_errunion_payload_ptr,
237 .unwrap_errunion_err_ptr,
238 .wrap_errunion_payload,
239 .wrap_errunion_err,
240 .slice_ptr,
241 .slice_len,
242 .ptr_slice_len_ptr,
243 .ptr_slice_ptr_ptr,
244 .struct_field_ptr_index_0,
245 .struct_field_ptr_index_1,
246 .struct_field_ptr_index_2,
247 .struct_field_ptr_index_3,
248 .array_to_slice,
249 .float_from_int,
250 .splat,
251 .int_from_float,
252 .int_from_float_optimized,
253 .get_union_tag,
254 .clz,
255 .ctz,
256 .popcount,
257 .byte_swap,
258 .bit_reverse,
259 .abs,
260 .error_set_has_value,
261 .addrspace_cast,
262 .c_va_arg,
263 .c_va_copy,
264 => try w.writeTyOp(s, inst),
265
266 .block, .dbg_inline_block => try w.writeBlock(s, tag, inst),
267
268 .loop => try w.writeLoop(s, inst),
269
270 .slice,
271 .slice_elem_ptr,
272 .ptr_elem_ptr,
273 .ptr_add,
274 .ptr_sub,
275 .add_with_overflow,
276 .sub_with_overflow,
277 .mul_with_overflow,
278 .shl_with_overflow,
279 => try w.writeTyPlBin(s, inst),
280
281 .call,
282 .call_always_tail,
283 .call_never_tail,
284 .call_never_inline,
285 => try w.writeCall(s, inst),
286
287 .dbg_var_ptr,
288 .dbg_var_val,
289 .dbg_arg_inline,
290 => try w.writeDbgVar(s, inst),
291
292 .struct_field_ptr => try w.writeStructField(s, inst),
293 .struct_field_val => try w.writeStructField(s, inst),
294 .inferred_alloc => @panic("TODO"),
295 .inferred_alloc_comptime => @panic("TODO"),
296 .assembly => try w.writeAssembly(s, inst),
297 .dbg_stmt => try w.writeDbgStmt(s, inst),
298
299 .aggregate_init => try w.writeAggregateInit(s, inst),
300 .union_init => try w.writeUnionInit(s, inst),
301 .br => try w.writeBr(s, inst),
302 .switch_dispatch => try w.writeBr(s, inst),
303 .repeat => try w.writeRepeat(s, inst),
304 .cond_br => try w.writeCondBr(s, inst),
305 .@"try", .try_cold => try w.writeTry(s, inst),
306 .try_ptr, .try_ptr_cold => try w.writeTryPtr(s, inst),
307 .loop_switch_br, .switch_br => try w.writeSwitchBr(s, inst),
308 .cmpxchg_weak, .cmpxchg_strong => try w.writeCmpxchg(s, inst),
309 .atomic_load => try w.writeAtomicLoad(s, inst),
310 .prefetch => try w.writePrefetch(s, inst),
311 .atomic_store_unordered => try w.writeAtomicStore(s, inst, .unordered),
312 .atomic_store_monotonic => try w.writeAtomicStore(s, inst, .monotonic),
313 .atomic_store_release => try w.writeAtomicStore(s, inst, .release),
314 .atomic_store_seq_cst => try w.writeAtomicStore(s, inst, .seq_cst),
315 .atomic_rmw => try w.writeAtomicRmw(s, inst),
316 .field_parent_ptr => try w.writeFieldParentPtr(s, inst),
317 .wasm_memory_size => try w.writeWasmMemorySize(s, inst),
318 .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst),
319 .mul_add => try w.writeMulAdd(s, inst),
320 .select => try w.writeSelect(s, inst),
321 .shuffle_one => try w.writeShuffleOne(s, inst),
322 .shuffle_two => try w.writeShuffleTwo(s, inst),
323 .reduce, .reduce_optimized => try w.writeReduce(s, inst),
324 .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
325 .vector_store_elem => try w.writeVectorStoreElem(s, inst),
326 .runtime_nav_ptr => try w.writeRuntimeNavPtr(s, inst),
327
328 .work_item_id,
329 .work_group_size,
330 .work_group_id,
331 => try w.writeWorkDimension(s, inst),
332 }
333 try s.writeByte(')');
334 }
335
336 fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
337 const bin_op = w.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
338 try w.writeOperand(s, inst, 0, bin_op.lhs);
339 try s.writeAll(", ");
340 try w.writeOperand(s, inst, 1, bin_op.rhs);
341 }
342
343 fn writeUnOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
344 const un_op = w.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
345 try w.writeOperand(s, inst, 0, un_op);
346 }
347
348 fn writeNoOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
349 _ = w;
350 _ = inst;
351 // no-op, no argument to write
352 }
353
354 fn writeType(w: *Writer, s: anytype, ty: Type) !void {
355 return ty.print(s, w.pt);
356 }
357
358 fn writeTy(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
359 const ty = w.air.instructions.items(.data)[@intFromEnum(inst)].ty;
360 try w.writeType(s, ty);
361 }
362
363 fn writeArg(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
364 const arg = w.air.instructions.items(.data)[@intFromEnum(inst)].arg;
365 try w.writeType(s, arg.ty.toType());
366 switch (arg.name) {
367 .none => {},
368 _ => try s.print(", \"{}\"", .{std.zig.fmtEscapes(arg.name.toSlice(w.air))}),
369 }
370 }
371
372 fn writeTyOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
373 const ty_op = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
374 try w.writeType(s, ty_op.ty.toType());
375 try s.writeAll(", ");
376 try w.writeOperand(s, inst, 0, ty_op.operand);
377 }
378
379 fn writeBlock(w: *Writer, s: anytype, tag: Air.Inst.Tag, inst: Air.Inst.Index) @TypeOf(s).Error!void {
380 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
381 try w.writeType(s, ty_pl.ty.toType());
382 const body: []const Air.Inst.Index = @ptrCast(switch (tag) {
383 inline .block, .dbg_inline_block => |comptime_tag| body: {
384 const extra = w.air.extraData(switch (comptime_tag) {
385 .block => Air.Block,
386 .dbg_inline_block => Air.DbgInlineBlock,
387 else => unreachable,
388 }, ty_pl.payload);
389 switch (comptime_tag) {
390 .block => {},
391 .dbg_inline_block => {
392 try s.writeAll(", ");
393 try w.writeInstRef(s, Air.internedToRef(extra.data.func), false);
394 },
395 else => unreachable,
396 }
397 break :body w.air.extra.items[extra.end..][0..extra.data.body_len];
398 },
399 else => unreachable,
400 });
401 if (w.skip_body) return s.writeAll(", ...");
402 const liveness_block: Air.Liveness.BlockSlices = if (w.liveness) |liveness|
403 liveness.getBlock(inst)
404 else
405 .{ .deaths = &.{} };
406
407 try s.writeAll(", {\n");
408 const old_indent = w.indent;
409 w.indent += 2;
410 try w.writeBody(s, body);
411 w.indent = old_indent;
412 try s.writeByteNTimes(' ', w.indent);
413 try s.writeAll("}");
414
415 for (liveness_block.deaths) |operand| {
416 try s.print(" {}!", .{operand});
417 }
418 }
419
420 fn writeLoop(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
421 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
422 const extra = w.air.extraData(Air.Block, ty_pl.payload);
423 const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]);
424
425 try w.writeType(s, ty_pl.ty.toType());
426 if (w.skip_body) return s.writeAll(", ...");
427 try s.writeAll(", {\n");
428 const old_indent = w.indent;
429 w.indent += 2;
430 try w.writeBody(s, body);
431 w.indent = old_indent;
432 try s.writeByteNTimes(' ', w.indent);
433 try s.writeAll("}");
434 }
435
436 fn writeAggregateInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
437 const zcu = w.pt.zcu;
438 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
439 const vector_ty = ty_pl.ty.toType();
440 const len = @as(usize, @intCast(vector_ty.arrayLen(zcu)));
441 const elements = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[ty_pl.payload..][0..len]));
442
443 try w.writeType(s, vector_ty);
444 try s.writeAll(", [");
445 for (elements, 0..) |elem, i| {
446 if (i != 0) try s.writeAll(", ");
447 try w.writeOperand(s, inst, i, elem);
448 }
449 try s.writeAll("]");
450 }
451
452 fn writeUnionInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
453 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
454 const extra = w.air.extraData(Air.UnionInit, ty_pl.payload).data;
455
456 try s.print("{d}, ", .{extra.field_index});
457 try w.writeOperand(s, inst, 0, extra.init);
458 }
459
460 fn writeStructField(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
461 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
462 const extra = w.air.extraData(Air.StructField, ty_pl.payload).data;
463
464 try w.writeOperand(s, inst, 0, extra.struct_operand);
465 try s.print(", {d}", .{extra.field_index});
466 }
467
468 fn writeTyPlBin(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
469 const data = w.air.instructions.items(.data);
470 const ty_pl = data[@intFromEnum(inst)].ty_pl;
471 const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
472
473 const inst_ty = data[@intFromEnum(inst)].ty_pl.ty.toType();
474 try w.writeType(s, inst_ty);
475 try s.writeAll(", ");
476 try w.writeOperand(s, inst, 0, extra.lhs);
477 try s.writeAll(", ");
478 try w.writeOperand(s, inst, 1, extra.rhs);
479 }
480
481 fn writeCmpxchg(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
482 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
483 const extra = w.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
484
485 try w.writeOperand(s, inst, 0, extra.ptr);
486 try s.writeAll(", ");
487 try w.writeOperand(s, inst, 1, extra.expected_value);
488 try s.writeAll(", ");
489 try w.writeOperand(s, inst, 2, extra.new_value);
490 try s.print(", {s}, {s}", .{
491 @tagName(extra.successOrder()), @tagName(extra.failureOrder()),
492 });
493 }
494
495 fn writeMulAdd(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
496 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
497 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
498
499 try w.writeOperand(s, inst, 0, extra.lhs);
500 try s.writeAll(", ");
501 try w.writeOperand(s, inst, 1, extra.rhs);
502 try s.writeAll(", ");
503 try w.writeOperand(s, inst, 2, pl_op.operand);
504 }
505
506 fn writeShuffleOne(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
507 const unwrapped = w.air.unwrapShuffleOne(w.pt.zcu, inst);
508 try w.writeType(s, unwrapped.result_ty);
509 try s.writeAll(", ");
510 try w.writeOperand(s, inst, 0, unwrapped.operand);
511 try s.writeAll(", [");
512 for (unwrapped.mask, 0..) |mask_elem, mask_idx| {
513 if (mask_idx > 0) try s.writeAll(", ");
514 switch (mask_elem.unwrap()) {
515 .elem => |idx| try s.print("elem {d}", .{idx}),
516 .value => |val| try s.print("val {}", .{Value.fromInterned(val).fmtValue(w.pt)}),
517 }
518 }
519 try s.writeByte(']');
520 }
521
522 fn writeShuffleTwo(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
523 const unwrapped = w.air.unwrapShuffleTwo(w.pt.zcu, inst);
524 try w.writeType(s, unwrapped.result_ty);
525 try s.writeAll(", ");
526 try w.writeOperand(s, inst, 0, unwrapped.operand_a);
527 try s.writeAll(", ");
528 try w.writeOperand(s, inst, 1, unwrapped.operand_b);
529 try s.writeAll(", [");
530 for (unwrapped.mask, 0..) |mask_elem, mask_idx| {
531 if (mask_idx > 0) try s.writeAll(", ");
532 switch (mask_elem.unwrap()) {
533 .a_elem => |idx| try s.print("a_elem {d}", .{idx}),
534 .b_elem => |idx| try s.print("b_elem {d}", .{idx}),
535 .undef => try s.writeAll("undef"),
536 }
537 }
538 try s.writeByte(']');
539 }
540
541 fn writeSelect(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
542 const zcu = w.pt.zcu;
543 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
544 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
545
546 const elem_ty = w.typeOfIndex(inst).childType(zcu);
547 try w.writeType(s, elem_ty);
548 try s.writeAll(", ");
549 try w.writeOperand(s, inst, 0, pl_op.operand);
550 try s.writeAll(", ");
551 try w.writeOperand(s, inst, 1, extra.lhs);
552 try s.writeAll(", ");
553 try w.writeOperand(s, inst, 2, extra.rhs);
554 }
555
556 fn writeReduce(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
557 const reduce = w.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
558
559 try w.writeOperand(s, inst, 0, reduce.operand);
560 try s.print(", {s}", .{@tagName(reduce.operation)});
561 }
562
563 fn writeCmpVector(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
564 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
565 const extra = w.air.extraData(Air.VectorCmp, ty_pl.payload).data;
566
567 try s.print("{s}, ", .{@tagName(extra.compareOperator())});
568 try w.writeOperand(s, inst, 0, extra.lhs);
569 try s.writeAll(", ");
570 try w.writeOperand(s, inst, 1, extra.rhs);
571 }
572
573 fn writeVectorStoreElem(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
574 const data = w.air.instructions.items(.data)[@intFromEnum(inst)].vector_store_elem;
575 const extra = w.air.extraData(Air.VectorCmp, data.payload).data;
576
577 try w.writeOperand(s, inst, 0, data.vector_ptr);
578 try s.writeAll(", ");
579 try w.writeOperand(s, inst, 1, extra.lhs);
580 try s.writeAll(", ");
581 try w.writeOperand(s, inst, 2, extra.rhs);
582 }
583
584 fn writeRuntimeNavPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
585 const ip = &w.pt.zcu.intern_pool;
586 const ty_nav = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
587 try w.writeType(s, .fromInterned(ty_nav.ty));
588 try s.print(", '{}'", .{ip.getNav(ty_nav.nav).fqn.fmt(ip)});
589 }
590
591 fn writeAtomicLoad(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
592 const atomic_load = w.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;
593
594 try w.writeOperand(s, inst, 0, atomic_load.ptr);
595 try s.print(", {s}", .{@tagName(atomic_load.order)});
596 }
597
598 fn writePrefetch(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
599 const prefetch = w.air.instructions.items(.data)[@intFromEnum(inst)].prefetch;
600
601 try w.writeOperand(s, inst, 0, prefetch.ptr);
602 try s.print(", {s}, {d}, {s}", .{
603 @tagName(prefetch.rw), prefetch.locality, @tagName(prefetch.cache),
604 });
605 }
606
607 fn writeAtomicStore(
608 w: *Writer,
609 s: anytype,
610 inst: Air.Inst.Index,
611 order: std.builtin.AtomicOrder,
612 ) @TypeOf(s).Error!void {
613 const bin_op = w.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
614 try w.writeOperand(s, inst, 0, bin_op.lhs);
615 try s.writeAll(", ");
616 try w.writeOperand(s, inst, 1, bin_op.rhs);
617 try s.print(", {s}", .{@tagName(order)});
618 }
619
620 fn writeAtomicRmw(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
621 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
622 const extra = w.air.extraData(Air.AtomicRmw, pl_op.payload).data;
623
624 try w.writeOperand(s, inst, 0, pl_op.operand);
625 try s.writeAll(", ");
626 try w.writeOperand(s, inst, 1, extra.operand);
627 try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) });
628 }
629
630 fn writeFieldParentPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
631 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
632 const extra = w.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
633
634 try w.writeOperand(s, inst, 0, extra.field_ptr);
635 try s.print(", {d}", .{extra.field_index});
636 }
637
638 fn writeAssembly(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
639 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
640 const extra = w.air.extraData(Air.Asm, ty_pl.payload);
641 const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0;
642 const clobbers_len = @as(u31, @truncate(extra.data.flags));
643 var extra_i: usize = extra.end;
644 var op_index: usize = 0;
645
646 const ret_ty = w.typeOfIndex(inst);
647 try w.writeType(s, ret_ty);
648
649 if (is_volatile) {
650 try s.writeAll(", volatile");
651 }
652
653 const outputs = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra_i..][0..extra.data.outputs_len]));
654 extra_i += outputs.len;
655 const inputs = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra_i..][0..extra.data.inputs_len]));
656 extra_i += inputs.len;
657
658 for (outputs) |output| {
659 const extra_bytes = std.mem.sliceAsBytes(w.air.extra.items[extra_i..]);
660 const constraint = std.mem.sliceTo(extra_bytes, 0);
661 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
662
663 // This equation accounts for the fact that even if we have exactly 4 bytes
664 // for the strings and their null terminators, we still use the next u32
665 // for the null terminator.
666 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
667
668 if (output == .none) {
669 try s.print(", [{s}] -> {s}", .{ name, constraint });
670 } else {
671 try s.print(", [{s}] out {s} = (", .{ name, constraint });
672 try w.writeOperand(s, inst, op_index, output);
673 op_index += 1;
674 try s.writeByte(')');
675 }
676 }
677
678 for (inputs) |input| {
679 const extra_bytes = std.mem.sliceAsBytes(w.air.extra.items[extra_i..]);
680 const constraint = std.mem.sliceTo(extra_bytes, 0);
681 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
682 // This equation accounts for the fact that even if we have exactly 4 bytes
683 // for the strings and their null terminators, we still use the next u32
684 // for the null terminator.
685 extra_i += (constraint.len + name.len + 1) / 4 + 1;
686
687 try s.print(", [{s}] in {s} = (", .{ name, constraint });
688 try w.writeOperand(s, inst, op_index, input);
689 op_index += 1;
690 try s.writeByte(')');
691 }
692
693 {
694 var clobber_i: u32 = 0;
695 while (clobber_i < clobbers_len) : (clobber_i += 1) {
696 const extra_bytes = std.mem.sliceAsBytes(w.air.extra.items[extra_i..]);
697 const clobber = std.mem.sliceTo(extra_bytes, 0);
698 // This equation accounts for the fact that even if we have exactly 4 bytes
699 // for the string, we still use the next u32 for the null terminator.
700 extra_i += clobber.len / 4 + 1;
701
702 try s.writeAll(", ~{");
703 try s.writeAll(clobber);
704 try s.writeAll("}");
705 }
706 }
707 const asm_source = std.mem.sliceAsBytes(w.air.extra.items[extra_i..])[0..extra.data.source_len];
708 try s.print(", \"{}\"", .{std.zig.fmtEscapes(asm_source)});
709 }
710
711 fn writeDbgStmt(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
712 const dbg_stmt = w.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
713 try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
714 }
715
716 fn writeDbgVar(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
717 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
718 try w.writeOperand(s, inst, 0, pl_op.operand);
719 const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
720 try s.print(", \"{}\"", .{std.zig.fmtEscapes(name.toSlice(w.air))});
721 }
722
723 fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
724 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
725 const extra = w.air.extraData(Air.Call, pl_op.payload);
726 const args = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra.end..][0..extra.data.args_len]));
727 try w.writeOperand(s, inst, 0, pl_op.operand);
728 try s.writeAll(", [");
729 for (args, 0..) |arg, i| {
730 if (i != 0) try s.writeAll(", ");
731 try w.writeOperand(s, inst, 1 + i, arg);
732 }
733 try s.writeAll("]");
734 }
735
736 fn writeBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
737 const br = w.air.instructions.items(.data)[@intFromEnum(inst)].br;
738 try w.writeInstIndex(s, br.block_inst, false);
739 try s.writeAll(", ");
740 try w.writeOperand(s, inst, 0, br.operand);
741 }
742
743 fn writeRepeat(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
744 const repeat = w.air.instructions.items(.data)[@intFromEnum(inst)].repeat;
745 try w.writeInstIndex(s, repeat.loop_inst, false);
746 }
747
748 fn writeTry(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
749 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
750 const extra = w.air.extraData(Air.Try, pl_op.payload);
751 const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]);
752 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
753 liveness.getCondBr(inst)
754 else
755 .{ .then_deaths = &.{}, .else_deaths = &.{} };
756
757 try w.writeOperand(s, inst, 0, pl_op.operand);
758 if (w.skip_body) return s.writeAll(", ...");
759 try s.writeAll(", {\n");
760 const old_indent = w.indent;
761 w.indent += 2;
762
763 if (liveness_condbr.else_deaths.len != 0) {
764 try s.writeByteNTimes(' ', w.indent);
765 for (liveness_condbr.else_deaths, 0..) |operand, i| {
766 if (i != 0) try s.writeAll(" ");
767 try s.print("{}!", .{operand});
768 }
769 try s.writeAll("\n");
770 }
771 try w.writeBody(s, body);
772
773 w.indent = old_indent;
774 try s.writeByteNTimes(' ', w.indent);
775 try s.writeAll("}");
776
777 for (liveness_condbr.then_deaths) |operand| {
778 try s.print(" {}!", .{operand});
779 }
780 }
781
782 fn writeTryPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
783 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
784 const extra = w.air.extraData(Air.TryPtr, ty_pl.payload);
785 const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]);
786 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
787 liveness.getCondBr(inst)
788 else
789 .{ .then_deaths = &.{}, .else_deaths = &.{} };
790
791 try w.writeOperand(s, inst, 0, extra.data.ptr);
792
793 try s.writeAll(", ");
794 try w.writeType(s, ty_pl.ty.toType());
795 if (w.skip_body) return s.writeAll(", ...");
796 try s.writeAll(", {\n");
797 const old_indent = w.indent;
798 w.indent += 2;
799
800 if (liveness_condbr.else_deaths.len != 0) {
801 try s.writeByteNTimes(' ', w.indent);
802 for (liveness_condbr.else_deaths, 0..) |operand, i| {
803 if (i != 0) try s.writeAll(" ");
804 try s.print("{}!", .{operand});
805 }
806 try s.writeAll("\n");
807 }
808 try w.writeBody(s, body);
809
810 w.indent = old_indent;
811 try s.writeByteNTimes(' ', w.indent);
812 try s.writeAll("}");
813
814 for (liveness_condbr.then_deaths) |operand| {
815 try s.print(" {}!", .{operand});
816 }
817 }
818
819 fn writeCondBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
820 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
821 const extra = w.air.extraData(Air.CondBr, pl_op.payload);
822 const then_body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.then_body_len]);
823 const else_body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end + then_body.len ..][0..extra.data.else_body_len]);
824 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
825 liveness.getCondBr(inst)
826 else
827 .{ .then_deaths = &.{}, .else_deaths = &.{} };
828
829 try w.writeOperand(s, inst, 0, pl_op.operand);
830 if (w.skip_body) return s.writeAll(", ...");
831 try s.writeAll(",");
832 if (extra.data.branch_hints.true != .none) {
833 try s.print(" {s}", .{@tagName(extra.data.branch_hints.true)});
834 }
835 if (extra.data.branch_hints.then_cov != .none) {
836 try s.print(" {s}", .{@tagName(extra.data.branch_hints.then_cov)});
837 }
838 try s.writeAll(" {\n");
839 const old_indent = w.indent;
840 w.indent += 2;
841
842 if (liveness_condbr.then_deaths.len != 0) {
843 try s.writeByteNTimes(' ', w.indent);
844 for (liveness_condbr.then_deaths, 0..) |operand, i| {
845 if (i != 0) try s.writeAll(" ");
846 try s.print("{}!", .{operand});
847 }
848 try s.writeAll("\n");
849 }
850
851 try w.writeBody(s, then_body);
852 try s.writeByteNTimes(' ', old_indent);
853 try s.writeAll("},");
854 if (extra.data.branch_hints.false != .none) {
855 try s.print(" {s}", .{@tagName(extra.data.branch_hints.false)});
856 }
857 if (extra.data.branch_hints.else_cov != .none) {
858 try s.print(" {s}", .{@tagName(extra.data.branch_hints.else_cov)});
859 }
860 try s.writeAll(" {\n");
861
862 if (liveness_condbr.else_deaths.len != 0) {
863 try s.writeByteNTimes(' ', w.indent);
864 for (liveness_condbr.else_deaths, 0..) |operand, i| {
865 if (i != 0) try s.writeAll(" ");
866 try s.print("{}!", .{operand});
867 }
868 try s.writeAll("\n");
869 }
870
871 try w.writeBody(s, else_body);
872 w.indent = old_indent;
873
874 try s.writeByteNTimes(' ', old_indent);
875 try s.writeAll("}");
876 }
877
878 fn writeSwitchBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
879 const switch_br = w.air.unwrapSwitch(inst);
880
881 const liveness: Air.Liveness.SwitchBrTable = if (w.liveness) |liveness|
882 liveness.getSwitchBr(w.gpa, inst, switch_br.cases_len + 1) catch
883 @panic("out of memory")
884 else blk: {
885 const slice = w.gpa.alloc([]const Air.Inst.Index, switch_br.cases_len + 1) catch
886 @panic("out of memory");
887 @memset(slice, &.{});
888 break :blk .{ .deaths = slice };
889 };
890 defer w.gpa.free(liveness.deaths);
891
892 try w.writeOperand(s, inst, 0, switch_br.operand);
893 if (w.skip_body) return s.writeAll(", ...");
894 const old_indent = w.indent;
895 w.indent += 2;
896
897 var it = switch_br.iterateCases();
898 while (it.next()) |case| {
899 try s.writeAll(", [");
900 for (case.items, 0..) |item, item_i| {
901 if (item_i != 0) try s.writeAll(", ");
902 try w.writeInstRef(s, item, false);
903 }
904 for (case.ranges, 0..) |range, range_i| {
905 if (range_i != 0 or case.items.len != 0) try s.writeAll(", ");
906 try w.writeInstRef(s, range[0], false);
907 try s.writeAll("...");
908 try w.writeInstRef(s, range[1], false);
909 }
910 try s.writeAll("] ");
911 const hint = switch_br.getHint(case.idx);
912 if (hint != .none) {
913 try s.print(".{s} ", .{@tagName(hint)});
914 }
915 try s.writeAll("=> {\n");
916 w.indent += 2;
917
918 const deaths = liveness.deaths[case.idx];
919 if (deaths.len != 0) {
920 try s.writeByteNTimes(' ', w.indent);
921 for (deaths, 0..) |operand, i| {
922 if (i != 0) try s.writeAll(" ");
923 try s.print("{}!", .{operand});
924 }
925 try s.writeAll("\n");
926 }
927
928 try w.writeBody(s, case.body);
929 w.indent -= 2;
930 try s.writeByteNTimes(' ', w.indent);
931 try s.writeAll("}");
932 }
933
934 const else_body = it.elseBody();
935 if (else_body.len != 0) {
936 try s.writeAll(", else ");
937 const hint = switch_br.getElseHint();
938 if (hint != .none) {
939 try s.print(".{s} ", .{@tagName(hint)});
940 }
941 try s.writeAll("=> {\n");
942 w.indent += 2;
943
944 const deaths = liveness.deaths[liveness.deaths.len - 1];
945 if (deaths.len != 0) {
946 try s.writeByteNTimes(' ', w.indent);
947 for (deaths, 0..) |operand, i| {
948 if (i != 0) try s.writeAll(" ");
949 try s.print("{}!", .{operand});
950 }
951 try s.writeAll("\n");
952 }
953
954 try w.writeBody(s, else_body);
955 w.indent -= 2;
956 try s.writeByteNTimes(' ', w.indent);
957 try s.writeAll("}");
958 }
959
960 try s.writeAll("\n");
961 try s.writeByteNTimes(' ', old_indent);
962 }
963
964 fn writeWasmMemorySize(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
965 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
966 try s.print("{d}", .{pl_op.payload});
967 }
968
969 fn writeWasmMemoryGrow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
970 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
971 try s.print("{d}, ", .{pl_op.payload});
972 try w.writeOperand(s, inst, 0, pl_op.operand);
973 }
974
975 fn writeWorkDimension(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
976 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
977 try s.print("{d}", .{pl_op.payload});
978 }
979
980 fn writeOperand(
981 w: *Writer,
982 s: anytype,
983 inst: Air.Inst.Index,
984 op_index: usize,
985 operand: Air.Inst.Ref,
986 ) @TypeOf(s).Error!void {
987 const small_tomb_bits = Air.Liveness.bpi - 1;
988 const dies = if (w.liveness) |liveness| blk: {
989 if (op_index < small_tomb_bits)
990 break :blk liveness.operandDies(inst, @intCast(op_index));
991 var extra_index = liveness.special.get(inst).?;
992 var tomb_op_index: usize = small_tomb_bits;
993 while (true) {
994 const bits = liveness.extra[extra_index];
995 if (op_index < tomb_op_index + 31) {
996 break :blk @as(u1, @truncate(bits >> @as(u5, @intCast(op_index - tomb_op_index)))) != 0;
997 }
998 if ((bits >> 31) != 0) break :blk false;
999 extra_index += 1;
1000 tomb_op_index += 31;
1001 }
1002 } else false;
1003 return w.writeInstRef(s, operand, dies);
1004 }
1005
1006 fn writeInstRef(
1007 w: *Writer,
1008 s: anytype,
1009 operand: Air.Inst.Ref,
1010 dies: bool,
1011 ) @TypeOf(s).Error!void {
1012 if (@intFromEnum(operand) < InternPool.static_len) {
1013 return s.print("@{}", .{operand});
1014 } else if (operand.toInterned()) |ip_index| {
1015 const pt = w.pt;
1016 const ty = Type.fromInterned(pt.zcu.intern_pool.indexToKey(ip_index).typeOf());
1017 try s.print("<{}, {}>", .{
1018 ty.fmt(pt),
1019 Value.fromInterned(ip_index).fmtValue(pt),
1020 });
1021 } else {
1022 return w.writeInstIndex(s, operand.toIndex().?, dies);
1023 }
1024 }
1025
1026 fn writeInstIndex(
1027 w: *Writer,
1028 s: anytype,
1029 inst: Air.Inst.Index,
1030 dies: bool,
1031 ) @TypeOf(s).Error!void {
1032 _ = w;
1033 try s.print("{}", .{inst});
1034 if (dies) try s.writeByte('!');
1035 }
1036
1037 fn typeOfIndex(w: *Writer, inst: Air.Inst.Index) Type {
1038 const zcu = w.pt.zcu;
1039 return w.air.typeOfIndex(inst, &zcu.intern_pool);
1040 }
1041};
src/Air/types_resolved.zig+1-1
......@@ -321,7 +321,7 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
321321 if (!checkRef(bin.rhs, zcu)) return false;
322322 },
323323
324 .tlv_dllimport_ptr => {
324 .runtime_nav_ptr => {
325325 if (!checkType(.fromInterned(data.ty_nav.ty), zcu)) return false;
326326 },
327327
src/Compilation.zig+9-6
......@@ -774,7 +774,7 @@ pub const Directories = struct {
774774/// `comp.debug_incremental`. It is inline so that comptime-known `false` propagates to the caller,
775775/// preventing debugging features from making it into release builds of the compiler.
776776pub inline fn debugIncremental(comp: *const Compilation) bool {
777 if (!build_options.enable_debug_extensions) return false;
777 if (!build_options.enable_debug_extensions or builtin.single_threaded) return false;
778778 return comp.debug_incremental;
779779}
780780
......@@ -7225,7 +7225,7 @@ fn buildOutputFromZig(
72257225 assert(out.* == null);
72267226 out.* = crt_file;
72277227
7228 comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
7228 comp.queueLinkTaskMode(crt_file.full_object_path, &config);
72297229}
72307230
72317231pub const CrtFileOptions = struct {
......@@ -7349,7 +7349,7 @@ pub fn build_crt_file(
73497349 try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node);
73507350
73517351 const crt_file = try sub_compilation.toCrtFile();
7352 comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
7352 comp.queueLinkTaskMode(crt_file.full_object_path, &config);
73537353
73547354 {
73557355 comp.mutex.lock();
......@@ -7359,11 +7359,14 @@ pub fn build_crt_file(
73597359 }
73607360}
73617361
7362pub fn queueLinkTaskMode(comp: *Compilation, path: Cache.Path, output_mode: std.builtin.OutputMode) void {
7363 comp.queueLinkTasks(switch (output_mode) {
7362pub fn queueLinkTaskMode(comp: *Compilation, path: Cache.Path, config: *const Compilation.Config) void {
7363 comp.queueLinkTasks(switch (config.output_mode) {
73647364 .Exe => unreachable,
73657365 .Obj => &.{.{ .load_object = path }},
7366 .Lib => &.{.{ .load_archive = path }},
7366 .Lib => &.{switch (config.link_mode) {
7367 .static => .{ .load_archive = path },
7368 .dynamic => .{ .load_dso = path },
7369 }},
73677370 });
73687371}
73697372
src/Compilation/Config.zig+125-113
......@@ -191,91 +191,6 @@ pub fn resolve(options: Options) ResolveError!Config {
191191
192192 const root_optimize_mode = options.root_optimize_mode orelse .Debug;
193193
194 // Make a decision on whether to use LLVM backend for machine code generation.
195 // Note that using the LLVM backend does not necessarily mean using LLVM libraries.
196 // For example, Zig can emit .bc and .ll files directly, and this is still considered
197 // using "the LLVM backend".
198 const use_llvm = b: {
199 // If we have no zig code to compile, no need for LLVM.
200 if (!options.have_zcu) break :b false;
201
202 // If emitting to LLVM bitcode object format, must use LLVM backend.
203 if (options.emit_llvm_ir or options.emit_llvm_bc) {
204 if (options.use_llvm == false)
205 return error.EmittingLlvmModuleRequiresLlvmBackend;
206 if (!target_util.hasLlvmSupport(target, target.ofmt))
207 return error.LlvmLacksTargetSupport;
208
209 break :b true;
210 }
211
212 // If LLVM does not support the target, then we can't use it.
213 if (!target_util.hasLlvmSupport(target, target.ofmt)) {
214 if (options.use_llvm == true) return error.LlvmLacksTargetSupport;
215 break :b false;
216 }
217
218 // If Zig does not support the target, then we can't use it.
219 if (target_util.zigBackend(target, false) == .other) {
220 if (options.use_llvm == false) return error.ZigLacksTargetSupport;
221 break :b true;
222 }
223
224 if (options.use_llvm) |x| break :b x;
225
226 // If we cannot use LLVM libraries, then our own backends will be a
227 // better default since the LLVM backend can only produce bitcode
228 // and not an object file or executable.
229 if (!use_lib_llvm and options.emit_bin) break :b false;
230
231 // Prefer LLVM for release builds.
232 if (root_optimize_mode != .Debug) break :b true;
233
234 // At this point we would prefer to use our own self-hosted backend,
235 // because the compilation speed is better than LLVM. But only do it if
236 // we are confident in the robustness of the backend.
237 break :b !target_util.selfHostedBackendIsAsRobustAsLlvm(target);
238 };
239
240 if (options.emit_bin and options.have_zcu) {
241 if (!use_lib_llvm and use_llvm) {
242 // Explicit request to use LLVM to produce an object file, but without
243 // using LLVM libraries. Impossible.
244 return error.EmittingBinaryRequiresLlvmLibrary;
245 }
246
247 if (target_util.zigBackend(target, use_llvm) == .other) {
248 // There is no compiler backend available for this target.
249 return error.ZigLacksTargetSupport;
250 }
251 }
252
253 // Make a decision on whether to use LLD or our own linker.
254 const use_lld = b: {
255 if (!target_util.hasLldSupport(target.ofmt)) {
256 if (options.use_lld == true) return error.LldIncompatibleObjectFormat;
257 break :b false;
258 }
259
260 if (!build_options.have_llvm) {
261 if (options.use_lld == true) return error.LldUnavailable;
262 break :b false;
263 }
264
265 if (options.lto != null and options.lto != .none) {
266 if (options.use_lld == false) return error.LtoRequiresLld;
267 break :b true;
268 }
269
270 if (options.use_llvm == false) {
271 if (options.use_lld == true) return error.LldCannotIncrementallyLink;
272 break :b false;
273 }
274
275 if (options.use_lld) |x| break :b x;
276 break :b true;
277 };
278
279194 // Make a decision on whether to use Clang or Aro for translate-c and compiling C files.
280195 const c_frontend: CFrontend = b: {
281196 if (!build_options.have_llvm) {
......@@ -288,19 +203,6 @@ pub fn resolve(options: Options) ResolveError!Config {
288203 break :b .clang;
289204 };
290205
291 const lto: std.zig.LtoMode = b: {
292 if (!use_lld) {
293 // zig ld LTO support is tracked by
294 // https://github.com/ziglang/zig/issues/8680
295 if (options.lto != null and options.lto != .none) return error.LtoRequiresLld;
296 break :b .none;
297 }
298
299 if (options.lto) |x| break :b x;
300
301 break :b .none;
302 };
303
304206 const link_libcpp = b: {
305207 if (options.link_libcpp == true) break :b true;
306208 if (options.any_sanitize_thread) {
......@@ -314,14 +216,6 @@ pub fn resolve(options: Options) ResolveError!Config {
314216 break :b false;
315217 };
316218
317 var link_libunwind = b: {
318 if (link_libcpp and target_util.libCxxNeedsLibUnwind(target)) {
319 if (options.link_libunwind == false) return error.LibCppRequiresLibUnwind;
320 break :b true;
321 }
322 break :b options.link_libunwind orelse false;
323 };
324
325219 const link_libc = b: {
326220 if (target_util.osRequiresLibC(target)) {
327221 if (options.link_libc == false) return error.OsRequiresLibC;
......@@ -331,7 +225,7 @@ pub fn resolve(options: Options) ResolveError!Config {
331225 if (options.link_libc == false) return error.LibCppRequiresLibC;
332226 break :b true;
333227 }
334 if (link_libunwind) {
228 if (options.link_libunwind == true) {
335229 if (options.link_libc == false) return error.LibUnwindRequiresLibC;
336230 break :b true;
337231 }
......@@ -402,12 +296,17 @@ pub fn resolve(options: Options) ResolveError!Config {
402296 break :b .static;
403297 };
404298
405 // This is done here to avoid excessive duplicated logic due to the complex dependencies between these options.
406 if (options.output_mode == .Exe and link_libc and target_util.libCNeedsLibUnwind(target, link_mode)) {
407 if (options.link_libunwind == false) return error.LibCRequiresLibUnwind;
408
409 link_libunwind = true;
410 }
299 const link_libunwind = b: {
300 if (options.output_mode == .Exe and link_libc and target_util.libCNeedsLibUnwind(target, link_mode)) {
301 if (options.link_libunwind == false) return error.LibCRequiresLibUnwind;
302 break :b true;
303 }
304 if (link_libcpp and target_util.libCxxNeedsLibUnwind(target)) {
305 if (options.link_libunwind == false) return error.LibCppRequiresLibUnwind;
306 break :b true;
307 }
308 break :b options.link_libunwind orelse false;
309 };
411310
412311 const import_memory = options.import_memory orelse (options.output_mode == .Obj);
413312 const export_memory = b: {
......@@ -446,6 +345,119 @@ pub fn resolve(options: Options) ResolveError!Config {
446345 } else false;
447346 };
448347
348 const is_dyn_lib = switch (options.output_mode) {
349 .Obj, .Exe => false,
350 .Lib => link_mode == .dynamic,
351 };
352
353 // Make a decision on whether to use LLVM backend for machine code generation.
354 // Note that using the LLVM backend does not necessarily mean using LLVM libraries.
355 // For example, Zig can emit .bc and .ll files directly, and this is still considered
356 // using "the LLVM backend".
357 const use_llvm = b: {
358 // If we have no zig code to compile, no need for LLVM.
359 if (!options.have_zcu) break :b false;
360
361 // If emitting to LLVM bitcode object format, must use LLVM backend.
362 if (options.emit_llvm_ir or options.emit_llvm_bc) {
363 if (options.use_llvm == false)
364 return error.EmittingLlvmModuleRequiresLlvmBackend;
365 if (!target_util.hasLlvmSupport(target, target.ofmt))
366 return error.LlvmLacksTargetSupport;
367
368 break :b true;
369 }
370
371 // If LLVM does not support the target, then we can't use it.
372 if (!target_util.hasLlvmSupport(target, target.ofmt)) {
373 if (options.use_llvm == true) return error.LlvmLacksTargetSupport;
374 break :b false;
375 }
376
377 // If Zig does not support the target, then we can't use it.
378 if (target_util.zigBackend(target, false) == .other) {
379 if (options.use_llvm == false) return error.ZigLacksTargetSupport;
380 break :b true;
381 }
382
383 if (options.use_llvm) |x| break :b x;
384
385 // If we cannot use LLVM libraries, then our own backends will be a
386 // better default since the LLVM backend can only produce bitcode
387 // and not an object file or executable.
388 if (!use_lib_llvm and options.emit_bin) break :b false;
389
390 // Prefer LLVM for release builds.
391 if (root_optimize_mode != .Debug) break :b true;
392
393 // load_dynamic_library standalone test not passing on this combination
394 // https://github.com/ziglang/zig/issues/24080
395 if (target.os.tag == .macos and is_dyn_lib) break :b true;
396
397 // At this point we would prefer to use our own self-hosted backend,
398 // because the compilation speed is better than LLVM. But only do it if
399 // we are confident in the robustness of the backend.
400 break :b !target_util.selfHostedBackendIsAsRobustAsLlvm(target);
401 };
402
403 if (options.emit_bin and options.have_zcu) {
404 if (!use_lib_llvm and use_llvm) {
405 // Explicit request to use LLVM to produce an object file, but without
406 // using LLVM libraries. Impossible.
407 return error.EmittingBinaryRequiresLlvmLibrary;
408 }
409
410 if (target_util.zigBackend(target, use_llvm) == .other) {
411 // There is no compiler backend available for this target.
412 return error.ZigLacksTargetSupport;
413 }
414 }
415
416 // Make a decision on whether to use LLD or our own linker.
417 const use_lld = b: {
418 if (!target_util.hasLldSupport(target.ofmt)) {
419 if (options.use_lld == true) return error.LldIncompatibleObjectFormat;
420 break :b false;
421 }
422
423 if (!build_options.have_llvm) {
424 if (options.use_lld == true) return error.LldUnavailable;
425 break :b false;
426 }
427
428 if (options.lto != null and options.lto != .none) {
429 if (options.use_lld == false) return error.LtoRequiresLld;
430 break :b true;
431 }
432
433 if (options.use_llvm == false) {
434 if (options.use_lld == true) return error.LldCannotIncrementallyLink;
435 break :b false;
436 }
437
438 if (options.use_lld) |x| break :b x;
439
440 // If we have no zig code to compile, no need for the self-hosted linker.
441 if (!options.have_zcu) break :b true;
442
443 // If we do have zig code, match the decision for whether to use the llvm backend,
444 // so that the llvm backend defaults to lld and the self-hosted backends do not.
445 break :b use_llvm;
446 };
447
448 const lto: std.zig.LtoMode = b: {
449 if (!use_lld) {
450 // zig ld LTO support is tracked by
451 // https://github.com/ziglang/zig/issues/8680
452 if (options.lto != null and options.lto != .none) return error.LtoRequiresLld;
453 break :b .none;
454 }
455
456 if (options.lto) |x| break :b x;
457
458 break :b .none;
459 };
460
449461 const root_strip = b: {
450462 if (options.root_strip) |x| break :b x;
451463 if (root_optimize_mode == .ReleaseSmall) break :b true;
src/IncrementalDebugServer.zig+1-1
......@@ -10,7 +10,7 @@
1010
1111comptime {
1212 // This file should only be referenced when debug extensions are enabled.
13 std.debug.assert(@import("build_options").enable_debug_extensions);
13 std.debug.assert(@import("build_options").enable_debug_extensions and !@import("builtin").single_threaded);
1414}
1515
1616zcu: *Zcu,
src/InternPool.zig+71-49
......@@ -526,10 +526,10 @@ pub const Nav = struct {
526526 /// The type of this `Nav` is resolved; the value is queued for resolution.
527527 type_resolved: struct {
528528 type: InternPool.Index,
529 is_const: bool,
529530 alignment: Alignment,
530531 @"linksection": OptionalNullTerminatedString,
531532 @"addrspace": std.builtin.AddressSpace,
532 is_const: bool,
533533 is_threadlocal: bool,
534534 /// This field is whether this `Nav` is a literal `extern` definition.
535535 /// It does *not* tell you whether this might alias an extern fn (see #21027).
......@@ -538,6 +538,7 @@ pub const Nav = struct {
538538 /// The value of this `Nav` is resolved.
539539 fully_resolved: struct {
540540 val: InternPool.Index,
541 is_const: bool,
541542 alignment: Alignment,
542543 @"linksection": OptionalNullTerminatedString,
543544 @"addrspace": std.builtin.AddressSpace,
......@@ -727,12 +728,12 @@ pub const Nav = struct {
727728 const Bits = packed struct(u16) {
728729 status: enum(u2) { unresolved, type_resolved, fully_resolved, type_resolved_extern_decl },
729730 /// Populated only if `bits.status != .unresolved`.
731 is_const: bool,
732 /// Populated only if `bits.status != .unresolved`.
730733 alignment: Alignment,
731734 /// Populated only if `bits.status != .unresolved`.
732735 @"addrspace": std.builtin.AddressSpace,
733736 /// Populated only if `bits.status == .type_resolved`.
734 is_const: bool,
735 /// Populated only if `bits.status == .type_resolved`.
736737 is_threadlocal: bool,
737738 is_usingnamespace: bool,
738739 };
......@@ -753,15 +754,16 @@ pub const Nav = struct {
753754 .unresolved => .unresolved,
754755 .type_resolved, .type_resolved_extern_decl => .{ .type_resolved = .{
755756 .type = repr.type_or_val,
757 .is_const = repr.bits.is_const,
756758 .alignment = repr.bits.alignment,
757759 .@"linksection" = repr.@"linksection",
758760 .@"addrspace" = repr.bits.@"addrspace",
759 .is_const = repr.bits.is_const,
760761 .is_threadlocal = repr.bits.is_threadlocal,
761762 .is_extern_decl = repr.bits.status == .type_resolved_extern_decl,
762763 } },
763764 .fully_resolved => .{ .fully_resolved = .{
764765 .val = repr.type_or_val,
766 .is_const = repr.bits.is_const,
765767 .alignment = repr.bits.alignment,
766768 .@"linksection" = repr.@"linksection",
767769 .@"addrspace" = repr.bits.@"addrspace",
......@@ -792,26 +794,26 @@ pub const Nav = struct {
792794 .bits = switch (nav.status) {
793795 .unresolved => .{
794796 .status = .unresolved,
797 .is_const = false,
795798 .alignment = .none,
796799 .@"addrspace" = .generic,
797800 .is_usingnamespace = nav.is_usingnamespace,
798 .is_const = false,
799801 .is_threadlocal = false,
800802 },
801803 .type_resolved => |r| .{
802804 .status = if (r.is_extern_decl) .type_resolved_extern_decl else .type_resolved,
805 .is_const = r.is_const,
803806 .alignment = r.alignment,
804807 .@"addrspace" = r.@"addrspace",
805808 .is_usingnamespace = nav.is_usingnamespace,
806 .is_const = r.is_const,
807809 .is_threadlocal = r.is_threadlocal,
808810 },
809811 .fully_resolved => |r| .{
810812 .status = .fully_resolved,
813 .is_const = r.is_const,
811814 .alignment = r.alignment,
812815 .@"addrspace" = r.@"addrspace",
813816 .is_usingnamespace = nav.is_usingnamespace,
814 .is_const = false,
815817 .is_threadlocal = false,
816818 },
817819 },
......@@ -2221,7 +2223,6 @@ pub const Key = union(enum) {
22212223 init: Index,
22222224 owner_nav: Nav.Index,
22232225 is_threadlocal: bool,
2224 is_weak_linkage: bool,
22252226 };
22262227
22272228 pub const Extern = struct {
......@@ -2234,10 +2235,12 @@ pub const Key = union(enum) {
22342235 /// For example `extern "c" fn write(...) usize` would have 'c' as library name.
22352236 /// Index into the string table bytes.
22362237 lib_name: OptionalNullTerminatedString,
2237 is_const: bool,
2238 linkage: std.builtin.GlobalLinkage,
2239 visibility: std.builtin.SymbolVisibility,
22382240 is_threadlocal: bool,
2239 is_weak_linkage: bool,
22402241 is_dll_import: bool,
2242 relocation: std.builtin.ExternOptions.Relocation,
2243 is_const: bool,
22412244 alignment: Alignment,
22422245 @"addrspace": std.builtin.AddressSpace,
22432246 /// The ZIR instruction which created this extern; used only for source locations.
......@@ -2844,9 +2847,10 @@ pub const Key = union(enum) {
28442847
28452848 .@"extern" => |e| Hash.hash(seed, asBytes(&e.name) ++
28462849 asBytes(&e.ty) ++ asBytes(&e.lib_name) ++
2847 asBytes(&e.is_const) ++ asBytes(&e.is_threadlocal) ++
2848 asBytes(&e.is_weak_linkage) ++ asBytes(&e.alignment) ++
2849 asBytes(&e.is_dll_import) ++ asBytes(&e.@"addrspace") ++
2850 asBytes(&e.linkage) ++ asBytes(&e.visibility) ++
2851 asBytes(&e.is_threadlocal) ++ asBytes(&e.is_dll_import) ++
2852 asBytes(&e.relocation) ++
2853 asBytes(&e.is_const) ++ asBytes(&e.alignment) ++ asBytes(&e.@"addrspace") ++
28502854 asBytes(&e.zir_index)),
28512855 };
28522856 }
......@@ -2928,21 +2932,22 @@ pub const Key = union(enum) {
29282932
29292933 .variable => |a_info| {
29302934 const b_info = b.variable;
2931 return a_info.owner_nav == b_info.owner_nav and
2932 a_info.ty == b_info.ty and
2935 return a_info.ty == b_info.ty and
29332936 a_info.init == b_info.init and
2934 a_info.is_threadlocal == b_info.is_threadlocal and
2935 a_info.is_weak_linkage == b_info.is_weak_linkage;
2937 a_info.owner_nav == b_info.owner_nav and
2938 a_info.is_threadlocal == b_info.is_threadlocal;
29362939 },
29372940 .@"extern" => |a_info| {
29382941 const b_info = b.@"extern";
29392942 return a_info.name == b_info.name and
29402943 a_info.ty == b_info.ty and
29412944 a_info.lib_name == b_info.lib_name and
2942 a_info.is_const == b_info.is_const and
2945 a_info.linkage == b_info.linkage and
2946 a_info.visibility == b_info.visibility and
29432947 a_info.is_threadlocal == b_info.is_threadlocal and
2944 a_info.is_weak_linkage == b_info.is_weak_linkage and
29452948 a_info.is_dll_import == b_info.is_dll_import and
2949 a_info.relocation == b_info.relocation and
2950 a_info.is_const == b_info.is_const and
29462951 a_info.alignment == b_info.alignment and
29472952 a_info.@"addrspace" == b_info.@"addrspace" and
29482953 a_info.zir_index == b_info.zir_index;
......@@ -4889,6 +4894,7 @@ pub const Index = enum(u32) {
48894894 float_c_longdouble_f128: struct { data: *Float128 },
48904895 float_comptime_float: struct { data: *Float128 },
48914896 variable: struct { data: *Tag.Variable },
4897 threadlocal_variable: struct { data: *Tag.Variable },
48924898 @"extern": struct { data: *Tag.Extern },
48934899 func_decl: struct {
48944900 const @"data.analysis.inferred_error_set" = opaque {};
......@@ -5548,6 +5554,9 @@ pub const Tag = enum(u8) {
55485554 /// A global variable.
55495555 /// data is extra index to Variable.
55505556 variable,
5557 /// A global threadlocal variable.
5558 /// data is extra index to Variable.
5559 threadlocal_variable,
55515560 /// An extern function or variable.
55525561 /// data is extra index to Extern.
55535562 /// Some parts of the key are stored in `owner_nav`.
......@@ -5863,6 +5872,7 @@ pub const Tag = enum(u8) {
58635872 .float_c_longdouble_f128 = .{ .summary = .@"@as(c_longdouble, {.payload%value})", .payload = f128 },
58645873 .float_comptime_float = .{ .summary = .@"{.payload%value}", .payload = f128 },
58655874 .variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable },
5875 .threadlocal_variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable },
58665876 .@"extern" = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Extern },
58675877 .func_decl = .{
58685878 .summary = .@"{.payload.owner_nav.fqn%summary#\"}",
......@@ -5913,24 +5923,24 @@ pub const Tag = enum(u8) {
59135923 /// May be `none`.
59145924 init: Index,
59155925 owner_nav: Nav.Index,
5916 flags: Flags,
5917
5918 pub const Flags = packed struct(u32) {
5919 is_const: bool,
5920 is_threadlocal: bool,
5921 is_weak_linkage: bool,
5922 is_dll_import: bool,
5923 _: u28 = 0,
5924 };
59255926 };
59265927
59275928 pub const Extern = struct {
5928 // name, alignment, addrspace come from `owner_nav`.
5929 // name, is_const, alignment, addrspace come from `owner_nav`.
59295930 ty: Index,
59305931 lib_name: OptionalNullTerminatedString,
5931 flags: Variable.Flags,
5932 flags: Flags,
59325933 owner_nav: Nav.Index,
59335934 zir_index: TrackedInst.Index,
5935
5936 pub const Flags = packed struct(u32) {
5937 linkage: std.builtin.GlobalLinkage,
5938 visibility: std.builtin.SymbolVisibility,
5939 is_threadlocal: bool,
5940 is_dll_import: bool,
5941 relocation: std.builtin.ExternOptions.Relocation,
5942 _: u25 = 0,
5943 };
59345944 };
59355945
59365946 /// Trailing:
......@@ -7248,14 +7258,17 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
72487258 .ty = .comptime_float_type,
72497259 .storage = .{ .f128 = extraData(unwrapped_index.getExtra(ip), Float128, data).get() },
72507260 } },
7251 .variable => {
7261 .variable, .threadlocal_variable => {
72527262 const extra = extraData(unwrapped_index.getExtra(ip), Tag.Variable, data);
72537263 return .{ .variable = .{
72547264 .ty = extra.ty,
72557265 .init = extra.init,
72567266 .owner_nav = extra.owner_nav,
7257 .is_threadlocal = extra.flags.is_threadlocal,
7258 .is_weak_linkage = extra.flags.is_weak_linkage,
7267 .is_threadlocal = switch (item.tag) {
7268 else => unreachable,
7269 .variable => false,
7270 .threadlocal_variable => true,
7271 },
72597272 } };
72607273 },
72617274 .@"extern" => {
......@@ -7265,10 +7278,12 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
72657278 .name = nav.name,
72667279 .ty = extra.ty,
72677280 .lib_name = extra.lib_name,
7268 .is_const = extra.flags.is_const,
7281 .linkage = extra.flags.linkage,
7282 .visibility = extra.flags.visibility,
72697283 .is_threadlocal = extra.flags.is_threadlocal,
7270 .is_weak_linkage = extra.flags.is_weak_linkage,
72717284 .is_dll_import = extra.flags.is_dll_import,
7285 .relocation = extra.flags.relocation,
7286 .is_const = nav.status.fully_resolved.is_const,
72727287 .alignment = nav.status.fully_resolved.alignment,
72737288 .@"addrspace" = nav.status.fully_resolved.@"addrspace",
72747289 .zir_index = extra.zir_index,
......@@ -7895,17 +7910,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
78957910 const has_init = variable.init != .none;
78967911 if (has_init) assert(variable.ty == ip.typeOf(variable.init));
78977912 items.appendAssumeCapacity(.{
7898 .tag = .variable,
7913 .tag = switch (variable.is_threadlocal) {
7914 false => .variable,
7915 true => .threadlocal_variable,
7916 },
78997917 .data = try addExtra(extra, Tag.Variable{
79007918 .ty = variable.ty,
79017919 .init = variable.init,
79027920 .owner_nav = variable.owner_nav,
7903 .flags = .{
7904 .is_const = false,
7905 .is_threadlocal = variable.is_threadlocal,
7906 .is_weak_linkage = variable.is_weak_linkage,
7907 .is_dll_import = false,
7908 },
79097921 }),
79107922 });
79117923 },
......@@ -9128,6 +9140,7 @@ pub fn getExtern(
91289140 .name = key.name,
91299141 .fqn = key.name,
91309142 .val = extern_index,
9143 .is_const = key.is_const,
91319144 .alignment = key.alignment,
91329145 .@"linksection" = .none,
91339146 .@"addrspace" = key.@"addrspace",
......@@ -9136,10 +9149,11 @@ pub fn getExtern(
91369149 .ty = key.ty,
91379150 .lib_name = key.lib_name,
91389151 .flags = .{
9139 .is_const = key.is_const,
9152 .linkage = key.linkage,
9153 .visibility = key.visibility,
91409154 .is_threadlocal = key.is_threadlocal,
9141 .is_weak_linkage = key.is_weak_linkage,
91429155 .is_dll_import = key.is_dll_import,
9156 .relocation = key.relocation,
91439157 },
91449158 .zir_index = key.zir_index,
91459159 .owner_nav = owner_nav,
......@@ -9714,6 +9728,7 @@ fn finishFuncInstance(
97149728 .name = nav_name,
97159729 .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, tid, nav_name),
97169730 .val = func_index,
9731 .is_const = fn_owner_nav.status.fully_resolved.is_const,
97179732 .alignment = fn_owner_nav.status.fully_resolved.alignment,
97189733 .@"linksection" = fn_owner_nav.status.fully_resolved.@"linksection",
97199734 .@"addrspace" = fn_owner_nav.status.fully_resolved.@"addrspace",
......@@ -10300,13 +10315,13 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 {
1030010315 u32,
1030110316 i32,
1030210317 FuncAnalysis,
10318 Tag.Extern.Flags,
1030310319 Tag.TypePointer.Flags,
1030410320 Tag.TypeFunction.Flags,
1030510321 Tag.TypePointer.PackedOffset,
1030610322 Tag.TypeUnion.Flags,
1030710323 Tag.TypeStruct.Flags,
1030810324 Tag.TypeStructPacked.Flags,
10309 Tag.Variable.Flags,
1031010325 => @bitCast(@field(item, field.name)),
1031110326
1031210327 else => @compileError("bad field type: " ++ @typeName(field.type)),
......@@ -10361,13 +10376,13 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat
1036110376
1036210377 u32,
1036310378 i32,
10379 Tag.Extern.Flags,
1036410380 Tag.TypePointer.Flags,
1036510381 Tag.TypeFunction.Flags,
1036610382 Tag.TypePointer.PackedOffset,
1036710383 Tag.TypeUnion.Flags,
1036810384 Tag.TypeStruct.Flags,
1036910385 Tag.TypeStructPacked.Flags,
10370 Tag.Variable.Flags,
1037110386 FuncAnalysis,
1037210387 => @bitCast(extra_item),
1037310388
......@@ -11162,7 +11177,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
1116211177 .float_c_longdouble_f80 => @sizeOf(Float80),
1116311178 .float_c_longdouble_f128 => @sizeOf(Float128),
1116411179 .float_comptime_float => @sizeOf(Float128),
11165 .variable => @sizeOf(Tag.Variable),
11180 .variable, .threadlocal_variable => @sizeOf(Tag.Variable),
1116611181 .@"extern" => @sizeOf(Tag.Extern),
1116711182 .func_decl => @sizeOf(Tag.FuncDecl),
1116811183 .func_instance => b: {
......@@ -11282,6 +11297,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
1128211297 .float_c_longdouble_f128,
1128311298 .float_comptime_float,
1128411299 .variable,
11300 .threadlocal_variable,
1128511301 .@"extern",
1128611302 .func_decl,
1128711303 .func_instance,
......@@ -11414,6 +11430,7 @@ pub fn createNav(
1141411430 name: NullTerminatedString,
1141511431 fqn: NullTerminatedString,
1141611432 val: InternPool.Index,
11433 is_const: bool,
1141711434 alignment: Alignment,
1141811435 @"linksection": OptionalNullTerminatedString,
1141911436 @"addrspace": std.builtin.AddressSpace,
......@@ -11430,6 +11447,7 @@ pub fn createNav(
1143011447 .analysis = null,
1143111448 .status = .{ .fully_resolved = .{
1143211449 .val = opts.val,
11450 .is_const = opts.is_const,
1143311451 .alignment = opts.alignment,
1143411452 .@"linksection" = opts.@"linksection",
1143511453 .@"addrspace" = opts.@"addrspace",
......@@ -11482,10 +11500,10 @@ pub fn resolveNavType(
1148211500 nav: Nav.Index,
1148311501 resolved: struct {
1148411502 type: InternPool.Index,
11503 is_const: bool,
1148511504 alignment: Alignment,
1148611505 @"linksection": OptionalNullTerminatedString,
1148711506 @"addrspace": std.builtin.AddressSpace,
11488 is_const: bool,
1148911507 is_threadlocal: bool,
1149011508 is_extern_decl: bool,
1149111509 },
......@@ -11512,9 +11530,9 @@ pub fn resolveNavType(
1151211530
1151311531 var bits = nav_bits[unwrapped.index];
1151411532 bits.status = if (resolved.is_extern_decl) .type_resolved_extern_decl else .type_resolved;
11533 bits.is_const = resolved.is_const;
1151511534 bits.alignment = resolved.alignment;
1151611535 bits.@"addrspace" = resolved.@"addrspace";
11517 bits.is_const = resolved.is_const;
1151811536 bits.is_threadlocal = resolved.is_threadlocal;
1151911537 @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);
1152011538}
......@@ -11526,6 +11544,7 @@ pub fn resolveNavValue(
1152611544 nav: Nav.Index,
1152711545 resolved: struct {
1152811546 val: InternPool.Index,
11547 is_const: bool,
1152911548 alignment: Alignment,
1153011549 @"linksection": OptionalNullTerminatedString,
1153111550 @"addrspace": std.builtin.AddressSpace,
......@@ -11553,6 +11572,7 @@ pub fn resolveNavValue(
1155311572
1155411573 var bits = nav_bits[unwrapped.index];
1155511574 bits.status = .fully_resolved;
11575 bits.is_const = resolved.is_const;
1155611576 bits.alignment = resolved.alignment;
1155711577 bits.@"addrspace" = resolved.@"addrspace";
1155811578 @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);
......@@ -12007,6 +12027,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
1200712027 .error_union_error,
1200812028 .enum_tag,
1200912029 .variable,
12030 .threadlocal_variable,
1201012031 .@"extern",
1201112032 .func_decl,
1201212033 .func_instance,
......@@ -12391,6 +12412,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
1239112412 .float_c_longdouble_f128,
1239212413 .float_comptime_float,
1239312414 .variable,
12415 .threadlocal_variable,
1239412416 .@"extern",
1239512417 .func_decl,
1239612418 .func_instance,
src/Sema.zig+45-14
......@@ -26089,10 +26089,12 @@ fn resolveExternOptions(
2608926089 zir_ref: Zir.Inst.Ref,
2609026090) CompileError!struct {
2609126091 name: InternPool.NullTerminatedString,
26092 library_name: InternPool.OptionalNullTerminatedString = .none,
26093 linkage: std.builtin.GlobalLinkage = .strong,
26094 is_thread_local: bool = false,
26095 is_dll_import: bool = false,
26092 library_name: InternPool.OptionalNullTerminatedString,
26093 linkage: std.builtin.GlobalLinkage,
26094 visibility: std.builtin.SymbolVisibility,
26095 is_thread_local: bool,
26096 is_dll_import: bool,
26097 relocation: std.builtin.ExternOptions.Relocation,
2609626098} {
2609726099 const pt = sema.pt;
2609826100 const zcu = pt.zcu;
......@@ -26105,8 +26107,10 @@ fn resolveExternOptions(
2610526107 const name_src = block.src(.{ .init_field_name = src.offset.node_offset_builtin_call_arg.builtin_call_node });
2610626108 const library_src = block.src(.{ .init_field_library = src.offset.node_offset_builtin_call_arg.builtin_call_node });
2610726109 const linkage_src = block.src(.{ .init_field_linkage = src.offset.node_offset_builtin_call_arg.builtin_call_node });
26110 const visibility_src = block.src(.{ .init_field_visibility = src.offset.node_offset_builtin_call_arg.builtin_call_node });
2610826111 const thread_local_src = block.src(.{ .init_field_thread_local = src.offset.node_offset_builtin_call_arg.builtin_call_node });
2610926112 const dll_import_src = block.src(.{ .init_field_dll_import = src.offset.node_offset_builtin_call_arg.builtin_call_node });
26113 const relocation_src = block.src(.{ .init_field_relocation = src.offset.node_offset_builtin_call_arg.builtin_call_node });
2611026114
2611126115 const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), name_src);
2611226116 const name = try sema.toConstString(block, name_src, name_ref, .{ .simple = .extern_options });
......@@ -26118,6 +26122,10 @@ fn resolveExternOptions(
2611826122 const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_ref, .{ .simple = .extern_options });
2611926123 const linkage = try sema.interpretBuiltinType(block, linkage_src, linkage_val, std.builtin.GlobalLinkage);
2612026124
26125 const visibility_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "visibility", .no_embedded_nulls), visibility_src);
26126 const visibility_val = try sema.resolveConstDefinedValue(block, visibility_src, visibility_ref, .{ .simple = .extern_options });
26127 const visibility = try sema.interpretBuiltinType(block, visibility_src, visibility_val, std.builtin.SymbolVisibility);
26128
2612126129 const is_thread_local = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "is_thread_local", .no_embedded_nulls), thread_local_src);
2612226130 const is_thread_local_val = try sema.resolveConstDefinedValue(block, thread_local_src, is_thread_local, .{ .simple = .extern_options });
2612326131
......@@ -26133,6 +26141,10 @@ fn resolveExternOptions(
2613326141 const is_dll_import_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "is_dll_import", .no_embedded_nulls), dll_import_src);
2613426142 const is_dll_import_val = try sema.resolveConstDefinedValue(block, dll_import_src, is_dll_import_ref, .{ .simple = .extern_options });
2613526143
26144 const relocation_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "relocation", .no_embedded_nulls), relocation_src);
26145 const relocation_val = try sema.resolveConstDefinedValue(block, relocation_src, relocation_ref, .{ .simple = .extern_options });
26146 const relocation = try sema.interpretBuiltinType(block, relocation_src, relocation_val, std.builtin.ExternOptions.Relocation);
26147
2613626148 if (name.len == 0) {
2613726149 return sema.fail(block, name_src, "extern symbol name cannot be empty", .{});
2613826150 }
......@@ -26145,8 +26157,10 @@ fn resolveExternOptions(
2614526157 .name = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls),
2614626158 .library_name = try ip.getOrPutStringOpt(gpa, pt.tid, library_name, .no_embedded_nulls),
2614726159 .linkage = linkage,
26160 .visibility = visibility,
2614826161 .is_thread_local = is_thread_local_val.toBool(),
2614926162 .is_dll_import = is_dll_import_val.toBool(),
26163 .relocation = relocation,
2615026164 };
2615126165}
2615226166
......@@ -26178,6 +26192,17 @@ fn zirBuiltinExtern(
2617826192 }
2617926193
2618026194 const options = try sema.resolveExternOptions(block, options_src, extra.rhs);
26195 switch (options.linkage) {
26196 .internal => if (options.visibility != .default) {
26197 return sema.fail(block, options_src, "internal symbol cannot have non-default visibility", .{});
26198 },
26199 .strong, .weak => {},
26200 .link_once => return sema.fail(block, options_src, "external symbol cannot have link once linkage", .{}),
26201 }
26202 switch (options.relocation) {
26203 .any => {},
26204 .pcrel => if (options.visibility == .default) return sema.fail(block, options_src, "cannot require a pc-relative relocation to a symbol with default visibility", .{}),
26205 }
2618126206
2618226207 // TODO: error for threadlocal functions, non-const functions, etc
2618326208
......@@ -26190,10 +26215,12 @@ fn zirBuiltinExtern(
2619026215 .name = options.name,
2619126216 .ty = ptr_info.child,
2619226217 .lib_name = options.library_name,
26193 .is_const = ptr_info.flags.is_const,
26218 .linkage = options.linkage,
26219 .visibility = options.visibility,
2619426220 .is_threadlocal = options.is_thread_local,
26195 .is_weak_linkage = options.linkage == .weak,
2619626221 .is_dll_import = options.is_dll_import,
26222 .relocation = options.relocation,
26223 .is_const = ptr_info.flags.is_const,
2619726224 .alignment = ptr_info.flags.alignment,
2619826225 .@"addrspace" = ptr_info.flags.address_space,
2619926226 // This instruction is just for source locations.
......@@ -31685,12 +31712,15 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
3168531712
3168631713 const nav_status = ip.getNav(nav_index).status;
3168731714
31688 const is_tlv_or_dllimport = switch (nav_status) {
31715 const is_runtime = switch (nav_status) {
3168931716 .unresolved => unreachable,
3169031717 // dllimports go straight to `fully_resolved`; the only option is threadlocal
3169131718 .type_resolved => |r| r.is_threadlocal,
3169231719 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
31693 .@"extern" => |e| e.is_threadlocal or e.is_dll_import,
31720 .@"extern" => |e| e.is_threadlocal or e.is_dll_import or switch (e.relocation) {
31721 .any => false,
31722 .pcrel => true,
31723 },
3169431724 .variable => |v| v.is_threadlocal,
3169531725 else => false,
3169631726 },
......@@ -31699,7 +31729,7 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
3169931729 const ty, const alignment, const @"addrspace", const is_const = switch (nav_status) {
3170031730 .unresolved => unreachable,
3170131731 .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },
31702 .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", zcu.navValIsConst(r.val) },
31732 .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", r.is_const },
3170331733 };
3170431734 const ptr_ty = try pt.ptrTypeSema(.{
3170531735 .child = ty,
......@@ -31710,10 +31740,10 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
3171031740 },
3171131741 });
3171231742
31713 if (is_tlv_or_dllimport) {
31743 if (is_runtime) {
3171431744 // This pointer is runtime-known; we need to emit an AIR instruction to create it.
3171531745 return block.addInst(.{
31716 .tag = .tlv_dllimport_ptr,
31746 .tag = .runtime_nav_ptr,
3171731747 .data = .{ .ty_nav = .{
3171831748 .ty = ptr_ty.toIntern(),
3171931749 .nav = nav_index,
......@@ -32508,11 +32538,11 @@ fn analyzeSlice(
3250832538 const actual_len = if (array_ty.zigTypeTag(zcu) == .array)
3250932539 try pt.intRef(.usize, array_ty.arrayLenIncludingSentinel(zcu))
3251032540 else if (slice_ty.isSlice(zcu)) l: {
32511 const slice_len_inst = try block.addTyOp(.slice_len, .usize, ptr_or_slice);
32541 const slice_len = try sema.analyzeSliceLen(block, src, ptr_or_slice);
3251232542 break :l if (slice_ty.sentinel(zcu) == null)
32513 slice_len_inst
32543 slice_len
3251432544 else
32515 try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true);
32545 try sema.analyzeArithmetic(block, .add, slice_len, .one, src, end_src, end_src, true);
3251632546 } else break :bounds_check;
3251732547
3251832548 const actual_end = if (slice_sentinel != null)
......@@ -36432,6 +36462,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3643236462 .float_c_longdouble_f128,
3643336463 .float_comptime_float,
3643436464 .variable,
36465 .threadlocal_variable,
3643536466 .@"extern",
3643636467 .func_decl,
3643736468 .func_instance,
src/Zcu.zig+3-9
......@@ -2047,6 +2047,7 @@ pub const SrcLoc = struct {
20472047 .init_field_library,
20482048 .init_field_thread_local,
20492049 .init_field_dll_import,
2050 .init_field_relocation,
20502051 => |builtin_call_node| {
20512052 const wanted = switch (src_loc.lazy) {
20522053 .init_field_name => "name",
......@@ -2059,6 +2060,7 @@ pub const SrcLoc = struct {
20592060 .init_field_library => "library",
20602061 .init_field_thread_local => "thread_local",
20612062 .init_field_dll_import => "dll_import",
2063 .init_field_relocation => "relocation",
20622064 else => unreachable,
20632065 };
20642066 const tree = try src_loc.file_scope.getTree(zcu);
......@@ -2506,6 +2508,7 @@ pub const LazySrcLoc = struct {
25062508 init_field_library: Ast.Node.Offset,
25072509 init_field_thread_local: Ast.Node.Offset,
25082510 init_field_dll_import: Ast.Node.Offset,
2511 init_field_relocation: Ast.Node.Offset,
25092512 /// The source location points to the value of an item in a specific
25102513 /// case of a `switch`.
25112514 switch_case_item: SwitchItem,
......@@ -4562,15 +4565,6 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu
45624565 return .ok;
45634566}
45644567
4565/// Given that a `Nav` has value `val`, determine if a ref of that `Nav` gives a `const` pointer.
4566pub fn navValIsConst(zcu: *const Zcu, val: InternPool.Index) bool {
4567 return switch (zcu.intern_pool.indexToKey(val)) {
4568 .variable => false,
4569 .@"extern" => |e| e.is_const,
4570 else => true,
4571 };
4572}
4573
45744568pub const CodegenFailError = error{
45754569 /// Indicates the error message has been already stored at `Zcu.failed_codegen`.
45764570 CodegenFail,
src/Zcu/PerThread.zig+29-21
......@@ -1153,18 +1153,23 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
11531153 // First, we must resolve the declaration's type. To do this, we analyze the type body if available,
11541154 // or otherwise, we analyze the value body, populating `early_val` in the process.
11551155
1156 switch (zir_decl.kind) {
1156 const is_const = is_const: switch (zir_decl.kind) {
11571157 .@"comptime" => unreachable, // this is not a Nav
1158 .unnamed_test, .@"test", .decltest => assert(nav_ty.zigTypeTag(zcu) == .@"fn"),
1159 .@"usingnamespace" => {},
1160 .@"const" => {},
1161 .@"var" => try sema.validateVarType(
1162 &block,
1163 if (zir_decl.type_body != null) ty_src else init_src,
1164 nav_ty,
1165 zir_decl.linkage == .@"extern",
1166 ),
1167 }
1158 .unnamed_test, .@"test", .decltest => {
1159 assert(nav_ty.zigTypeTag(zcu) == .@"fn");
1160 break :is_const true;
1161 },
1162 .@"usingnamespace", .@"const" => true,
1163 .@"var" => {
1164 try sema.validateVarType(
1165 &block,
1166 if (zir_decl.type_body != null) ty_src else init_src,
1167 nav_ty,
1168 zir_decl.linkage == .@"extern",
1169 );
1170 break :is_const false;
1171 },
1172 };
11681173
11691174 // Now that we know the type, we can evaluate the alignment, linksection, and addrspace, to determine
11701175 // the full pointer type of this declaration.
......@@ -1195,7 +1200,6 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
11951200 .init = final_val.?.toIntern(),
11961201 .owner_nav = nav_id,
11971202 .is_threadlocal = zir_decl.is_threadlocal,
1198 .is_weak_linkage = false,
11991203 } })),
12001204 else => final_val.?,
12011205 },
......@@ -1212,10 +1216,12 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
12121216 .name = old_nav.name,
12131217 .ty = nav_ty.toIntern(),
12141218 .lib_name = try ip.getOrPutStringOpt(gpa, pt.tid, lib_name, .no_embedded_nulls),
1215 .is_const = zir_decl.kind == .@"const",
12161219 .is_threadlocal = zir_decl.is_threadlocal,
1217 .is_weak_linkage = false,
1220 .linkage = .strong,
1221 .visibility = .default,
12181222 .is_dll_import = false,
1223 .relocation = .any,
1224 .is_const = is_const,
12191225 .alignment = modifiers.alignment,
12201226 .@"addrspace" = modifiers.@"addrspace",
12211227 .zir_index = old_nav.analysis.?.zir_index, // `declaration` instruction
......@@ -1243,6 +1249,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
12431249 }
12441250 ip.resolveNavValue(nav_id, .{
12451251 .val = nav_val.toIntern(),
1252 .is_const = is_const,
12461253 .alignment = .none,
12471254 .@"linksection" = .none,
12481255 .@"addrspace" = .generic,
......@@ -1286,6 +1293,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
12861293
12871294 ip.resolveNavValue(nav_id, .{
12881295 .val = nav_val.toIntern(),
1296 .is_const = is_const,
12891297 .alignment = modifiers.alignment,
12901298 .@"linksection" = modifiers.@"linksection",
12911299 .@"addrspace" = modifiers.@"addrspace",
......@@ -1515,8 +1523,6 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
15151523 // the pointer modifiers, i.e. alignment, linksection, addrspace.
15161524 const modifiers = try sema.resolveNavPtrModifiers(&block, zir_decl, inst_resolved.inst, resolved_ty);
15171525
1518 // Usually, we can infer this information from the resolved `Nav` value; see `Zcu.navValIsConst`.
1519 // However, since we don't have one, we need to quickly check the ZIR to figure this out.
15201526 const is_const = switch (zir_decl.kind) {
15211527 .@"comptime" => unreachable,
15221528 .unnamed_test, .@"test", .decltest, .@"usingnamespace", .@"const" => true,
......@@ -1542,7 +1548,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
15421548 r.alignment != modifiers.alignment or
15431549 r.@"linksection" != modifiers.@"linksection" or
15441550 r.@"addrspace" != modifiers.@"addrspace" or
1545 zcu.navValIsConst(r.val) != is_const or
1551 r.is_const != is_const or
15461552 (old_nav.getExtern(ip) != null) != is_extern_decl,
15471553 };
15481554
......@@ -1550,10 +1556,10 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
15501556
15511557 ip.resolveNavType(nav_id, .{
15521558 .type = resolved_ty.toIntern(),
1559 .is_const = is_const,
15531560 .alignment = modifiers.alignment,
15541561 .@"linksection" = modifiers.@"linksection",
15551562 .@"addrspace" = modifiers.@"addrspace",
1556 .is_const = is_const,
15571563 .is_threadlocal = zir_decl.is_threadlocal,
15581564 .is_extern_decl = is_extern_decl,
15591565 });
......@@ -1750,7 +1756,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: *A
17501756
17511757 if (build_options.enable_debug_extensions and comp.verbose_air) {
17521758 std.debug.print("# Begin Function AIR: {}:\n", .{nav.fqn.fmt(ip)});
1753 @import("../print_air.zig").dump(pt, air.*, liveness);
1759 air.dump(pt, liveness);
17541760 std.debug.print("# End Function AIR: {}\n\n", .{nav.fqn.fmt(ip)});
17551761 }
17561762
......@@ -3577,8 +3583,10 @@ pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!V
35773583 .lib_name = e.lib_name,
35783584 .is_const = e.is_const,
35793585 .is_threadlocal = e.is_threadlocal,
3580 .is_weak_linkage = e.is_weak_linkage,
3586 .linkage = e.linkage,
3587 .visibility = e.visibility,
35813588 .is_dll_import = e.is_dll_import,
3589 .relocation = e.relocation,
35823590 .alignment = e.alignment,
35833591 .@"addrspace" = e.@"addrspace",
35843592 .zir_index = e.zir_index,
......@@ -3954,7 +3962,7 @@ pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Err
39543962 const ty, const alignment, const @"addrspace", const is_const = switch (ip.getNav(nav_id).status) {
39553963 .unresolved => unreachable,
39563964 .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },
3957 .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", zcu.navValIsConst(r.val) },
3965 .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", r.is_const },
39583966 };
39593967 return pt.ptrType(.{
39603968 .child = ty,
src/arch/aarch64/CodeGen.zig+1-1
......@@ -880,7 +880,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
880880 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
881881 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
882882 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
883 .tlv_dllimport_ptr => return self.fail("TODO implement tlv_dllimport_ptr", .{}),
883 .runtime_nav_ptr => return self.fail("TODO implement runtime_nav_ptr", .{}),
884884
885885 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
886886 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
src/arch/arm/CodeGen.zig+1-1
......@@ -869,7 +869,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
869869 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
870870 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
871871 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
872 .tlv_dllimport_ptr => return self.fail("TODO implement tlv_dllimport_ptr", .{}),
872 .runtime_nav_ptr => return self.fail("TODO implement runtime_nav_ptr", .{}),
873873
874874 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
875875 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
src/arch/riscv64/CodeGen.zig+4-9
......@@ -1041,12 +1041,7 @@ fn formatAir(
10411041 _: std.fmt.FormatOptions,
10421042 writer: anytype,
10431043) @TypeOf(writer).Error!void {
1044 @import("../../print_air.zig").dumpInst(
1045 data.inst,
1046 data.func.pt,
1047 data.func.air,
1048 data.func.liveness,
1049 );
1044 data.func.air.dumpInst(data.inst, data.func.pt, data.func.liveness);
10501045}
10511046fn fmtAir(func: *Func, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {
10521047 return .{ .data = .{ .func = func, .inst = inst } };
......@@ -1656,7 +1651,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
16561651 .wrap_errunion_payload => try func.airWrapErrUnionPayload(inst),
16571652 .wrap_errunion_err => try func.airWrapErrUnionErr(inst),
16581653
1659 .tlv_dllimport_ptr => try func.airTlvDllimportPtr(inst),
1654 .runtime_nav_ptr => try func.airRuntimeNavPtr(inst),
16601655
16611656 .add_optimized,
16621657 .sub_optimized,
......@@ -3626,7 +3621,7 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void {
36263621 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
36273622}
36283623
3629fn airTlvDllimportPtr(func: *Func, inst: Air.Inst.Index) !void {
3624fn airRuntimeNavPtr(func: *Func, inst: Air.Inst.Index) !void {
36303625 const zcu = func.pt.zcu;
36313626 const ip = &zcu.intern_pool;
36323627 const ty_nav = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
......@@ -3641,7 +3636,7 @@ fn airTlvDllimportPtr(func: *Func, inst: Air.Inst.Index) !void {
36413636 break :sym sym;
36423637 }
36433638 break :sym try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav);
3644 } else return func.fail("TODO tlv_dllimport_ptr on {}", .{func.bin_file.tag});
3639 } else return func.fail("TODO runtime_nav_ptr on {}", .{func.bin_file.tag});
36453640
36463641 const dest_mcv = try func.allocRegOrMem(ptr_ty, inst, true);
36473642 if (dest_mcv.isRegister()) {
src/arch/sparc64/CodeGen.zig+1-1
......@@ -723,7 +723,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
723723 .is_named_enum_value => @panic("TODO implement is_named_enum_value"),
724724 .error_set_has_value => @panic("TODO implement error_set_has_value"),
725725 .vector_store_elem => @panic("TODO implement vector_store_elem"),
726 .tlv_dllimport_ptr => @panic("TODO implement tlv_dllimport_ptr"),
726 .runtime_nav_ptr => @panic("TODO implement runtime_nav_ptr"),
727727
728728 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
729729 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
src/arch/wasm/CodeGen.zig+2-2
......@@ -2057,7 +2057,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
20572057 .error_set_has_value => cg.airErrorSetHasValue(inst),
20582058 .frame_addr => cg.airFrameAddress(inst),
20592059
2060 .tlv_dllimport_ptr => cg.airTlvDllimportPtr(inst),
2060 .runtime_nav_ptr => cg.airRuntimeNavPtr(inst),
20612061
20622062 .assembly,
20632063 .is_err_ptr,
......@@ -7616,7 +7616,7 @@ fn airFrameAddress(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
76167616 return cg.finishAir(inst, .stack, &.{});
76177617}
76187618
7619fn airTlvDllimportPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7619fn airRuntimeNavPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
76207620 const ty_nav = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
76217621 const mod = cg.pt.zcu.navFileScope(cg.owner_nav).mod.?;
76227622 if (mod.single_threaded) {
src/arch/x86_64/CodeGen.zig+187-56
......@@ -274,6 +274,12 @@ pub const MCValue = union(enum) {
274274 load_symbol: bits.SymbolOffset,
275275 /// The address of the memory location not-yet-allocated by the linker.
276276 lea_symbol: bits.SymbolOffset,
277 /// The value is in memory at an address not-yet-allocated by the linker.
278 /// This must use a non-got pc-relative relocation.
279 load_pcrel: bits.SymbolOffset,
280 /// The address of the memory location not-yet-allocated by the linker.
281 /// This must use a non-got pc-relative relocation.
282 lea_pcrel: bits.SymbolOffset,
277283 /// The value is in memory at a constant offset from the address in a register.
278284 indirect: bits.RegisterOffset,
279285 /// The value is in memory.
......@@ -314,6 +320,7 @@ pub const MCValue = union(enum) {
314320 .eflags,
315321 .register_overflow,
316322 .lea_symbol,
323 .lea_pcrel,
317324 .lea_direct,
318325 .lea_got,
319326 .lea_frame,
......@@ -327,6 +334,7 @@ pub const MCValue = union(enum) {
327334 .register_quadruple,
328335 .memory,
329336 .load_symbol,
337 .load_pcrel,
330338 .load_got,
331339 .load_direct,
332340 .indirect,
......@@ -429,6 +437,7 @@ pub const MCValue = union(enum) {
429437 .register_overflow,
430438 .register_mask,
431439 .lea_symbol,
440 .lea_pcrel,
432441 .lea_direct,
433442 .lea_got,
434443 .lea_frame,
......@@ -445,6 +454,7 @@ pub const MCValue = union(enum) {
445454 .load_got => |sym_index| .{ .lea_got = sym_index },
446455 .load_frame => |frame_addr| .{ .lea_frame = frame_addr },
447456 .load_symbol => |sym_off| .{ .lea_symbol = sym_off },
457 .load_pcrel => |sym_off| .{ .lea_pcrel = sym_off },
448458 };
449459 }
450460
......@@ -466,6 +476,7 @@ pub const MCValue = union(enum) {
466476 .load_got,
467477 .load_frame,
468478 .load_symbol,
479 .load_pcrel,
469480 .elementwise_args,
470481 .reserved_frame,
471482 .air_ref,
......@@ -477,6 +488,7 @@ pub const MCValue = union(enum) {
477488 .lea_got => |sym_index| .{ .load_got = sym_index },
478489 .lea_frame => |frame_addr| .{ .load_frame = frame_addr },
479490 .lea_symbol => |sym_index| .{ .load_symbol = sym_index },
491 .lea_pcrel => |sym_index| .{ .load_pcrel = sym_index },
480492 };
481493 }
482494
......@@ -505,6 +517,8 @@ pub const MCValue = union(enum) {
505517 .load_frame,
506518 .load_symbol,
507519 .lea_symbol,
520 .load_pcrel,
521 .lea_pcrel,
508522 => switch (off) {
509523 0 => mcv,
510524 else => unreachable, // not offsettable
......@@ -543,6 +557,7 @@ pub const MCValue = union(enum) {
543557 .elementwise_args,
544558 .reserved_frame,
545559 .lea_symbol,
560 .lea_pcrel,
546561 => unreachable,
547562 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| .{
548563 .base = .{ .reg = .ds },
......@@ -583,6 +598,18 @@ pub const MCValue = union(enum) {
583598 } },
584599 };
585600 },
601 .load_pcrel => |sym_off| {
602 assert(sym_off.off == 0);
603 return .{
604 .base = .{ .pcrel = sym_off.sym_index },
605 .mod = .{ .rm = .{
606 .size = mod_rm.size,
607 .index = mod_rm.index,
608 .scale = mod_rm.scale,
609 .disp = sym_off.off + mod_rm.disp,
610 } },
611 };
612 },
586613 .air_ref => |ref| (try function.resolveInst(ref)).mem(function, mod_rm),
587614 };
588615 }
......@@ -618,6 +645,8 @@ pub const MCValue = union(enum) {
618645 }),
619646 .load_symbol => |pl| try writer.print("[sym:{} + 0x{x}]", .{ pl.sym_index, pl.off }),
620647 .lea_symbol => |pl| try writer.print("sym:{} + 0x{x}", .{ pl.sym_index, pl.off }),
648 .load_pcrel => |pl| try writer.print("[sym@pcrel:{} + 0x{x}]", .{ pl.sym_index, pl.off }),
649 .lea_pcrel => |pl| try writer.print("sym@pcrel:{} + 0x{x}", .{ pl.sym_index, pl.off }),
621650 .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),
622651 .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}),
623652 .lea_direct => |pl| try writer.print("direct:{d}", .{pl}),
......@@ -655,6 +684,8 @@ const InstTracking = struct {
655684 .lea_frame,
656685 .load_symbol,
657686 .lea_symbol,
687 .load_pcrel,
688 .lea_pcrel,
658689 => result,
659690 .dead,
660691 .elementwise_args,
......@@ -755,6 +786,8 @@ const InstTracking = struct {
755786 .lea_frame,
756787 .load_symbol,
757788 .lea_symbol,
789 .load_pcrel,
790 .lea_pcrel,
758791 => assert(std.meta.eql(self.long, target.long)),
759792 .dead,
760793 .eflags,
......@@ -1228,12 +1261,7 @@ fn formatAir(
12281261 _: std.fmt.FormatOptions,
12291262 writer: anytype,
12301263) @TypeOf(writer).Error!void {
1231 @import("../../print_air.zig").dumpInst(
1232 data.inst,
1233 data.self.pt,
1234 data.self.air,
1235 data.self.liveness,
1236 );
1264 data.self.air.dumpInst(data.inst, data.self.pt, data.self.liveness);
12371265}
12381266fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {
12391267 return .{ .data = .{ .self = self, .inst = inst } };
......@@ -161477,10 +161505,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
161477161505 for (elems, 0..) |elem_ref, field_index| {
161478161506 const elem_dies = bt.feed();
161479161507 if (loaded_struct.fieldIsComptime(ip, field_index)) continue;
161480 var elem = try cg.tempFromOperand(elem_ref, elem_dies);
161481 try res.write(&elem, .{ .disp = @intCast(loaded_struct.offsets.get(ip)[field_index]) }, cg);
161482 try elem.die(cg);
161483 try cg.resetTemps(reset_index);
161508 if (!hack_around_sema_opv_bugs or Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]).hasRuntimeBitsIgnoreComptime(zcu)) {
161509 var elem = try cg.tempFromOperand(elem_ref, elem_dies);
161510 try res.write(&elem, .{ .disp = @intCast(loaded_struct.offsets.get(ip)[field_index]) }, cg);
161511 try elem.die(cg);
161512 try cg.resetTemps(reset_index);
161513 }
161484161514 }
161485161515 },
161486161516 .@"packed" => return cg.fail("failed to select {s} {}", .{
......@@ -163487,31 +163517,49 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
163487163517 };
163488163518 for (ops) |op| try op.die(cg);
163489163519 },
163490 .tlv_dllimport_ptr => switch (cg.bin_file.tag) {
163520 .runtime_nav_ptr => switch (cg.bin_file.tag) {
163491163521 .elf, .macho => {
163492163522 const ty_nav = air_datas[@intFromEnum(inst)].ty_nav;
163493163523
163494163524 const nav = ip.getNav(ty_nav.nav);
163495 const tlv_sym_index = sym: {
163525 const sym_index, const relocation = sym: {
163496163526 if (cg.bin_file.cast(.elf)) |elf_file| {
163497163527 const zo = elf_file.zigObjectPtr().?;
163498163528 if (nav.getExtern(ip)) |e| {
163499163529 const sym = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip));
163500 zo.symbol(sym).flags.is_extern_ptr = true;
163501 break :sym sym;
163502 }
163503 break :sym try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav);
163504 }
163505 if (cg.bin_file.cast(.macho)) |macho_file| {
163530 linkage: switch (e.linkage) {
163531 .internal => {},
163532 .strong => switch (e.visibility) {
163533 .default => zo.symbol(sym).flags.is_extern_ptr = true,
163534 .hidden, .protected => {},
163535 },
163536 .weak => {
163537 zo.symbol(sym).flags.weak = true;
163538 continue :linkage .strong;
163539 },
163540 .link_once => unreachable,
163541 }
163542 break :sym .{ sym, e.relocation };
163543 } else break :sym .{ try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav), .any };
163544 } else if (cg.bin_file.cast(.macho)) |macho_file| {
163506163545 const zo = macho_file.getZigObject().?;
163507163546 if (nav.getExtern(ip)) |e| {
163508163547 const sym = try macho_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip));
163509 zo.symbols.items[sym].flags.is_extern_ptr = true;
163510 break :sym sym;
163511 }
163512 break :sym try zo.getOrCreateMetadataForNav(macho_file, ty_nav.nav);
163513 }
163514 unreachable;
163548 linkage: switch (e.linkage) {
163549 .internal => {},
163550 .strong => switch (e.visibility) {
163551 .default => zo.symbols.items[sym].flags.is_extern_ptr = true,
163552 .hidden, .protected => {},
163553 },
163554 .weak => {
163555 zo.symbols.items[sym].flags.weak = true;
163556 continue :linkage .strong;
163557 },
163558 .link_once => unreachable,
163559 }
163560 break :sym .{ sym, e.relocation };
163561 } else break :sym .{ try zo.getOrCreateMetadataForNav(macho_file, ty_nav.nav), .any };
163562 } else unreachable;
163515163563 };
163516163564
163517163565 if (cg.mod.pic) {
......@@ -163520,13 +163568,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
163520163568 try cg.spillRegisters(&.{.rax});
163521163569 }
163522163570
163523 var slot = try cg.tempInit(.usize, .{ .lea_symbol = .{
163524 .sym_index = tlv_sym_index,
163525 } });
163571 var slot = try cg.tempInit(.usize, switch (relocation) {
163572 .any => .{ .lea_symbol = .{ .sym_index = sym_index } },
163573 .pcrel => .{ .lea_pcrel = .{ .sym_index = sym_index } },
163574 });
163526163575 while (try slot.toRegClass(true, .general_purpose, cg)) {}
163527163576 try slot.finish(inst, &.{}, &.{}, cg);
163528163577 },
163529 else => return cg.fail("TODO implement tlv/dllimport on {}", .{cg.bin_file.tag}),
163578 else => return cg.fail("TODO implement runtime_nav_ptr on {}", .{cg.bin_file.tag}),
163530163579 },
163531163580 .c_va_arg => try cg.airVaArg(inst),
163532163581 .c_va_copy => try cg.airVaCopy(inst),
......@@ -169189,6 +169238,7 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE
169189169238 .register,
169190169239 .register_offset,
169191169240 .lea_symbol,
169241 .lea_pcrel,
169192169242 .lea_direct,
169193169243 .lea_got,
169194169244 .lea_frame,
......@@ -169196,6 +169246,7 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE
169196169246 .memory,
169197169247 .indirect,
169198169248 .load_symbol,
169249 .load_pcrel,
169199169250 .load_direct,
169200169251 .load_got,
169201169252 .load_frame,
......@@ -169407,6 +169458,7 @@ fn store(
169407169458 .register,
169408169459 .register_offset,
169409169460 .lea_symbol,
169461 .lea_pcrel,
169410169462 .lea_direct,
169411169463 .lea_got,
169412169464 .lea_frame,
......@@ -169414,6 +169466,7 @@ fn store(
169414169466 .memory,
169415169467 .indirect,
169416169468 .load_symbol,
169469 .load_pcrel,
169417169470 .load_direct,
169418169471 .load_got,
169419169472 .load_frame,
......@@ -169883,6 +169936,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
169883169936 .register_overflow,
169884169937 .register_mask,
169885169938 .lea_symbol,
169939 .lea_pcrel,
169886169940 .lea_direct,
169887169941 .lea_got,
169888169942 .lea_frame,
......@@ -169892,7 +169946,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
169892169946 => unreachable, // unmodifiable destination
169893169947 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
169894169948 .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented
169895 .memory, .load_symbol, .load_got, .load_direct => {
169949 .memory, .load_symbol, .load_pcrel, .load_got, .load_direct => {
169896169950 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
169897169951 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
169898169952 defer self.register_manager.unlockReg(addr_reg_lock);
......@@ -171552,6 +171606,8 @@ fn genBinOp(
171552171606 .register_mask,
171553171607 .load_symbol,
171554171608 .lea_symbol,
171609 .load_pcrel,
171610 .lea_pcrel,
171555171611 .load_direct,
171556171612 .lea_direct,
171557171613 .load_got,
......@@ -172740,6 +172796,7 @@ fn genBinOpMir(
172740172796 .lea_got,
172741172797 .lea_frame,
172742172798 .lea_symbol,
172799 .lea_pcrel,
172743172800 .elementwise_args,
172744172801 .reserved_frame,
172745172802 .air_ref,
......@@ -172831,6 +172888,8 @@ fn genBinOpMir(
172831172888 .indirect,
172832172889 .load_symbol,
172833172890 .lea_symbol,
172891 .load_pcrel,
172892 .lea_pcrel,
172834172893 .load_direct,
172835172894 .lea_direct,
172836172895 .load_got,
......@@ -172906,7 +172965,7 @@ fn genBinOpMir(
172906172965 }
172907172966 }
172908172967 },
172909 .memory, .indirect, .load_symbol, .load_got, .load_direct, .load_frame => {
172968 .memory, .indirect, .load_symbol, .load_pcrel, .load_got, .load_direct, .load_frame => {
172910172969 const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock };
172911172970 const limb_abi_size: u32 = @min(abi_size, 8);
172912172971
......@@ -172953,8 +173012,9 @@ fn genBinOpMir(
172953173012 .load_frame,
172954173013 .lea_frame,
172955173014 .lea_symbol,
173015 .lea_pcrel,
172956173016 => null,
172957 .memory, .load_symbol, .load_got, .load_direct => src: {
173017 .memory, .load_symbol, .load_pcrel, .load_got, .load_direct => src: {
172958173018 switch (resolved_src_mcv) {
172959173019 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr))) != null and
172960173020 std.math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null)
......@@ -173093,6 +173153,8 @@ fn genBinOpMir(
173093173153 .indirect,
173094173154 .load_symbol,
173095173155 .lea_symbol,
173156 .load_pcrel,
173157 .lea_pcrel,
173096173158 .load_direct,
173097173159 .lea_direct,
173098173160 .load_got,
......@@ -173160,6 +173222,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
173160173222 .register_overflow,
173161173223 .register_mask,
173162173224 .lea_symbol,
173225 .lea_pcrel,
173163173226 .lea_direct,
173164173227 .lea_got,
173165173228 .lea_frame,
......@@ -173222,6 +173285,8 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
173222173285 .eflags,
173223173286 .load_symbol,
173224173287 .lea_symbol,
173288 .load_pcrel,
173289 .lea_pcrel,
173225173290 .load_direct,
173226173291 .lea_direct,
173227173292 .load_got,
......@@ -173281,7 +173346,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
173281173346 }
173282173347 },
173283173348 .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented
173284 .memory, .indirect, .load_symbol, .load_direct, .load_got, .load_frame => {
173349 .memory, .indirect, .load_symbol, .load_pcrel, .load_direct, .load_got, .load_frame => {
173285173350 const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
173286173351 const tmp_mcv = MCValue{ .register = tmp_reg };
173287173352 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
......@@ -173450,7 +173515,8 @@ fn genLocalDebugInfo(
173450173515 .disp = frame_addr.off,
173451173516 } },
173452173517 }),
173453 .lea_symbol => |sym_off| try self.asmAirMemory(.dbg_local, inst, .{
173518 // debug info should explicitly ignore pcrel requirements
173519 .lea_symbol, .lea_pcrel => |sym_off| try self.asmAirMemory(.dbg_local, inst, .{
173454173520 .base = .{ .reloc = sym_off.sym_index },
173455173521 .mod = .{ .rm = .{
173456173522 .size = .qword,
......@@ -174108,12 +174174,13 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174108174174 .lea_got,
174109174175 .lea_frame,
174110174176 .lea_symbol,
174177 .lea_pcrel,
174111174178 .elementwise_args,
174112174179 .reserved_frame,
174113174180 .air_ref,
174114174181 => unreachable,
174115174182 .register, .register_pair, .register_triple, .register_quadruple, .load_frame => null,
174116 .memory, .load_symbol, .load_got, .load_direct => dst: {
174183 .memory, .load_symbol, .load_pcrel, .load_got, .load_direct => dst: {
174117174184 switch (resolved_dst_mcv) {
174118174185 .memory => |addr| if (std.math.cast(
174119174186 i32,
......@@ -174122,7 +174189,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174122174189 i32,
174123174190 @as(i64, @bitCast(addr)) + abi_size - 8,
174124174191 ) != null) break :dst null,
174125 .load_symbol, .load_got, .load_direct => {},
174192 .load_symbol, .load_pcrel, .load_got, .load_direct => {},
174126174193 else => unreachable,
174127174194 }
174128174195
......@@ -174160,6 +174227,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174160174227 .register_mask,
174161174228 .indirect,
174162174229 .lea_symbol,
174230 .lea_pcrel,
174163174231 .lea_direct,
174164174232 .lea_got,
174165174233 .lea_frame,
......@@ -174168,7 +174236,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174168174236 .air_ref,
174169174237 => unreachable,
174170174238 .register_pair, .register_triple, .register_quadruple, .load_frame => null,
174171 .memory, .load_symbol, .load_got, .load_direct => src: {
174239 .memory, .load_symbol, .load_pcrel, .load_got, .load_direct => src: {
174172174240 switch (resolved_src_mcv) {
174173174241 .memory => |addr| if (std.math.cast(
174174174242 i32,
......@@ -174177,7 +174245,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174177174245 i32,
174178174246 @as(i64, @bitCast(addr)) + abi_size - 8,
174179174247 ) != null) break :src null,
174180 .load_symbol, .load_got, .load_direct => {},
174248 .load_symbol, .load_pcrel, .load_got, .load_direct => {},
174181174249 else => unreachable,
174182174250 }
174183174251
......@@ -174568,6 +174636,7 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)
174568174636 .lea_direct,
174569174637 .lea_got,
174570174638 .lea_symbol,
174639 .lea_pcrel,
174571174640 .elementwise_args,
174572174641 .reserved_frame,
174573174642 .air_ref,
......@@ -174616,6 +174685,7 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)
174616174685
174617174686 .memory,
174618174687 .load_symbol,
174688 .load_pcrel,
174619174689 .load_got,
174620174690 .load_direct,
174621174691 => {
......@@ -174947,8 +175017,7 @@ fn lowerSwitchBr(
174947175017) !void {
174948175018 const zcu = cg.pt.zcu;
174949175019 const condition_ty = cg.typeOf(switch_br.operand);
174950 const condition_int_info = cg.intInfo(condition_ty).?;
174951 const condition_int_ty = try cg.pt.intType(condition_int_info.signedness, condition_int_info.bits);
175020 const unsigned_condition_ty = try cg.pt.intType(.unsigned, cg.intInfo(condition_ty).?.bits);
174952175021
174953175022 const ExpectedContents = extern struct {
174954175023 liveness_deaths: [1 << 8 | 1]Air.Inst.Index,
......@@ -175019,8 +175088,8 @@ fn lowerSwitchBr(
175019175088 .{ .air_ref = Air.internedToRef(min.?.toIntern()) },
175020175089 );
175021175090 const else_reloc = if (switch_br.else_body_len > 0) else_reloc: {
175022 var cond_temp = try cg.tempInit(condition_ty, condition_index);
175023 var table_max_temp = try cg.tempFromValue(try cg.pt.intValue(condition_int_ty, table_len - 1));
175091 var cond_temp = try cg.tempInit(unsigned_condition_ty, condition_index);
175092 var table_max_temp = try cg.tempFromValue(try cg.pt.intValue(unsigned_condition_ty, table_len - 1));
175024175093 const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, cg) catch |err| switch (err) {
175025175094 error.SelectFailed => unreachable,
175026175095 else => |e| return e,
......@@ -175348,8 +175417,7 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void {
175348175417
175349175418 if (self.loop_switches.getPtr(br.block_inst)) |table| {
175350175419 const condition_ty = self.typeOf(br.operand);
175351 const condition_int_info = self.intInfo(condition_ty).?;
175352 const condition_int_ty = try self.pt.intType(condition_int_info.signedness, condition_int_info.bits);
175420 const unsigned_condition_ty = try self.pt.intType(.unsigned, self.intInfo(condition_ty).?.bits);
175353175421 const condition_mcv = block_tracking.short;
175354175422 try self.spillEflagsIfOccupied();
175355175423 if (table.min.orderAgainstZero(self.pt.zcu).compare(.neq)) try self.genBinOpMir(
......@@ -175361,8 +175429,8 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void {
175361175429 switch (table.else_relocs) {
175362175430 .@"unreachable" => {},
175363175431 .forward => |*else_relocs| {
175364 var cond_temp = try self.tempInit(condition_ty, condition_mcv);
175365 var table_max_temp = try self.tempFromValue(try self.pt.intValue(condition_int_ty, table.len - 1));
175432 var cond_temp = try self.tempInit(unsigned_condition_ty, condition_mcv);
175433 var table_max_temp = try self.tempFromValue(try self.pt.intValue(unsigned_condition_ty, table.len - 1));
175366175434 const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, self) catch |err| switch (err) {
175367175435 error.SelectFailed => unreachable,
175368175436 else => |e| return e,
......@@ -175373,8 +175441,8 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void {
175373175441 try cc_temp.die(self);
175374175442 },
175375175443 .backward => |else_reloc| {
175376 var cond_temp = try self.tempInit(condition_ty, condition_mcv);
175377 var table_max_temp = try self.tempFromValue(try self.pt.intValue(condition_int_ty, table.len - 1));
175444 var cond_temp = try self.tempInit(unsigned_condition_ty, condition_mcv);
175445 var table_max_temp = try self.tempFromValue(try self.pt.intValue(unsigned_condition_ty, table.len - 1));
175378175446 const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, self) catch |err| switch (err) {
175379175447 error.SelectFailed => unreachable,
175380175448 else => |e| return e,
......@@ -176625,6 +176693,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
176625176693 .lea_got,
176626176694 .lea_frame,
176627176695 .lea_symbol,
176696 .lea_pcrel,
176628176697 .elementwise_args,
176629176698 .reserved_frame,
176630176699 .air_ref,
......@@ -176719,7 +176788,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
176719176788 }
176720176789 return;
176721176790 },
176722 .load_symbol, .load_direct, .load_got => {
176791 .load_symbol, .load_pcrel, .load_direct, .load_got => {
176723176792 const src_addr_reg =
176724176793 (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
176725176794 const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);
......@@ -176752,7 +176821,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
176752176821 .undef => if (opts.safety and part_i > 0) .{ .register = dst_regs[0] } else .undef,
176753176822 dst_tag => |src_regs| .{ .register = src_regs[part_i] },
176754176823 .memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(),
176755 .load_symbol, .load_direct, .load_got => .{ .indirect = .{
176824 .load_symbol, .load_pcrel, .load_direct, .load_got => .{ .indirect = .{
176756176825 .reg = src_info.?.addr_reg,
176757176826 .off = part_disp,
176758176827 } },
......@@ -176773,11 +176842,11 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
176773176842 src_mcv,
176774176843 opts,
176775176844 ),
176776 .memory, .load_symbol, .load_direct, .load_got => {
176845 .memory, .load_symbol, .load_pcrel, .load_direct, .load_got => {
176777176846 switch (dst_mcv) {
176778176847 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
176779176848 return self.genSetMem(.{ .reg = .ds }, small_addr, ty, src_mcv, opts),
176780 .load_symbol, .load_direct, .load_got => {},
176849 .load_symbol, .load_pcrel, .load_direct, .load_got => {},
176781176850 else => unreachable,
176782176851 }
176783176852
......@@ -177234,7 +177303,7 @@ fn genSetReg(
177234177303 if (src_reg_mask.info.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size));
177235177304 try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{});
177236177305 },
177237 .memory, .load_symbol, .load_direct, .load_got => {
177306 .memory, .load_symbol, .load_pcrel, .load_direct, .load_got => {
177238177307 switch (src_mcv) {
177239177308 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
177240177309 return (try self.moveStrategy(
......@@ -177263,6 +177332,21 @@ fn genSetReg(
177263177332 .segment, .mmx, .ip, .cr, .dr => unreachable,
177264177333 .x87, .sse => {},
177265177334 },
177335 .load_pcrel => |sym_off| switch (dst_reg.class()) {
177336 .general_purpose, .gphi => {
177337 assert(sym_off.off == 0);
177338 try self.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{
177339 .base = .{ .pcrel = sym_off.sym_index },
177340 .mod = .{ .rm = .{
177341 .size = self.memSize(ty),
177342 .disp = sym_off.off,
177343 } },
177344 });
177345 return;
177346 },
177347 .segment, .mmx, .ip, .cr, .dr => unreachable,
177348 .x87, .sse => {},
177349 },
177266177350 .load_direct => |sym_index| switch (dst_reg.class()) {
177267177351 .general_purpose, .gphi => {
177268177352 _ = try self.addInst(.{
......@@ -177313,6 +177397,28 @@ fn genSetReg(
177313177397 @tagName(self.bin_file.tag),
177314177398 }),
177315177399 },
177400 .lea_pcrel => |sym_off| switch (self.bin_file.tag) {
177401 .elf, .macho => {
177402 try self.asmRegisterMemory(
177403 .{ ._, .lea },
177404 dst_reg.to64(),
177405 .{
177406 .base = .{ .pcrel = sym_off.sym_index },
177407 },
177408 );
177409 if (sym_off.off != 0) try self.asmRegisterMemory(
177410 .{ ._, .lea },
177411 dst_reg.to64(),
177412 .{
177413 .base = .{ .reg = dst_reg.to64() },
177414 .mod = .{ .rm = .{ .disp = sym_off.off } },
177415 },
177416 );
177417 },
177418 else => return self.fail("TODO emit symbol sequence on {s}", .{
177419 @tagName(self.bin_file.tag),
177420 }),
177421 },
177316177422 .lea_direct, .lea_got => |sym_index| _ = try self.addInst(.{
177317177423 .tag = switch (src_mcv) {
177318177424 .lea_direct => .lea,
......@@ -177350,6 +177456,7 @@ fn genSetMem(
177350177456 .frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } },
177351177457 .table, .rip_inst => unreachable,
177352177458 .reloc => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index, .off = disp } },
177459 .pcrel => |sym_index| .{ .lea_pcrel = .{ .sym_index = sym_index, .off = disp } },
177353177460 };
177354177461 switch (src_mcv) {
177355177462 .none,
......@@ -177466,7 +177573,7 @@ fn genSetMem(
177466177573 .off = disp,
177467177574 }).compare(.gte, src_align),
177468177575 .table, .rip_inst => unreachable,
177469 .reloc => false,
177576 .reloc, .pcrel => false,
177470177577 })).write(
177471177578 self,
177472177579 .{ .base = base, .mod = .{ .rm = .{
......@@ -177557,6 +177664,8 @@ fn genSetMem(
177557177664 .lea_frame,
177558177665 .load_symbol,
177559177666 .lea_symbol,
177667 .load_pcrel,
177668 .lea_pcrel,
177560177669 => switch (abi_size) {
177561177670 0 => {},
177562177671 1, 2, 4, 8 => {
......@@ -178110,7 +178219,7 @@ fn airCmpxchg(self: *CodeGen, inst: Air.Inst.Index) !void {
178110178219 .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
178111178220 }
178112178221 const ptr_lock = switch (ptr_mem.base) {
178113 .none, .frame, .reloc => null,
178222 .none, .frame, .reloc, .pcrel => null,
178114178223 .reg => |reg| self.register_manager.lockReg(reg),
178115178224 .table, .rip_inst => unreachable,
178116178225 };
......@@ -178193,7 +178302,7 @@ fn atomicOp(
178193178302 .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
178194178303 }
178195178304 const mem_lock = switch (ptr_mem.base) {
178196 .none, .frame, .reloc => null,
178305 .none, .frame, .reloc, .pcrel => null,
178197178306 .reg => |reg| self.register_manager.lockReg(reg),
178198178307 .table, .rip_inst => unreachable,
178199178308 };
......@@ -182266,6 +182375,8 @@ const Temp = struct {
182266182375 .memory,
182267182376 .load_symbol,
182268182377 .lea_symbol,
182378 .load_pcrel,
182379 .lea_pcrel,
182269182380 .indirect,
182270182381 .load_direct,
182271182382 .lea_direct,
......@@ -182427,6 +182538,22 @@ const Temp = struct {
182427182538 assert(limb_index == 0);
182428182539 new_temp_index.tracking(cg).* = .init(.{ .lea_symbol = sym_off });
182429182540 },
182541 .load_pcrel => |sym_off| {
182542 const new_reg =
182543 try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
182544 new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
182545 try cg.asmRegisterMemory(.{ ._, .mov }, new_reg.to64(), .{
182546 .base = .{ .pcrel = sym_off.sym_index },
182547 .mod = .{ .rm = .{
182548 .size = .qword,
182549 .disp = sym_off.off + @as(u31, limb_index) * 8,
182550 } },
182551 });
182552 },
182553 .lea_pcrel => |sym_off| {
182554 assert(limb_index == 0);
182555 new_temp_index.tracking(cg).* = .init(.{ .lea_pcrel = sym_off });
182556 },
182430182557 .load_frame => |frame_addr| {
182431182558 const new_reg =
182432182559 try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
......@@ -182721,11 +182848,12 @@ const Temp = struct {
182721182848 .memory,
182722182849 .indirect,
182723182850 .load_symbol,
182851 .load_pcrel,
182724182852 .load_direct,
182725182853 .load_got,
182726182854 .load_frame,
182727182855 => return temp.toRegClass(true, .general_purpose, cg),
182728 .lea_symbol => |sym_off| {
182856 .lea_symbol, .lea_pcrel => |sym_off| {
182729182857 const off = sym_off.off;
182730182858 // hack around linker relocation bugs
182731182859 if (false and off == 0) return false;
......@@ -187464,6 +187592,8 @@ const Temp = struct {
187464187592 .memory,
187465187593 .load_symbol,
187466187594 .lea_symbol,
187595 .load_pcrel,
187596 .lea_pcrel,
187467187597 .indirect,
187468187598 .load_direct,
187469187599 .lea_direct,
......@@ -190044,6 +190174,7 @@ const Select = struct {
190044190174 .register => |base_reg| .{ .reg = base_reg.toSize(.ptr, s.cg.target) },
190045190175 .register_offset => |base_reg_off| .{ .reg = base_reg_off.reg.toSize(.ptr, s.cg.target) },
190046190176 .lea_symbol => |base_sym_off| .{ .reloc = base_sym_off.sym_index },
190177 .lea_pcrel => |base_sym_off| .{ .pcrel = base_sym_off.sym_index },
190047190178 },
190048190179 .mod = .{ .rm = .{
190049190180 .size = op.flags.base.size,
src/arch/x86_64/Emit.zig+9-8
......@@ -189,12 +189,12 @@ pub fn emitMir(emit: *Emit) Error!void {
189189 .r_addend = lowered_relocs[0].off,
190190 }, zo);
191191 },
192 .linker_reloc => |sym_index| if (emit.lower.bin_file.cast(.elf)) |elf_file| {
192 .linker_reloc, .linker_pcrel => |sym_index| if (emit.lower.bin_file.cast(.elf)) |elf_file| {
193193 const zo = elf_file.zigObjectPtr().?;
194194 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
195195 const sym = zo.symbol(sym_index);
196196 if (emit.lower.pic) {
197 const r_type: u32 = if (sym.flags.is_extern_ptr)
197 const r_type: u32 = if (sym.flags.is_extern_ptr and lowered_relocs[0].target != .linker_pcrel)
198198 @intFromEnum(std.elf.R_X86_64.GOTPCREL)
199199 else
200200 @intFromEnum(std.elf.R_X86_64.PC32);
......@@ -218,7 +218,7 @@ pub fn emitMir(emit: *Emit) Error!void {
218218 const zo = macho_file.getZigObject().?;
219219 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;
220220 const sym = &zo.symbols.items[sym_index];
221 const @"type": link.File.MachO.Relocation.Type = if (sym.flags.is_extern_ptr)
221 const @"type": link.File.MachO.Relocation.Type = if (sym.flags.is_extern_ptr and lowered_relocs[0].target != .linker_pcrel)
222222 .got_load
223223 else if (sym.flags.tlv)
224224 .tlv
......@@ -378,9 +378,9 @@ pub fn emitMir(emit: *Emit) Error!void {
378378 };
379379 break :stack_value &loc_buf[0];
380380 } } },
381 .pseudo_dbg_local_as => .{ mir_inst.data.as.air_inst, .{ .addr = .{
382 .sym = mir_inst.data.as.sym_index,
383 } } },
381 .pseudo_dbg_local_as => .{ mir_inst.data.as.air_inst, .{
382 .addr_reloc = mir_inst.data.as.sym_index,
383 } },
384384 .pseudo_dbg_local_aso => loc: {
385385 const sym_off = emit.lower.mir.extraData(
386386 bits.SymbolOffset,
......@@ -388,7 +388,7 @@ pub fn emitMir(emit: *Emit) Error!void {
388388 ).data;
389389 break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{
390390 sym: {
391 loc_buf[0] = .{ .addr = .{ .sym = sym_off.sym_index } };
391 loc_buf[0] = .{ .addr_reloc = sym_off.sym_index };
392392 break :sym &loc_buf[0];
393393 },
394394 off: {
......@@ -437,7 +437,8 @@ pub fn emitMir(emit: *Emit) Error!void {
437437 .none => .{ .constu = 0 },
438438 .reg => |reg| .{ .breg = reg.dwarfNum() },
439439 .frame, .table, .rip_inst => unreachable,
440 .reloc => |sym_index| .{ .addr = .{ .sym = sym_index } },
440 .reloc => |sym_index| .{ .addr_reloc = sym_index },
441 .pcrel => unreachable,
441442 };
442443 break :base &loc_buf[0];
443444 },
src/arch/x86_64/Lower.zig+19-2
......@@ -66,6 +66,7 @@ pub const Reloc = struct {
6666 inst: Mir.Inst.Index,
6767 table,
6868 linker_reloc: u32,
69 linker_pcrel: u32,
6970 linker_tlsld: u32,
7071 linker_dtpoff: u32,
7172 linker_extern_fn: u32,
......@@ -421,9 +422,9 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
421422 for (emit_ops, ops, 0..) |*emit_op, op, op_index| {
422423 emit_op.* = switch (op) {
423424 else => op,
424 .mem => |mem_op| switch (mem_op.base()) {
425 .mem => |mem_op| op: switch (mem_op.base()) {
425426 else => op,
426 .reloc => |sym_index| op: {
427 .reloc => |sym_index| {
427428 assert(prefix == .none);
428429 assert(mem_op.sib.disp == 0);
429430 assert(mem_op.sib.scale_index.scale == 0);
......@@ -559,6 +560,22 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
559560 return lower.fail("TODO: bin format '{s}'", .{@tagName(lower.bin_file.tag)});
560561 }
561562 },
563 .pcrel => |sym_index| {
564 assert(prefix == .none);
565 assert(mem_op.sib.disp == 0);
566 assert(mem_op.sib.scale_index.scale == 0);
567
568 _ = lower.reloc(@intCast(op_index), .{ .linker_pcrel = sym_index }, 0);
569 break :op switch (lower.bin_file.tag) {
570 .elf => op,
571 .macho => switch (mnemonic) {
572 .lea => .{ .mem = Memory.initRip(.none, 0) },
573 .mov => .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) },
574 else => unreachable,
575 },
576 else => |tag| return lower.fail("TODO: bin format '{s}'", .{@tagName(tag)}),
577 };
578 },
562579 },
563580 };
564581 }
src/arch/x86_64/Mir.zig+3-2
......@@ -1866,7 +1866,7 @@ pub const Memory = struct {
18661866 .none, .table => undefined,
18671867 .reg => |reg| @intFromEnum(reg),
18681868 .frame => |frame_index| @intFromEnum(frame_index),
1869 .reloc => |sym_index| sym_index,
1869 .reloc, .pcrel => |sym_index| sym_index,
18701870 .rip_inst => |inst_index| inst_index,
18711871 },
18721872 .off = switch (mem.mod) {
......@@ -1895,6 +1895,7 @@ pub const Memory = struct {
18951895 .frame => .{ .frame = @enumFromInt(mem.base) },
18961896 .table => .table,
18971897 .reloc => .{ .reloc = mem.base },
1898 .pcrel => .{ .pcrel = mem.base },
18981899 .rip_inst => .{ .rip_inst = mem.base },
18991900 },
19001901 .scale_index = switch (mem.info.index) {
......@@ -1959,7 +1960,7 @@ pub fn resolveFrameAddr(mir: Mir, frame_addr: bits.FrameAddr) bits.RegisterOffse
19591960
19601961pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory {
19611962 return switch (mem.info.base) {
1962 .none, .reg, .table, .reloc, .rip_inst => mem,
1963 .none, .reg, .table, .reloc, .pcrel, .rip_inst => mem,
19631964 .frame => if (mir.frame_locs.len > 0) .{
19641965 .info = .{
19651966 .base = .reg,
src/arch/x86_64/bits.zig+1
......@@ -762,6 +762,7 @@ pub const Memory = struct {
762762 frame: FrameIndex,
763763 table,
764764 reloc: u32,
765 pcrel: u32,
765766 rip_inst: Mir.Inst.Index,
766767
767768 pub const Tag = @typeInfo(Base).@"union".tag_type.?;
src/arch/x86_64/encoder.zig+4-3
......@@ -138,7 +138,7 @@ pub const Instruction = struct {
138138 .moffs => true,
139139 .rip => false,
140140 .sib => |s| switch (s.base) {
141 .none, .frame, .table, .reloc, .rip_inst => false,
141 .none, .frame, .table, .reloc, .pcrel, .rip_inst => false,
142142 .reg => |reg| reg.isClass(.segment),
143143 },
144144 };
......@@ -211,7 +211,7 @@ pub const Instruction = struct {
211211 .none, .imm => 0b00,
212212 .reg => |reg| @truncate(reg.enc() >> 3),
213213 .mem => |mem| switch (mem.base()) {
214 .none, .frame, .table, .reloc, .rip_inst => 0b00, // rsp, rbp, and rip are not extended
214 .none, .frame, .table, .reloc, .pcrel, .rip_inst => 0b00, // rsp, rbp, and rip are not extended
215215 .reg => |reg| @truncate(reg.enc() >> 3),
216216 },
217217 .bytes => unreachable,
......@@ -282,6 +282,7 @@ pub const Instruction = struct {
282282 .frame => |frame_index| try writer.print("{}", .{frame_index}),
283283 .table => try writer.print("Table", .{}),
284284 .reloc => |sym_index| try writer.print("Symbol({d})", .{sym_index}),
285 .pcrel => |sym_index| try writer.print("PcRelSymbol({d})", .{sym_index}),
285286 .rip_inst => |inst_index| try writer.print("RipInst({d})", .{inst_index}),
286287 }
287288 if (mem.scaleIndex()) |si| {
......@@ -721,7 +722,7 @@ pub const Instruction = struct {
721722 try encoder.modRm_indirectDisp32(operand_enc, 0);
722723 try encoder.disp32(undefined);
723724 } else return error.CannotEncode,
724 .rip_inst => {
725 .pcrel, .rip_inst => {
725726 try encoder.modRm_RIPDisp32(operand_enc);
726727 try encoder.disp32(sib.disp);
727728 },
src/codegen.zig+57-24
......@@ -921,41 +921,74 @@ fn genNavRef(
921921 const nav = ip.getNav(nav_index);
922922 assert(!nav.isThreadlocal(ip));
923923
924 const is_extern, const lib_name = if (nav.getExtern(ip)) |e|
925 .{ true, e.lib_name }
924 const lib_name, const linkage, const visibility = if (nav.getExtern(ip)) |e|
925 .{ e.lib_name, e.linkage, e.visibility }
926926 else
927 .{ false, .none };
927 .{ .none, .internal, .default };
928928
929929 const name = nav.name;
930930 if (lf.cast(.elf)) |elf_file| {
931931 const zo = elf_file.zigObjectPtr().?;
932 if (is_extern) {
933 const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
934 zo.symbol(sym_index).flags.is_extern_ptr = true;
935 return .{ .mcv = .{ .lea_symbol = sym_index } };
932 switch (linkage) {
933 .internal => {
934 const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index);
935 return .{ .mcv = .{ .lea_symbol = sym_index } };
936 },
937 .strong, .weak => {
938 const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
939 switch (linkage) {
940 .internal => unreachable,
941 .strong => {},
942 .weak => zo.symbol(sym_index).flags.weak = true,
943 .link_once => unreachable,
944 }
945 switch (visibility) {
946 .default => zo.symbol(sym_index).flags.is_extern_ptr = true,
947 .hidden, .protected => {},
948 }
949 return .{ .mcv = .{ .lea_symbol = sym_index } };
950 },
951 .link_once => unreachable,
936952 }
937 const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index);
938 return .{ .mcv = .{ .lea_symbol = sym_index } };
939953 } else if (lf.cast(.macho)) |macho_file| {
940954 const zo = macho_file.getZigObject().?;
941 if (is_extern) {
942 const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
943 zo.symbols.items[sym_index].flags.is_extern_ptr = true;
944 return .{ .mcv = .{ .lea_symbol = sym_index } };
955 switch (linkage) {
956 .internal => {
957 const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);
958 const sym = zo.symbols.items[sym_index];
959 return .{ .mcv = .{ .lea_symbol = sym.nlist_idx } };
960 },
961 .strong, .weak => {
962 const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
963 switch (linkage) {
964 .internal => unreachable,
965 .strong => {},
966 .weak => zo.symbols.items[sym_index].flags.weak = true,
967 .link_once => unreachable,
968 }
969 switch (visibility) {
970 .default => zo.symbols.items[sym_index].flags.is_extern_ptr = true,
971 .hidden, .protected => {},
972 }
973 return .{ .mcv = .{ .lea_symbol = sym_index } };
974 },
975 .link_once => unreachable,
945976 }
946 const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);
947 const sym = zo.symbols.items[sym_index];
948 return .{ .mcv = .{ .lea_symbol = sym.nlist_idx } };
949977 } else if (lf.cast(.coff)) |coff_file| {
950 if (is_extern) {
951 // TODO audit this
952 const global_index = try coff_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
953 try coff_file.need_got_table.put(gpa, global_index, {}); // needs GOT
954 return .{ .mcv = .{ .load_got = link.File.Coff.global_symbol_bit | global_index } };
978 // TODO audit this
979 switch (linkage) {
980 .internal => {
981 const atom_index = try coff_file.getOrCreateAtomForNav(nav_index);
982 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
983 return .{ .mcv = .{ .load_got = sym_index } };
984 },
985 .strong, .weak => {
986 const global_index = try coff_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
987 try coff_file.need_got_table.put(gpa, global_index, {}); // needs GOT
988 return .{ .mcv = .{ .load_got = link.File.Coff.global_symbol_bit | global_index } };
989 },
990 .link_once => unreachable,
955991 }
956 const atom_index = try coff_file.getOrCreateAtomForNav(nav_index);
957 const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
958 return .{ .mcv = .{ .load_got = sym_index } };
959992 } else if (lf.cast(.plan9)) |p9| {
960993 const atom_index = try p9.seeNav(pt, nav_index);
961994 const atom = p9.getAtom(atom_index);
src/codegen/c.zig+22-12
......@@ -2255,19 +2255,30 @@ pub const DeclGen = struct {
22552255 fn renderFwdDecl(
22562256 dg: *DeclGen,
22572257 nav_index: InternPool.Nav.Index,
2258 flags: struct {
2259 is_extern: bool,
2258 flags: packed struct {
22602259 is_const: bool,
22612260 is_threadlocal: bool,
2262 is_weak_linkage: bool,
2261 linkage: std.builtin.GlobalLinkage,
2262 visibility: std.builtin.SymbolVisibility,
22632263 },
22642264 ) !void {
22652265 const zcu = dg.pt.zcu;
22662266 const ip = &zcu.intern_pool;
22672267 const nav = ip.getNav(nav_index);
22682268 const fwd = dg.fwdDeclWriter();
2269 try fwd.writeAll(if (flags.is_extern) "zig_extern " else "static ");
2270 if (flags.is_weak_linkage) try fwd.writeAll("zig_weak_linkage ");
2269 try fwd.writeAll(switch (flags.linkage) {
2270 .internal => "static ",
2271 .strong, .weak, .link_once => "zig_extern ",
2272 });
2273 switch (flags.linkage) {
2274 .internal, .strong => {},
2275 .weak => try fwd.writeAll("zig_weak_linkage "),
2276 .link_once => return dg.fail("TODO: CBE: implement linkonce linkage?", .{}),
2277 }
2278 switch (flags.linkage) {
2279 .internal => {},
2280 .strong, .weak, .link_once => try fwd.print("zig_visibility({s}) ", .{@tagName(flags.visibility)}),
2281 }
22712282 if (flags.is_threadlocal and !dg.mod.single_threaded) try fwd.writeAll("zig_threadlocal ");
22722283 try dg.renderTypeAndName(
22732284 fwd,
......@@ -2994,10 +3005,10 @@ pub fn genDecl(o: *Object) !void {
29943005 switch (ip.indexToKey(nav.status.fully_resolved.val)) {
29953006 .@"extern" => |@"extern"| {
29963007 if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{
2997 .is_extern = true,
29983008 .is_const = @"extern".is_const,
29993009 .is_threadlocal = @"extern".is_threadlocal,
3000 .is_weak_linkage = @"extern".is_weak_linkage,
3010 .linkage = @"extern".linkage,
3011 .visibility = @"extern".visibility,
30013012 });
30023013
30033014 const fwd = o.dg.fwdDeclWriter();
......@@ -3016,13 +3027,12 @@ pub fn genDecl(o: *Object) !void {
30163027 },
30173028 .variable => |variable| {
30183029 try o.dg.renderFwdDecl(o.dg.pass.nav, .{
3019 .is_extern = false,
30203030 .is_const = false,
30213031 .is_threadlocal = variable.is_threadlocal,
3022 .is_weak_linkage = variable.is_weak_linkage,
3032 .linkage = .internal,
3033 .visibility = .default,
30233034 });
30243035 const w = o.writer();
3025 if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
30263036 if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");
30273037 if (nav.status.fully_resolved.@"linksection".toSlice(&zcu.intern_pool)) |s|
30283038 try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
......@@ -3467,7 +3477,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
34673477 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
34683478 .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),
34693479
3470 .tlv_dllimport_ptr => try airTlvDllimportPtr(f, inst),
3480 .runtime_nav_ptr => try airRuntimeNavPtr(f, inst),
34713481
34723482 .c_va_start => try airCVaStart(f, inst),
34733483 .c_va_arg => try airCVaArg(f, inst),
......@@ -7672,7 +7682,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
76727682 return local;
76737683}
76747684
7675fn airTlvDllimportPtr(f: *Function, inst: Air.Inst.Index) !CValue {
7685fn airRuntimeNavPtr(f: *Function, inst: Air.Inst.Index) !CValue {
76767686 const ty_nav = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
76777687 const writer = f.object.writer();
76787688 const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty));
src/codegen/llvm.zig+73-50
......@@ -2979,36 +2979,49 @@ pub const Object = struct {
29792979 const zcu = pt.zcu;
29802980 const ip = &zcu.intern_pool;
29812981 const nav = ip.getNav(nav_index);
2982 const is_extern, const is_threadlocal, const is_weak_linkage, const is_dll_import = switch (nav.status) {
2982 const linkage: std.builtin.GlobalLinkage, const visibility: Builder.Visibility, const is_threadlocal, const is_dll_import = switch (nav.status) {
29832983 .unresolved => unreachable,
29842984 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
2985 .variable => |variable| .{ false, variable.is_threadlocal, variable.is_weak_linkage, false },
2986 .@"extern" => |@"extern"| .{ true, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import },
2987 else => .{ false, false, false, false },
2985 .variable => |variable| .{ .internal, .default, variable.is_threadlocal, false },
2986 .@"extern" => |@"extern"| .{ @"extern".linkage, .fromSymbolVisibility(@"extern".visibility), @"extern".is_threadlocal, @"extern".is_dll_import },
2987 else => .{ .internal, .default, false, false },
29882988 },
29892989 // This means it's a source declaration which is not `extern`!
2990 .type_resolved => |r| .{ false, r.is_threadlocal, false, false },
2990 .type_resolved => |r| .{ .internal, .default, r.is_threadlocal, false },
29912991 };
29922992
29932993 const variable_index = try o.builder.addVariable(
2994 try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)),
2994 try o.builder.strtabString(switch (linkage) {
2995 .internal => nav.fqn,
2996 .strong, .weak => nav.name,
2997 .link_once => unreachable,
2998 }.toSlice(ip)),
29952999 try o.lowerType(Type.fromInterned(nav.typeOf(ip))),
29963000 toLlvmGlobalAddressSpace(nav.getAddrspace(), zcu.getTarget()),
29973001 );
29983002 gop.value_ptr.* = variable_index.ptrConst(&o.builder).global;
29993003
30003004 // This is needed for declarations created by `@extern`.
3001 if (is_extern) {
3002 variable_index.setLinkage(.external, &o.builder);
3003 variable_index.setUnnamedAddr(.default, &o.builder);
3004 if (is_threadlocal and !zcu.navFileScope(nav_index).mod.?.single_threaded)
3005 variable_index.setThreadLocal(.generaldynamic, &o.builder);
3006 if (is_weak_linkage) variable_index.setLinkage(.extern_weak, &o.builder);
3007 if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder);
3008 } else {
3009 variable_index.setLinkage(.internal, &o.builder);
3010 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
3011 }
3005 switch (linkage) {
3006 .internal => {
3007 variable_index.setLinkage(.internal, &o.builder);
3008 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
3009 },
3010 .strong, .weak => {
3011 variable_index.setLinkage(switch (linkage) {
3012 .internal => unreachable,
3013 .strong => .external,
3014 .weak => .extern_weak,
3015 .link_once => unreachable,
3016 }, &o.builder);
3017 variable_index.setUnnamedAddr(.default, &o.builder);
3018 if (is_threadlocal and !zcu.navFileScope(nav_index).mod.?.single_threaded)
3019 variable_index.setThreadLocal(.generaldynamic, &o.builder);
3020 if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder);
3021 },
3022 .link_once => unreachable,
3023 }
3024 variable_index.setVisibility(visibility, &o.builder);
30123025 return variable_index;
30133026 }
30143027
......@@ -4530,14 +4543,14 @@ pub const NavGen = struct {
45304543 const nav = ip.getNav(nav_index);
45314544 const resolved = nav.status.fully_resolved;
45324545
4533 const is_extern, const lib_name, const is_threadlocal, const is_weak_linkage, const is_dll_import, const is_const, const init_val, const owner_nav = switch (ip.indexToKey(resolved.val)) {
4534 .variable => |variable| .{ false, .none, variable.is_threadlocal, variable.is_weak_linkage, false, false, variable.init, variable.owner_nav },
4535 .@"extern" => |@"extern"| .{ true, @"extern".lib_name, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import, @"extern".is_const, .none, @"extern".owner_nav },
4536 else => .{ false, .none, false, false, false, true, resolved.val, nav_index },
4546 const lib_name, const linkage, const visibility: Builder.Visibility, const is_threadlocal, const is_dll_import, const is_const, const init_val, const owner_nav = switch (ip.indexToKey(resolved.val)) {
4547 .variable => |variable| .{ .none, .internal, .default, variable.is_threadlocal, false, false, variable.init, variable.owner_nav },
4548 .@"extern" => |@"extern"| .{ @"extern".lib_name, @"extern".linkage, .fromSymbolVisibility(@"extern".visibility), @"extern".is_threadlocal, @"extern".is_dll_import, @"extern".is_const, .none, @"extern".owner_nav },
4549 else => .{ .none, .internal, .default, false, false, true, resolved.val, nav_index },
45374550 };
45384551 const ty = Type.fromInterned(nav.typeOf(ip));
45394552
4540 if (is_extern and ip.isFunctionType(ty.toIntern())) {
4553 if (linkage != .internal and ip.isFunctionType(ty.toIntern())) {
45414554 _ = try o.resolveLlvmFunction(owner_nav);
45424555 } else {
45434556 const variable_index = try o.resolveGlobalNav(nav_index);
......@@ -4549,6 +4562,7 @@ pub const NavGen = struct {
45494562 .none => .no_init,
45504563 else => try o.lowerValue(init_val),
45514564 }, &o.builder);
4565 variable_index.setVisibility(visibility, &o.builder);
45524566
45534567 const file_scope = zcu.navFileScopeIndex(nav_index);
45544568 const mod = zcu.fileByIndex(file_scope).mod.?;
......@@ -4568,7 +4582,7 @@ pub const NavGen = struct {
45684582 line_number,
45694583 try o.lowerDebugType(ty),
45704584 variable_index,
4571 .{ .local = !is_extern },
4585 .{ .local = linkage == .internal },
45724586 );
45734587
45744588 const debug_expression = try o.builder.debugExpression(&.{});
......@@ -4583,38 +4597,47 @@ pub const NavGen = struct {
45834597 }
45844598 }
45854599
4586 if (is_extern) {
4587 const global_index = o.nav_map.get(nav_index).?;
4600 switch (linkage) {
4601 .internal => {},
4602 .strong, .weak => {
4603 const global_index = o.nav_map.get(nav_index).?;
45884604
4589 const decl_name = decl_name: {
4590 if (zcu.getTarget().cpu.arch.isWasm() and ty.zigTypeTag(zcu) == .@"fn") {
4591 if (lib_name.toSlice(ip)) |lib_name_slice| {
4592 if (!std.mem.eql(u8, lib_name_slice, "c")) {
4593 break :decl_name try o.builder.strtabStringFmt("{}|{s}", .{ nav.name.fmt(ip), lib_name_slice });
4605 const decl_name = decl_name: {
4606 if (zcu.getTarget().cpu.arch.isWasm() and ty.zigTypeTag(zcu) == .@"fn") {
4607 if (lib_name.toSlice(ip)) |lib_name_slice| {
4608 if (!std.mem.eql(u8, lib_name_slice, "c")) {
4609 break :decl_name try o.builder.strtabStringFmt("{}|{s}", .{ nav.name.fmt(ip), lib_name_slice });
4610 }
45944611 }
45954612 }
4596 }
4597 break :decl_name try o.builder.strtabString(nav.name.toSlice(ip));
4598 };
4613 break :decl_name try o.builder.strtabString(nav.name.toSlice(ip));
4614 };
45994615
4600 if (o.builder.getGlobal(decl_name)) |other_global| {
4601 if (other_global != global_index) {
4602 // Another global already has this name; just use it in place of this global.
4603 try global_index.replace(other_global, &o.builder);
4604 return;
4616 if (o.builder.getGlobal(decl_name)) |other_global| {
4617 if (other_global != global_index) {
4618 // Another global already has this name; just use it in place of this global.
4619 try global_index.replace(other_global, &o.builder);
4620 return;
4621 }
46054622 }
4606 }
46074623
4608 try global_index.rename(decl_name, &o.builder);
4609 global_index.setLinkage(.external, &o.builder);
4610 global_index.setUnnamedAddr(.default, &o.builder);
4611 if (is_dll_import) {
4612 global_index.setDllStorageClass(.dllimport, &o.builder);
4613 } else if (zcu.comp.config.dll_export_fns) {
4614 global_index.setDllStorageClass(.default, &o.builder);
4615 }
4624 try global_index.rename(decl_name, &o.builder);
4625 global_index.setUnnamedAddr(.default, &o.builder);
4626 if (is_dll_import) {
4627 global_index.setDllStorageClass(.dllimport, &o.builder);
4628 } else if (zcu.comp.config.dll_export_fns) {
4629 global_index.setDllStorageClass(.default, &o.builder);
4630 }
46164631
4617 if (is_weak_linkage) global_index.setLinkage(.extern_weak, &o.builder);
4632 global_index.setLinkage(switch (linkage) {
4633 .internal => unreachable,
4634 .strong => .external,
4635 .weak => .extern_weak,
4636 .link_once => unreachable,
4637 }, &o.builder);
4638 global_index.setVisibility(visibility, &o.builder);
4639 },
4640 .link_once => unreachable,
46184641 }
46194642 }
46204643};
......@@ -5023,7 +5046,7 @@ pub const FuncGen = struct {
50235046
50245047 .vector_store_elem => try self.airVectorStoreElem(inst),
50255048
5026 .tlv_dllimport_ptr => try self.airTlvDllimportPtr(inst),
5049 .runtime_nav_ptr => try self.airRuntimeNavPtr(inst),
50275050
50285051 .inferred_alloc, .inferred_alloc_comptime => unreachable,
50295052
......@@ -8122,7 +8145,7 @@ pub const FuncGen = struct {
81228145 return .none;
81238146 }
81248147
8125 fn airTlvDllimportPtr(fg: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8148 fn airRuntimeNavPtr(fg: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
81268149 const o = fg.ng.object;
81278150 const ty_nav = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
81288151 const llvm_ptr_const = try o.lowerNavRefValue(ty_nav.nav);
src/libs/libcxx.zig+2-2
......@@ -308,7 +308,7 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
308308 assert(comp.libcxx_static_lib == null);
309309 const crt_file = try sub_compilation.toCrtFile();
310310 comp.libcxx_static_lib = crt_file;
311 comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
311 comp.queueLinkTaskMode(crt_file.full_object_path, &config);
312312}
313313
314314pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void {
......@@ -504,7 +504,7 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
504504 assert(comp.libcxxabi_static_lib == null);
505505 const crt_file = try sub_compilation.toCrtFile();
506506 comp.libcxxabi_static_lib = crt_file;
507 comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
507 comp.queueLinkTaskMode(crt_file.full_object_path, &config);
508508}
509509
510510pub fn addCxxArgs(
src/libs/libtsan.zig+1-1
......@@ -325,7 +325,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
325325 };
326326
327327 const crt_file = try sub_compilation.toCrtFile();
328 comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
328 comp.queueLinkTaskMode(crt_file.full_object_path, &config);
329329 assert(comp.tsan_lib == null);
330330 comp.tsan_lib = crt_file;
331331}
src/libs/libunwind.zig+1-1
......@@ -195,7 +195,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
195195 };
196196
197197 const crt_file = try sub_compilation.toCrtFile();
198 comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
198 comp.queueLinkTaskMode(crt_file.full_object_path, &config);
199199 assert(comp.libunwind_static_lib == null);
200200 comp.libunwind_static_lib = crt_file;
201201}
src/libs/musl.zig+1-1
......@@ -278,7 +278,7 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
278278 errdefer comp.gpa.free(basename);
279279
280280 const crt_file = try sub_compilation.toCrtFile();
281 comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
281 comp.queueLinkTaskMode(crt_file.full_object_path, &config);
282282 {
283283 comp.mutex.lock();
284284 defer comp.mutex.unlock();
src/link/Dwarf.zig+34-20
......@@ -1051,7 +1051,7 @@ const Entry = struct {
10511051 const ref = zo.getSymbolRef(reloc.target_sym, macho_file);
10521052 try dwarf.resolveReloc(
10531053 entry_off + reloc.source_off,
1054 ref.getSymbol(macho_file).?.getAddress(.{}, macho_file),
1054 ref.getSymbol(macho_file).?.getAddress(.{}, macho_file) + @as(i64, @intCast(reloc.target_off)),
10551055 @intFromEnum(dwarf.address_size),
10561056 );
10571057 }
......@@ -1085,13 +1085,19 @@ const ExternalReloc = struct {
10851085
10861086pub const Loc = union(enum) {
10871087 empty,
1088 addr: union(enum) { sym: u32 },
1088 addr_reloc: u32,
1089 deref: *const Loc,
10891090 constu: u64,
10901091 consts: i64,
10911092 plus: Bin,
10921093 reg: u32,
10931094 breg: u32,
10941095 push_object_address,
1096 call: struct {
1097 args: []const Loc = &.{},
1098 unit: Unit.Index,
1099 entry: Entry.Index,
1100 },
10951101 form_tls_address: *const Loc,
10961102 implicit_value: []const u8,
10971103 stack_value: *const Loc,
......@@ -1136,11 +1142,13 @@ pub const Loc = union(enum) {
11361142 const writer = adapter.writer();
11371143 switch (loc) {
11381144 .empty => {},
1139 .addr => |addr| {
1145 .addr_reloc => |sym_index| {
11401146 try writer.writeByte(DW.OP.addr);
1141 switch (addr) {
1142 .sym => |sym_index| try adapter.addrSym(sym_index),
1143 }
1147 try adapter.addrSym(sym_index);
1148 },
1149 .deref => |addr| {
1150 try addr.write(adapter);
1151 try writer.writeByte(DW.OP.deref);
11441152 },
11451153 .constu => |constu| if (std.math.cast(u5, constu)) |lit| {
11461154 try writer.writeByte(@as(u8, DW.OP.lit0) + lit);
......@@ -1225,6 +1233,11 @@ pub const Loc = union(enum) {
12251233 try sleb128(writer, 0);
12261234 },
12271235 .push_object_address => try writer.writeByte(DW.OP.push_object_address),
1236 .call => |call| {
1237 for (call.args) |arg| try arg.write(adapter);
1238 try writer.writeByte(DW.OP.call_ref);
1239 try adapter.infoEntry(call.unit, call.entry);
1240 },
12281241 .form_tls_address => |addr| {
12291242 try addr.write(adapter);
12301243 try writer.writeByte(DW.OP.form_tls_address);
......@@ -1385,12 +1398,12 @@ pub const Cfa = union(enum) {
13851398 },
13861399 .def_cfa_expression => |expr| {
13871400 try writer.writeByte(DW.CFA.def_cfa_expression);
1388 try wip_nav.frameExprloc(expr);
1401 try wip_nav.frameExprLoc(expr);
13891402 },
13901403 .expression => |reg_expr| {
13911404 try writer.writeByte(DW.CFA.expression);
13921405 try uleb128(writer, reg_expr.reg);
1393 try wip_nav.frameExprloc(reg_expr.expr);
1406 try wip_nav.frameExprLoc(reg_expr.expr);
13941407 },
13951408 .val_offset => |reg_off| {
13961409 const factored_off = @divExact(reg_off.off, wip_nav.dwarf.debug_frame.header.data_alignment_factor);
......@@ -1407,7 +1420,7 @@ pub const Cfa = union(enum) {
14071420 .val_expression => |reg_expr| {
14081421 try writer.writeByte(DW.CFA.val_expression);
14091422 try uleb128(writer, reg_expr.reg);
1410 try wip_nav.frameExprloc(reg_expr.expr);
1423 try wip_nav.frameExprLoc(reg_expr.expr);
14111424 },
14121425 .escape => |bytes| try writer.writeAll(bytes),
14131426 }
......@@ -1471,7 +1484,7 @@ pub const WipNav = struct {
14711484 });
14721485 try wip_nav.strp(name);
14731486 try wip_nav.refType(ty);
1474 try wip_nav.infoExprloc(loc);
1487 try wip_nav.infoExprLoc(loc);
14751488 wip_nav.any_children = true;
14761489 }
14771490
......@@ -1741,7 +1754,7 @@ pub const WipNav = struct {
17411754 }
17421755 };
17431756
1744 fn infoExprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
1757 fn infoExprLoc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
17451758 var counter: ExprLocCounter = .init(wip_nav.dwarf);
17461759 try loc.write(&counter);
17471760
......@@ -1773,7 +1786,7 @@ pub const WipNav = struct {
17731786 try wip_nav.debug_info.appendNTimes(wip_nav.dwarf.gpa, 0, @intFromEnum(wip_nav.dwarf.address_size));
17741787 }
17751788
1776 fn frameExprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
1789 fn frameExprLoc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
17771790 var counter: ExprLocCounter = .init(wip_nav.dwarf);
17781791 try loc.write(&counter);
17791792
......@@ -2384,7 +2397,8 @@ fn initWipNavInner(
23842397 else => {},
23852398 }
23862399
2387 const unit = try dwarf.getUnit(file.mod.?);
2400 const mod = file.mod.?;
2401 const unit = try dwarf.getUnit(mod);
23882402 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
23892403 errdefer _ = if (!nav_gop.found_existing) dwarf.navs.pop();
23902404 if (nav_gop.found_existing) {
......@@ -2425,13 +2439,13 @@ fn initWipNavInner(
24252439 }, &nav, inst_info.file, &decl);
24262440 try wip_nav.strp(nav.fqn.toSlice(ip));
24272441 const ty: Type = nav_val.typeOf(zcu);
2428 const addr: Loc = .{ .addr = .{ .sym = sym_index } };
2442 const addr: Loc = .{ .addr_reloc = sym_index };
24292443 const loc: Loc = if (decl.is_threadlocal) .{ .form_tls_address = &addr } else addr;
24302444 switch (decl.kind) {
24312445 .unnamed_test, .@"test", .decltest, .@"comptime", .@"usingnamespace" => unreachable,
24322446 .@"const" => {
24332447 const const_ty_reloc_index = try wip_nav.refForward();
2434 try wip_nav.infoExprloc(loc);
2448 try wip_nav.infoExprLoc(loc);
24352449 try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
24362450 ty.abiAlignment(zcu).toByteUnits().?);
24372451 try diw.writeByte(@intFromBool(decl.linkage != .normal));
......@@ -2441,7 +2455,7 @@ fn initWipNavInner(
24412455 },
24422456 .@"var" => {
24432457 try wip_nav.refType(ty);
2444 try wip_nav.infoExprloc(loc);
2458 try wip_nav.infoExprLoc(loc);
24452459 try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
24462460 ty.abiAlignment(zcu).toByteUnits().?);
24472461 try diw.writeByte(@intFromBool(decl.linkage != .normal));
......@@ -2512,7 +2526,7 @@ fn initWipNavInner(
25122526 try wip_nav.infoAddrSym(sym_index, 0);
25132527 wip_nav.func_high_pc = @intCast(wip_nav.debug_info.items.len);
25142528 try diw.writeInt(u32, 0, dwarf.endian);
2515 const target = file.mod.?.resolved_target.result;
2529 const target = mod.resolved_target.result;
25162530 try uleb128(diw, switch (nav.status.fully_resolved.alignment) {
25172531 .none => target_info.defaultFunctionAlignment(target),
25182532 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
......@@ -3838,7 +3852,7 @@ fn updateLazyValue(
38383852 byte_offset += base_ptr.byte_offset;
38393853 };
38403854 try wip_nav.abbrevCode(.location_comptime_value);
3841 try wip_nav.infoExprloc(.{ .implicit_pointer = .{
3855 try wip_nav.infoExprLoc(.{ .implicit_pointer = .{
38423856 .unit = base_unit,
38433857 .entry = base_entry,
38443858 .offset = byte_offset,
......@@ -4360,7 +4374,7 @@ fn refAbbrevCode(dwarf: *Dwarf, abbrev_code: AbbrevCode) UpdateError!@typeInfo(A
43604374 assert(abbrev_code != .null);
43614375 const entry: Entry.Index = @enumFromInt(@intFromEnum(abbrev_code));
43624376 if (dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).getEntry(entry).len > 0) return @intFromEnum(abbrev_code);
4363 var debug_abbrev = std.ArrayList(u8).init(dwarf.gpa);
4377 var debug_abbrev: std.ArrayList(u8) = .init(dwarf.gpa);
43644378 defer debug_abbrev.deinit();
43654379 const daw = debug_abbrev.writer();
43664380 const abbrev = AbbrevCode.abbrevs.get(abbrev_code);
......@@ -4422,7 +4436,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
44224436 mod_info.root_dir_path = try dwarf.debug_line_str.addString(dwarf, root_dir_path);
44234437 }
44244438
4425 var header = std.ArrayList(u8).init(dwarf.gpa);
4439 var header: std.ArrayList(u8) = .init(dwarf.gpa);
44264440 defer header.deinit();
44274441 if (dwarf.debug_aranges.section.dirty) {
44284442 for (dwarf.debug_aranges.section.units.items, 0..) |*unit_ptr, unit_index| {
src/link/Elf.zig+25-17
......@@ -959,6 +959,12 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
959959 self.rela_plt.clearRetainingCapacity();
960960
961961 if (self.zigObjectPtr()) |zo| {
962 var undefs: std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)) = .init(gpa);
963 defer {
964 for (undefs.values()) |*refs| refs.deinit();
965 undefs.deinit();
966 }
967
962968 var has_reloc_errors = false;
963969 for (zo.atoms_indexes.items) |atom_index| {
964970 const atom_ptr = zo.atom(atom_index) orelse continue;
......@@ -969,7 +975,10 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
969975 const code = try zo.codeAlloc(self, atom_index);
970976 defer gpa.free(code);
971977 const file_offset = atom_ptr.offset(self);
972 atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {
978 (if (shdr.sh_flags & elf.SHF_ALLOC == 0)
979 atom_ptr.resolveRelocsNonAlloc(self, code, &undefs)
980 else
981 atom_ptr.resolveRelocsAlloc(self, code)) catch |err| switch (err) {
973982 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
974983 error.UnsupportedCpuArch => {
975984 try self.reportUnsupportedCpuArch();
......@@ -980,6 +989,8 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
980989 try self.pwriteAll(code, file_offset);
981990 }
982991
992 try self.reportUndefinedSymbols(&undefs);
993
983994 if (has_reloc_errors) return error.LinkFailure;
984995 }
985996
......@@ -1392,11 +1403,9 @@ fn scanRelocs(self: *Elf) !void {
13921403 const gpa = self.base.comp.gpa;
13931404 const shared_objects = self.shared_objects.values();
13941405
1395 var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa);
1406 var undefs: std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)) = .init(gpa);
13961407 defer {
1397 for (undefs.values()) |*refs| {
1398 refs.deinit();
1399 }
1408 for (undefs.values()) |*refs| refs.deinit();
14001409 undefs.deinit();
14011410 }
14021411
......@@ -2702,15 +2711,16 @@ fn initSyntheticSections(self: *Elf) !void {
27022711 });
27032712 }
27042713
2705 const needs_interp = blk: {
2706 // On Ubuntu with musl-gcc, we get a weird combo of options looking like this:
2707 // -dynamic-linker=<path> -static
2708 // In this case, if we do generate .interp section and segment, we will get
2709 // a segfault in the dynamic linker trying to load a binary that is static
2710 // and doesn't contain .dynamic section.
2711 if (self.base.isStatic() and !comp.config.pie) break :blk false;
2712 break :blk target.dynamic_linker.get() != null;
2714 const is_exe_or_dyn_lib = switch (comp.config.output_mode) {
2715 .Exe => true,
2716 .Lib => comp.config.link_mode == .dynamic,
2717 .Obj => false,
27132718 };
2719 const have_dynamic_linker = comp.config.link_mode == .dynamic and is_exe_or_dyn_lib and !target.dynamic_linker.eql(.none);
2720
2721 const needs_interp = have_dynamic_linker and
2722 (comp.config.link_libc or comp.root_mod.resolved_target.is_explicit_dynamic_linker);
2723
27142724 if (needs_interp and self.section_indexes.interp == null) {
27152725 self.section_indexes.interp = try self.addSection(.{
27162726 .name = try self.insertShString(".interp"),
......@@ -3707,11 +3717,9 @@ fn allocateSpecialPhdrs(self: *Elf) void {
37073717fn writeAtoms(self: *Elf) !void {
37083718 const gpa = self.base.comp.gpa;
37093719
3710 var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa);
3720 var undefs: std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)) = .init(gpa);
37113721 defer {
3712 for (undefs.values()) |*refs| {
3713 refs.deinit();
3714 }
3722 for (undefs.values()) |*refs| refs.deinit();
37153723 undefs.deinit();
37163724 }
37173725
src/link/Elf/Atom.zig+3-3
......@@ -497,14 +497,14 @@ fn dynAbsRelocAction(symbol: *const Symbol, elf_file: *Elf) RelocAction {
497497}
498498
499499fn outputType(elf_file: *Elf) u2 {
500 const comp = elf_file.base.comp;
501500 assert(!elf_file.base.isRelocatable());
502 return switch (elf_file.base.comp.config.output_mode) {
501 const config = &elf_file.base.comp.config;
502 return switch (config.output_mode) {
503503 .Obj => unreachable,
504504 .Lib => 0,
505505 .Exe => switch (elf_file.getTarget().os.tag) {
506506 .haiku => 0,
507 else => if (comp.config.pie) 1 else 2,
507 else => if (config.pie) 1 else 2,
508508 },
509509 };
510510}
src/link/Elf/ZigObject.zig+1
......@@ -657,6 +657,7 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
657657 const atom_ptr = self.atom(atom_index) orelse continue;
658658 if (!atom_ptr.alive) continue;
659659 const shdr = atom_ptr.inputShdr(elf_file);
660 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
660661 if (shdr.sh_type == elf.SHT_NOBITS) continue;
661662 if (atom_ptr.scanRelocsRequiresCode(elf_file)) {
662663 // TODO ideally we don't have to fetch the code here.
src/link/Wasm.zig+1-1
......@@ -2376,7 +2376,7 @@ pub const FunctionImportId = enum(u32) {
23762376 const zcu = wasm.base.comp.zcu.?;
23772377 const ip = &zcu.intern_pool;
23782378 const ext = ip.getNav(i.ptr(wasm).*).getResolvedExtern(ip).?;
2379 return !ext.is_weak_linkage and ext.lib_name != .none;
2379 return ext.linkage != .weak and ext.lib_name != .none;
23802380 },
23812381 };
23822382 }
src/main.zig+2-2
......@@ -39,7 +39,7 @@ test {
3939 _ = Package;
4040}
4141
42const thread_stack_size = 50 << 20;
42const thread_stack_size = 60 << 20;
4343
4444pub const std_options: std.Options = .{
4545 .wasiCwd = wasi_cwd,
......@@ -4208,7 +4208,7 @@ fn serve(
42084208 const main_progress_node = std.Progress.start(.{});
42094209 const file_system_inputs = comp.file_system_inputs.?;
42104210
4211 const IncrementalDebugServer = if (build_options.enable_debug_extensions)
4211 const IncrementalDebugServer = if (build_options.enable_debug_extensions and !builtin.single_threaded)
42124212 @import("IncrementalDebugServer.zig")
42134213 else
42144214 void;
src/print_air.zig deleted-1038
......@@ -1,1038 +0,0 @@
1const std = @import("std");
2const Allocator = std.mem.Allocator;
3const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
4
5const Zcu = @import("Zcu.zig");
6const Value = @import("Value.zig");
7const Type = @import("Type.zig");
8const Air = @import("Air.zig");
9const InternPool = @import("InternPool.zig");
10
11pub fn write(stream: anytype, pt: Zcu.PerThread, air: Air, liveness: ?Air.Liveness) void {
12 const instruction_bytes = air.instructions.len *
13 // Here we don't use @sizeOf(Air.Inst.Data) because it would include
14 // the debug safety tag but we want to measure release size.
15 (@sizeOf(Air.Inst.Tag) + 8);
16 const extra_bytes = air.extra.items.len * @sizeOf(u32);
17 const tomb_bytes = if (liveness) |l| l.tomb_bits.len * @sizeOf(usize) else 0;
18 const liveness_extra_bytes = if (liveness) |l| l.extra.len * @sizeOf(u32) else 0;
19 const liveness_special_bytes = if (liveness) |l| l.special.count() * 8 else 0;
20 const total_bytes = @sizeOf(Air) + instruction_bytes + extra_bytes +
21 @sizeOf(Air.Liveness) + liveness_extra_bytes +
22 liveness_special_bytes + tomb_bytes;
23
24 // zig fmt: off
25 stream.print(
26 \\# Total AIR+Liveness bytes: {}
27 \\# AIR Instructions: {d} ({})
28 \\# AIR Extra Data: {d} ({})
29 \\# Liveness tomb_bits: {}
30 \\# Liveness Extra Data: {d} ({})
31 \\# Liveness special table: {d} ({})
32 \\
33 , .{
34 fmtIntSizeBin(total_bytes),
35 air.instructions.len, fmtIntSizeBin(instruction_bytes),
36 air.extra.items.len, fmtIntSizeBin(extra_bytes),
37 fmtIntSizeBin(tomb_bytes),
38 if (liveness) |l| l.extra.len else 0, fmtIntSizeBin(liveness_extra_bytes),
39 if (liveness) |l| l.special.count() else 0, fmtIntSizeBin(liveness_special_bytes),
40 }) catch return;
41 // zig fmt: on
42
43 var writer: Writer = .{
44 .pt = pt,
45 .gpa = pt.zcu.gpa,
46 .air = air,
47 .liveness = liveness,
48 .indent = 2,
49 .skip_body = false,
50 };
51 writer.writeBody(stream, air.getMainBody()) catch return;
52}
53
54pub fn writeInst(
55 stream: anytype,
56 inst: Air.Inst.Index,
57 pt: Zcu.PerThread,
58 air: Air,
59 liveness: ?Air.Liveness,
60) void {
61 var writer: Writer = .{
62 .pt = pt,
63 .gpa = pt.zcu.gpa,
64 .air = air,
65 .liveness = liveness,
66 .indent = 2,
67 .skip_body = true,
68 };
69 writer.writeInst(stream, inst) catch return;
70}
71
72pub fn dump(pt: Zcu.PerThread, air: Air, liveness: ?Air.Liveness) void {
73 write(std.io.getStdErr().writer(), pt, air, liveness);
74}
75
76pub fn dumpInst(inst: Air.Inst.Index, pt: Zcu.PerThread, air: Air, liveness: ?Air.Liveness) void {
77 writeInst(std.io.getStdErr().writer(), inst, pt, air, liveness);
78}
79
80const Writer = struct {
81 pt: Zcu.PerThread,
82 gpa: Allocator,
83 air: Air,
84 liveness: ?Air.Liveness,
85 indent: usize,
86 skip_body: bool,
87
88 fn writeBody(w: *Writer, s: anytype, body: []const Air.Inst.Index) @TypeOf(s).Error!void {
89 for (body) |inst| {
90 try w.writeInst(s, inst);
91 try s.writeByte('\n');
92 }
93 }
94
95 fn writeInst(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
96 const tag = w.air.instructions.items(.tag)[@intFromEnum(inst)];
97 try s.writeByteNTimes(' ', w.indent);
98 try s.print("{}{c}= {s}(", .{
99 inst,
100 @as(u8, if (if (w.liveness) |liveness| liveness.isUnused(inst) else false) '!' else ' '),
101 @tagName(tag),
102 });
103 switch (tag) {
104 .add,
105 .add_optimized,
106 .add_safe,
107 .add_wrap,
108 .add_sat,
109 .sub,
110 .sub_optimized,
111 .sub_safe,
112 .sub_wrap,
113 .sub_sat,
114 .mul,
115 .mul_optimized,
116 .mul_safe,
117 .mul_wrap,
118 .mul_sat,
119 .div_float,
120 .div_trunc,
121 .div_floor,
122 .div_exact,
123 .rem,
124 .mod,
125 .bit_and,
126 .bit_or,
127 .xor,
128 .cmp_lt,
129 .cmp_lte,
130 .cmp_eq,
131 .cmp_gte,
132 .cmp_gt,
133 .cmp_neq,
134 .bool_and,
135 .bool_or,
136 .store,
137 .store_safe,
138 .array_elem_val,
139 .slice_elem_val,
140 .ptr_elem_val,
141 .shl,
142 .shl_exact,
143 .shl_sat,
144 .shr,
145 .shr_exact,
146 .set_union_tag,
147 .min,
148 .max,
149 .div_float_optimized,
150 .div_trunc_optimized,
151 .div_floor_optimized,
152 .div_exact_optimized,
153 .rem_optimized,
154 .mod_optimized,
155 .cmp_lt_optimized,
156 .cmp_lte_optimized,
157 .cmp_eq_optimized,
158 .cmp_gte_optimized,
159 .cmp_gt_optimized,
160 .cmp_neq_optimized,
161 .memcpy,
162 .memmove,
163 .memset,
164 .memset_safe,
165 => try w.writeBinOp(s, inst),
166
167 .is_null,
168 .is_non_null,
169 .is_null_ptr,
170 .is_non_null_ptr,
171 .is_err,
172 .is_non_err,
173 .is_err_ptr,
174 .is_non_err_ptr,
175 .ret,
176 .ret_safe,
177 .ret_load,
178 .is_named_enum_value,
179 .tag_name,
180 .error_name,
181 .sqrt,
182 .sin,
183 .cos,
184 .tan,
185 .exp,
186 .exp2,
187 .log,
188 .log2,
189 .log10,
190 .floor,
191 .ceil,
192 .round,
193 .trunc_float,
194 .neg,
195 .neg_optimized,
196 .cmp_lt_errors_len,
197 .set_err_return_trace,
198 .c_va_end,
199 => try w.writeUnOp(s, inst),
200
201 .trap,
202 .breakpoint,
203 .dbg_empty_stmt,
204 .unreach,
205 .ret_addr,
206 .frame_addr,
207 .save_err_return_trace_index,
208 => try w.writeNoOp(s, inst),
209
210 .alloc,
211 .ret_ptr,
212 .err_return_trace,
213 .c_va_start,
214 => try w.writeTy(s, inst),
215
216 .arg => try w.writeArg(s, inst),
217
218 .not,
219 .bitcast,
220 .load,
221 .fptrunc,
222 .fpext,
223 .intcast,
224 .intcast_safe,
225 .trunc,
226 .optional_payload,
227 .optional_payload_ptr,
228 .optional_payload_ptr_set,
229 .errunion_payload_ptr_set,
230 .wrap_optional,
231 .unwrap_errunion_payload,
232 .unwrap_errunion_err,
233 .unwrap_errunion_payload_ptr,
234 .unwrap_errunion_err_ptr,
235 .wrap_errunion_payload,
236 .wrap_errunion_err,
237 .slice_ptr,
238 .slice_len,
239 .ptr_slice_len_ptr,
240 .ptr_slice_ptr_ptr,
241 .struct_field_ptr_index_0,
242 .struct_field_ptr_index_1,
243 .struct_field_ptr_index_2,
244 .struct_field_ptr_index_3,
245 .array_to_slice,
246 .float_from_int,
247 .splat,
248 .int_from_float,
249 .int_from_float_optimized,
250 .get_union_tag,
251 .clz,
252 .ctz,
253 .popcount,
254 .byte_swap,
255 .bit_reverse,
256 .abs,
257 .error_set_has_value,
258 .addrspace_cast,
259 .c_va_arg,
260 .c_va_copy,
261 => try w.writeTyOp(s, inst),
262
263 .block, .dbg_inline_block => try w.writeBlock(s, tag, inst),
264
265 .loop => try w.writeLoop(s, inst),
266
267 .slice,
268 .slice_elem_ptr,
269 .ptr_elem_ptr,
270 .ptr_add,
271 .ptr_sub,
272 .add_with_overflow,
273 .sub_with_overflow,
274 .mul_with_overflow,
275 .shl_with_overflow,
276 => try w.writeTyPlBin(s, inst),
277
278 .call,
279 .call_always_tail,
280 .call_never_tail,
281 .call_never_inline,
282 => try w.writeCall(s, inst),
283
284 .dbg_var_ptr,
285 .dbg_var_val,
286 .dbg_arg_inline,
287 => try w.writeDbgVar(s, inst),
288
289 .struct_field_ptr => try w.writeStructField(s, inst),
290 .struct_field_val => try w.writeStructField(s, inst),
291 .inferred_alloc => @panic("TODO"),
292 .inferred_alloc_comptime => @panic("TODO"),
293 .assembly => try w.writeAssembly(s, inst),
294 .dbg_stmt => try w.writeDbgStmt(s, inst),
295
296 .aggregate_init => try w.writeAggregateInit(s, inst),
297 .union_init => try w.writeUnionInit(s, inst),
298 .br => try w.writeBr(s, inst),
299 .switch_dispatch => try w.writeBr(s, inst),
300 .repeat => try w.writeRepeat(s, inst),
301 .cond_br => try w.writeCondBr(s, inst),
302 .@"try", .try_cold => try w.writeTry(s, inst),
303 .try_ptr, .try_ptr_cold => try w.writeTryPtr(s, inst),
304 .loop_switch_br, .switch_br => try w.writeSwitchBr(s, inst),
305 .cmpxchg_weak, .cmpxchg_strong => try w.writeCmpxchg(s, inst),
306 .atomic_load => try w.writeAtomicLoad(s, inst),
307 .prefetch => try w.writePrefetch(s, inst),
308 .atomic_store_unordered => try w.writeAtomicStore(s, inst, .unordered),
309 .atomic_store_monotonic => try w.writeAtomicStore(s, inst, .monotonic),
310 .atomic_store_release => try w.writeAtomicStore(s, inst, .release),
311 .atomic_store_seq_cst => try w.writeAtomicStore(s, inst, .seq_cst),
312 .atomic_rmw => try w.writeAtomicRmw(s, inst),
313 .field_parent_ptr => try w.writeFieldParentPtr(s, inst),
314 .wasm_memory_size => try w.writeWasmMemorySize(s, inst),
315 .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst),
316 .mul_add => try w.writeMulAdd(s, inst),
317 .select => try w.writeSelect(s, inst),
318 .shuffle_one => try w.writeShuffleOne(s, inst),
319 .shuffle_two => try w.writeShuffleTwo(s, inst),
320 .reduce, .reduce_optimized => try w.writeReduce(s, inst),
321 .cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
322 .vector_store_elem => try w.writeVectorStoreElem(s, inst),
323 .tlv_dllimport_ptr => try w.writeTlvDllimportPtr(s, inst),
324
325 .work_item_id,
326 .work_group_size,
327 .work_group_id,
328 => try w.writeWorkDimension(s, inst),
329 }
330 try s.writeByte(')');
331 }
332
333 fn writeBinOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
334 const bin_op = w.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
335 try w.writeOperand(s, inst, 0, bin_op.lhs);
336 try s.writeAll(", ");
337 try w.writeOperand(s, inst, 1, bin_op.rhs);
338 }
339
340 fn writeUnOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
341 const un_op = w.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
342 try w.writeOperand(s, inst, 0, un_op);
343 }
344
345 fn writeNoOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
346 _ = w;
347 _ = inst;
348 // no-op, no argument to write
349 }
350
351 fn writeType(w: *Writer, s: anytype, ty: Type) !void {
352 return ty.print(s, w.pt);
353 }
354
355 fn writeTy(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
356 const ty = w.air.instructions.items(.data)[@intFromEnum(inst)].ty;
357 try w.writeType(s, ty);
358 }
359
360 fn writeArg(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
361 const arg = w.air.instructions.items(.data)[@intFromEnum(inst)].arg;
362 try w.writeType(s, arg.ty.toType());
363 switch (arg.name) {
364 .none => {},
365 _ => try s.print(", \"{}\"", .{std.zig.fmtEscapes(arg.name.toSlice(w.air))}),
366 }
367 }
368
369 fn writeTyOp(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
370 const ty_op = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
371 try w.writeType(s, ty_op.ty.toType());
372 try s.writeAll(", ");
373 try w.writeOperand(s, inst, 0, ty_op.operand);
374 }
375
376 fn writeBlock(w: *Writer, s: anytype, tag: Air.Inst.Tag, inst: Air.Inst.Index) @TypeOf(s).Error!void {
377 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
378 try w.writeType(s, ty_pl.ty.toType());
379 const body: []const Air.Inst.Index = @ptrCast(switch (tag) {
380 inline .block, .dbg_inline_block => |comptime_tag| body: {
381 const extra = w.air.extraData(switch (comptime_tag) {
382 .block => Air.Block,
383 .dbg_inline_block => Air.DbgInlineBlock,
384 else => unreachable,
385 }, ty_pl.payload);
386 switch (comptime_tag) {
387 .block => {},
388 .dbg_inline_block => {
389 try s.writeAll(", ");
390 try w.writeInstRef(s, Air.internedToRef(extra.data.func), false);
391 },
392 else => unreachable,
393 }
394 break :body w.air.extra.items[extra.end..][0..extra.data.body_len];
395 },
396 else => unreachable,
397 });
398 if (w.skip_body) return s.writeAll(", ...");
399 const liveness_block: Air.Liveness.BlockSlices = if (w.liveness) |liveness|
400 liveness.getBlock(inst)
401 else
402 .{ .deaths = &.{} };
403
404 try s.writeAll(", {\n");
405 const old_indent = w.indent;
406 w.indent += 2;
407 try w.writeBody(s, body);
408 w.indent = old_indent;
409 try s.writeByteNTimes(' ', w.indent);
410 try s.writeAll("}");
411
412 for (liveness_block.deaths) |operand| {
413 try s.print(" {}!", .{operand});
414 }
415 }
416
417 fn writeLoop(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
418 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
419 const extra = w.air.extraData(Air.Block, ty_pl.payload);
420 const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]);
421
422 try w.writeType(s, ty_pl.ty.toType());
423 if (w.skip_body) return s.writeAll(", ...");
424 try s.writeAll(", {\n");
425 const old_indent = w.indent;
426 w.indent += 2;
427 try w.writeBody(s, body);
428 w.indent = old_indent;
429 try s.writeByteNTimes(' ', w.indent);
430 try s.writeAll("}");
431 }
432
433 fn writeAggregateInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
434 const zcu = w.pt.zcu;
435 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
436 const vector_ty = ty_pl.ty.toType();
437 const len = @as(usize, @intCast(vector_ty.arrayLen(zcu)));
438 const elements = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[ty_pl.payload..][0..len]));
439
440 try w.writeType(s, vector_ty);
441 try s.writeAll(", [");
442 for (elements, 0..) |elem, i| {
443 if (i != 0) try s.writeAll(", ");
444 try w.writeOperand(s, inst, i, elem);
445 }
446 try s.writeAll("]");
447 }
448
449 fn writeUnionInit(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
450 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
451 const extra = w.air.extraData(Air.UnionInit, ty_pl.payload).data;
452
453 try s.print("{d}, ", .{extra.field_index});
454 try w.writeOperand(s, inst, 0, extra.init);
455 }
456
457 fn writeStructField(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
458 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
459 const extra = w.air.extraData(Air.StructField, ty_pl.payload).data;
460
461 try w.writeOperand(s, inst, 0, extra.struct_operand);
462 try s.print(", {d}", .{extra.field_index});
463 }
464
465 fn writeTyPlBin(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
466 const data = w.air.instructions.items(.data);
467 const ty_pl = data[@intFromEnum(inst)].ty_pl;
468 const extra = w.air.extraData(Air.Bin, ty_pl.payload).data;
469
470 const inst_ty = data[@intFromEnum(inst)].ty_pl.ty.toType();
471 try w.writeType(s, inst_ty);
472 try s.writeAll(", ");
473 try w.writeOperand(s, inst, 0, extra.lhs);
474 try s.writeAll(", ");
475 try w.writeOperand(s, inst, 1, extra.rhs);
476 }
477
478 fn writeCmpxchg(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
479 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
480 const extra = w.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
481
482 try w.writeOperand(s, inst, 0, extra.ptr);
483 try s.writeAll(", ");
484 try w.writeOperand(s, inst, 1, extra.expected_value);
485 try s.writeAll(", ");
486 try w.writeOperand(s, inst, 2, extra.new_value);
487 try s.print(", {s}, {s}", .{
488 @tagName(extra.successOrder()), @tagName(extra.failureOrder()),
489 });
490 }
491
492 fn writeMulAdd(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
493 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
494 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
495
496 try w.writeOperand(s, inst, 0, extra.lhs);
497 try s.writeAll(", ");
498 try w.writeOperand(s, inst, 1, extra.rhs);
499 try s.writeAll(", ");
500 try w.writeOperand(s, inst, 2, pl_op.operand);
501 }
502
503 fn writeShuffleOne(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
504 const unwrapped = w.air.unwrapShuffleOne(w.pt.zcu, inst);
505 try w.writeType(s, unwrapped.result_ty);
506 try s.writeAll(", ");
507 try w.writeOperand(s, inst, 0, unwrapped.operand);
508 try s.writeAll(", [");
509 for (unwrapped.mask, 0..) |mask_elem, mask_idx| {
510 if (mask_idx > 0) try s.writeAll(", ");
511 switch (mask_elem.unwrap()) {
512 .elem => |idx| try s.print("elem {d}", .{idx}),
513 .value => |val| try s.print("val {}", .{Value.fromInterned(val).fmtValue(w.pt)}),
514 }
515 }
516 try s.writeByte(']');
517 }
518
519 fn writeShuffleTwo(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
520 const unwrapped = w.air.unwrapShuffleTwo(w.pt.zcu, inst);
521 try w.writeType(s, unwrapped.result_ty);
522 try s.writeAll(", ");
523 try w.writeOperand(s, inst, 0, unwrapped.operand_a);
524 try s.writeAll(", ");
525 try w.writeOperand(s, inst, 1, unwrapped.operand_b);
526 try s.writeAll(", [");
527 for (unwrapped.mask, 0..) |mask_elem, mask_idx| {
528 if (mask_idx > 0) try s.writeAll(", ");
529 switch (mask_elem.unwrap()) {
530 .a_elem => |idx| try s.print("a_elem {d}", .{idx}),
531 .b_elem => |idx| try s.print("b_elem {d}", .{idx}),
532 .undef => try s.writeAll("undef"),
533 }
534 }
535 try s.writeByte(']');
536 }
537
538 fn writeSelect(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
539 const zcu = w.pt.zcu;
540 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
541 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
542
543 const elem_ty = w.typeOfIndex(inst).childType(zcu);
544 try w.writeType(s, elem_ty);
545 try s.writeAll(", ");
546 try w.writeOperand(s, inst, 0, pl_op.operand);
547 try s.writeAll(", ");
548 try w.writeOperand(s, inst, 1, extra.lhs);
549 try s.writeAll(", ");
550 try w.writeOperand(s, inst, 2, extra.rhs);
551 }
552
553 fn writeReduce(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
554 const reduce = w.air.instructions.items(.data)[@intFromEnum(inst)].reduce;
555
556 try w.writeOperand(s, inst, 0, reduce.operand);
557 try s.print(", {s}", .{@tagName(reduce.operation)});
558 }
559
560 fn writeCmpVector(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
561 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
562 const extra = w.air.extraData(Air.VectorCmp, ty_pl.payload).data;
563
564 try s.print("{s}, ", .{@tagName(extra.compareOperator())});
565 try w.writeOperand(s, inst, 0, extra.lhs);
566 try s.writeAll(", ");
567 try w.writeOperand(s, inst, 1, extra.rhs);
568 }
569
570 fn writeVectorStoreElem(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
571 const data = w.air.instructions.items(.data)[@intFromEnum(inst)].vector_store_elem;
572 const extra = w.air.extraData(Air.VectorCmp, data.payload).data;
573
574 try w.writeOperand(s, inst, 0, data.vector_ptr);
575 try s.writeAll(", ");
576 try w.writeOperand(s, inst, 1, extra.lhs);
577 try s.writeAll(", ");
578 try w.writeOperand(s, inst, 2, extra.rhs);
579 }
580
581 fn writeTlvDllimportPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
582 const ip = &w.pt.zcu.intern_pool;
583 const ty_nav = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
584 try w.writeType(s, .fromInterned(ty_nav.ty));
585 try s.print(", '{}'", .{ip.getNav(ty_nav.nav).fqn.fmt(ip)});
586 }
587
588 fn writeAtomicLoad(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
589 const atomic_load = w.air.instructions.items(.data)[@intFromEnum(inst)].atomic_load;
590
591 try w.writeOperand(s, inst, 0, atomic_load.ptr);
592 try s.print(", {s}", .{@tagName(atomic_load.order)});
593 }
594
595 fn writePrefetch(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
596 const prefetch = w.air.instructions.items(.data)[@intFromEnum(inst)].prefetch;
597
598 try w.writeOperand(s, inst, 0, prefetch.ptr);
599 try s.print(", {s}, {d}, {s}", .{
600 @tagName(prefetch.rw), prefetch.locality, @tagName(prefetch.cache),
601 });
602 }
603
604 fn writeAtomicStore(
605 w: *Writer,
606 s: anytype,
607 inst: Air.Inst.Index,
608 order: std.builtin.AtomicOrder,
609 ) @TypeOf(s).Error!void {
610 const bin_op = w.air.instructions.items(.data)[@intFromEnum(inst)].bin_op;
611 try w.writeOperand(s, inst, 0, bin_op.lhs);
612 try s.writeAll(", ");
613 try w.writeOperand(s, inst, 1, bin_op.rhs);
614 try s.print(", {s}", .{@tagName(order)});
615 }
616
617 fn writeAtomicRmw(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
618 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
619 const extra = w.air.extraData(Air.AtomicRmw, pl_op.payload).data;
620
621 try w.writeOperand(s, inst, 0, pl_op.operand);
622 try s.writeAll(", ");
623 try w.writeOperand(s, inst, 1, extra.operand);
624 try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) });
625 }
626
627 fn writeFieldParentPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
628 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
629 const extra = w.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
630
631 try w.writeOperand(s, inst, 0, extra.field_ptr);
632 try s.print(", {d}", .{extra.field_index});
633 }
634
635 fn writeAssembly(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
636 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
637 const extra = w.air.extraData(Air.Asm, ty_pl.payload);
638 const is_volatile = @as(u1, @truncate(extra.data.flags >> 31)) != 0;
639 const clobbers_len = @as(u31, @truncate(extra.data.flags));
640 var extra_i: usize = extra.end;
641 var op_index: usize = 0;
642
643 const ret_ty = w.typeOfIndex(inst);
644 try w.writeType(s, ret_ty);
645
646 if (is_volatile) {
647 try s.writeAll(", volatile");
648 }
649
650 const outputs = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra_i..][0..extra.data.outputs_len]));
651 extra_i += outputs.len;
652 const inputs = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra_i..][0..extra.data.inputs_len]));
653 extra_i += inputs.len;
654
655 for (outputs) |output| {
656 const extra_bytes = std.mem.sliceAsBytes(w.air.extra.items[extra_i..]);
657 const constraint = std.mem.sliceTo(extra_bytes, 0);
658 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
659
660 // This equation accounts for the fact that even if we have exactly 4 bytes
661 // for the strings and their null terminators, we still use the next u32
662 // for the null terminator.
663 extra_i += (constraint.len + name.len + (2 + 3)) / 4;
664
665 if (output == .none) {
666 try s.print(", [{s}] -> {s}", .{ name, constraint });
667 } else {
668 try s.print(", [{s}] out {s} = (", .{ name, constraint });
669 try w.writeOperand(s, inst, op_index, output);
670 op_index += 1;
671 try s.writeByte(')');
672 }
673 }
674
675 for (inputs) |input| {
676 const extra_bytes = std.mem.sliceAsBytes(w.air.extra.items[extra_i..]);
677 const constraint = std.mem.sliceTo(extra_bytes, 0);
678 const name = std.mem.sliceTo(extra_bytes[constraint.len + 1 ..], 0);
679 // This equation accounts for the fact that even if we have exactly 4 bytes
680 // for the strings and their null terminators, we still use the next u32
681 // for the null terminator.
682 extra_i += (constraint.len + name.len + 1) / 4 + 1;
683
684 try s.print(", [{s}] in {s} = (", .{ name, constraint });
685 try w.writeOperand(s, inst, op_index, input);
686 op_index += 1;
687 try s.writeByte(')');
688 }
689
690 {
691 var clobber_i: u32 = 0;
692 while (clobber_i < clobbers_len) : (clobber_i += 1) {
693 const extra_bytes = std.mem.sliceAsBytes(w.air.extra.items[extra_i..]);
694 const clobber = std.mem.sliceTo(extra_bytes, 0);
695 // This equation accounts for the fact that even if we have exactly 4 bytes
696 // for the string, we still use the next u32 for the null terminator.
697 extra_i += clobber.len / 4 + 1;
698
699 try s.writeAll(", ~{");
700 try s.writeAll(clobber);
701 try s.writeAll("}");
702 }
703 }
704 const asm_source = std.mem.sliceAsBytes(w.air.extra.items[extra_i..])[0..extra.data.source_len];
705 try s.print(", \"{}\"", .{std.zig.fmtEscapes(asm_source)});
706 }
707
708 fn writeDbgStmt(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
709 const dbg_stmt = w.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
710 try s.print("{d}:{d}", .{ dbg_stmt.line + 1, dbg_stmt.column + 1 });
711 }
712
713 fn writeDbgVar(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
714 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
715 try w.writeOperand(s, inst, 0, pl_op.operand);
716 const name: Air.NullTerminatedString = @enumFromInt(pl_op.payload);
717 try s.print(", \"{}\"", .{std.zig.fmtEscapes(name.toSlice(w.air))});
718 }
719
720 fn writeCall(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
721 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
722 const extra = w.air.extraData(Air.Call, pl_op.payload);
723 const args = @as([]const Air.Inst.Ref, @ptrCast(w.air.extra.items[extra.end..][0..extra.data.args_len]));
724 try w.writeOperand(s, inst, 0, pl_op.operand);
725 try s.writeAll(", [");
726 for (args, 0..) |arg, i| {
727 if (i != 0) try s.writeAll(", ");
728 try w.writeOperand(s, inst, 1 + i, arg);
729 }
730 try s.writeAll("]");
731 }
732
733 fn writeBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
734 const br = w.air.instructions.items(.data)[@intFromEnum(inst)].br;
735 try w.writeInstIndex(s, br.block_inst, false);
736 try s.writeAll(", ");
737 try w.writeOperand(s, inst, 0, br.operand);
738 }
739
740 fn writeRepeat(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
741 const repeat = w.air.instructions.items(.data)[@intFromEnum(inst)].repeat;
742 try w.writeInstIndex(s, repeat.loop_inst, false);
743 }
744
745 fn writeTry(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
746 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
747 const extra = w.air.extraData(Air.Try, pl_op.payload);
748 const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]);
749 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
750 liveness.getCondBr(inst)
751 else
752 .{ .then_deaths = &.{}, .else_deaths = &.{} };
753
754 try w.writeOperand(s, inst, 0, pl_op.operand);
755 if (w.skip_body) return s.writeAll(", ...");
756 try s.writeAll(", {\n");
757 const old_indent = w.indent;
758 w.indent += 2;
759
760 if (liveness_condbr.else_deaths.len != 0) {
761 try s.writeByteNTimes(' ', w.indent);
762 for (liveness_condbr.else_deaths, 0..) |operand, i| {
763 if (i != 0) try s.writeAll(" ");
764 try s.print("{}!", .{operand});
765 }
766 try s.writeAll("\n");
767 }
768 try w.writeBody(s, body);
769
770 w.indent = old_indent;
771 try s.writeByteNTimes(' ', w.indent);
772 try s.writeAll("}");
773
774 for (liveness_condbr.then_deaths) |operand| {
775 try s.print(" {}!", .{operand});
776 }
777 }
778
779 fn writeTryPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
780 const ty_pl = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
781 const extra = w.air.extraData(Air.TryPtr, ty_pl.payload);
782 const body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.body_len]);
783 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
784 liveness.getCondBr(inst)
785 else
786 .{ .then_deaths = &.{}, .else_deaths = &.{} };
787
788 try w.writeOperand(s, inst, 0, extra.data.ptr);
789
790 try s.writeAll(", ");
791 try w.writeType(s, ty_pl.ty.toType());
792 if (w.skip_body) return s.writeAll(", ...");
793 try s.writeAll(", {\n");
794 const old_indent = w.indent;
795 w.indent += 2;
796
797 if (liveness_condbr.else_deaths.len != 0) {
798 try s.writeByteNTimes(' ', w.indent);
799 for (liveness_condbr.else_deaths, 0..) |operand, i| {
800 if (i != 0) try s.writeAll(" ");
801 try s.print("{}!", .{operand});
802 }
803 try s.writeAll("\n");
804 }
805 try w.writeBody(s, body);
806
807 w.indent = old_indent;
808 try s.writeByteNTimes(' ', w.indent);
809 try s.writeAll("}");
810
811 for (liveness_condbr.then_deaths) |operand| {
812 try s.print(" {}!", .{operand});
813 }
814 }
815
816 fn writeCondBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
817 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
818 const extra = w.air.extraData(Air.CondBr, pl_op.payload);
819 const then_body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.then_body_len]);
820 const else_body: []const Air.Inst.Index = @ptrCast(w.air.extra.items[extra.end + then_body.len ..][0..extra.data.else_body_len]);
821 const liveness_condbr: Air.Liveness.CondBrSlices = if (w.liveness) |liveness|
822 liveness.getCondBr(inst)
823 else
824 .{ .then_deaths = &.{}, .else_deaths = &.{} };
825
826 try w.writeOperand(s, inst, 0, pl_op.operand);
827 if (w.skip_body) return s.writeAll(", ...");
828 try s.writeAll(",");
829 if (extra.data.branch_hints.true != .none) {
830 try s.print(" {s}", .{@tagName(extra.data.branch_hints.true)});
831 }
832 if (extra.data.branch_hints.then_cov != .none) {
833 try s.print(" {s}", .{@tagName(extra.data.branch_hints.then_cov)});
834 }
835 try s.writeAll(" {\n");
836 const old_indent = w.indent;
837 w.indent += 2;
838
839 if (liveness_condbr.then_deaths.len != 0) {
840 try s.writeByteNTimes(' ', w.indent);
841 for (liveness_condbr.then_deaths, 0..) |operand, i| {
842 if (i != 0) try s.writeAll(" ");
843 try s.print("{}!", .{operand});
844 }
845 try s.writeAll("\n");
846 }
847
848 try w.writeBody(s, then_body);
849 try s.writeByteNTimes(' ', old_indent);
850 try s.writeAll("},");
851 if (extra.data.branch_hints.false != .none) {
852 try s.print(" {s}", .{@tagName(extra.data.branch_hints.false)});
853 }
854 if (extra.data.branch_hints.else_cov != .none) {
855 try s.print(" {s}", .{@tagName(extra.data.branch_hints.else_cov)});
856 }
857 try s.writeAll(" {\n");
858
859 if (liveness_condbr.else_deaths.len != 0) {
860 try s.writeByteNTimes(' ', w.indent);
861 for (liveness_condbr.else_deaths, 0..) |operand, i| {
862 if (i != 0) try s.writeAll(" ");
863 try s.print("{}!", .{operand});
864 }
865 try s.writeAll("\n");
866 }
867
868 try w.writeBody(s, else_body);
869 w.indent = old_indent;
870
871 try s.writeByteNTimes(' ', old_indent);
872 try s.writeAll("}");
873 }
874
875 fn writeSwitchBr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
876 const switch_br = w.air.unwrapSwitch(inst);
877
878 const liveness: Air.Liveness.SwitchBrTable = if (w.liveness) |liveness|
879 liveness.getSwitchBr(w.gpa, inst, switch_br.cases_len + 1) catch
880 @panic("out of memory")
881 else blk: {
882 const slice = w.gpa.alloc([]const Air.Inst.Index, switch_br.cases_len + 1) catch
883 @panic("out of memory");
884 @memset(slice, &.{});
885 break :blk .{ .deaths = slice };
886 };
887 defer w.gpa.free(liveness.deaths);
888
889 try w.writeOperand(s, inst, 0, switch_br.operand);
890 if (w.skip_body) return s.writeAll(", ...");
891 const old_indent = w.indent;
892 w.indent += 2;
893
894 var it = switch_br.iterateCases();
895 while (it.next()) |case| {
896 try s.writeAll(", [");
897 for (case.items, 0..) |item, item_i| {
898 if (item_i != 0) try s.writeAll(", ");
899 try w.writeInstRef(s, item, false);
900 }
901 for (case.ranges, 0..) |range, range_i| {
902 if (range_i != 0 or case.items.len != 0) try s.writeAll(", ");
903 try w.writeInstRef(s, range[0], false);
904 try s.writeAll("...");
905 try w.writeInstRef(s, range[1], false);
906 }
907 try s.writeAll("] ");
908 const hint = switch_br.getHint(case.idx);
909 if (hint != .none) {
910 try s.print(".{s} ", .{@tagName(hint)});
911 }
912 try s.writeAll("=> {\n");
913 w.indent += 2;
914
915 const deaths = liveness.deaths[case.idx];
916 if (deaths.len != 0) {
917 try s.writeByteNTimes(' ', w.indent);
918 for (deaths, 0..) |operand, i| {
919 if (i != 0) try s.writeAll(" ");
920 try s.print("{}!", .{operand});
921 }
922 try s.writeAll("\n");
923 }
924
925 try w.writeBody(s, case.body);
926 w.indent -= 2;
927 try s.writeByteNTimes(' ', w.indent);
928 try s.writeAll("}");
929 }
930
931 const else_body = it.elseBody();
932 if (else_body.len != 0) {
933 try s.writeAll(", else ");
934 const hint = switch_br.getElseHint();
935 if (hint != .none) {
936 try s.print(".{s} ", .{@tagName(hint)});
937 }
938 try s.writeAll("=> {\n");
939 w.indent += 2;
940
941 const deaths = liveness.deaths[liveness.deaths.len - 1];
942 if (deaths.len != 0) {
943 try s.writeByteNTimes(' ', w.indent);
944 for (deaths, 0..) |operand, i| {
945 if (i != 0) try s.writeAll(" ");
946 try s.print("{}!", .{operand});
947 }
948 try s.writeAll("\n");
949 }
950
951 try w.writeBody(s, else_body);
952 w.indent -= 2;
953 try s.writeByteNTimes(' ', w.indent);
954 try s.writeAll("}");
955 }
956
957 try s.writeAll("\n");
958 try s.writeByteNTimes(' ', old_indent);
959 }
960
961 fn writeWasmMemorySize(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
962 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
963 try s.print("{d}", .{pl_op.payload});
964 }
965
966 fn writeWasmMemoryGrow(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
967 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
968 try s.print("{d}, ", .{pl_op.payload});
969 try w.writeOperand(s, inst, 0, pl_op.operand);
970 }
971
972 fn writeWorkDimension(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
973 const pl_op = w.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
974 try s.print("{d}", .{pl_op.payload});
975 }
976
977 fn writeOperand(
978 w: *Writer,
979 s: anytype,
980 inst: Air.Inst.Index,
981 op_index: usize,
982 operand: Air.Inst.Ref,
983 ) @TypeOf(s).Error!void {
984 const small_tomb_bits = Air.Liveness.bpi - 1;
985 const dies = if (w.liveness) |liveness| blk: {
986 if (op_index < small_tomb_bits)
987 break :blk liveness.operandDies(inst, @intCast(op_index));
988 var extra_index = liveness.special.get(inst).?;
989 var tomb_op_index: usize = small_tomb_bits;
990 while (true) {
991 const bits = liveness.extra[extra_index];
992 if (op_index < tomb_op_index + 31) {
993 break :blk @as(u1, @truncate(bits >> @as(u5, @intCast(op_index - tomb_op_index)))) != 0;
994 }
995 if ((bits >> 31) != 0) break :blk false;
996 extra_index += 1;
997 tomb_op_index += 31;
998 }
999 } else false;
1000 return w.writeInstRef(s, operand, dies);
1001 }
1002
1003 fn writeInstRef(
1004 w: *Writer,
1005 s: anytype,
1006 operand: Air.Inst.Ref,
1007 dies: bool,
1008 ) @TypeOf(s).Error!void {
1009 if (@intFromEnum(operand) < InternPool.static_len) {
1010 return s.print("@{}", .{operand});
1011 } else if (operand.toInterned()) |ip_index| {
1012 const pt = w.pt;
1013 const ty = Type.fromInterned(pt.zcu.intern_pool.indexToKey(ip_index).typeOf());
1014 try s.print("<{}, {}>", .{
1015 ty.fmt(pt),
1016 Value.fromInterned(ip_index).fmtValue(pt),
1017 });
1018 } else {
1019 return w.writeInstIndex(s, operand.toIndex().?, dies);
1020 }
1021 }
1022
1023 fn writeInstIndex(
1024 w: *Writer,
1025 s: anytype,
1026 inst: Air.Inst.Index,
1027 dies: bool,
1028 ) @TypeOf(s).Error!void {
1029 _ = w;
1030 try s.print("{}", .{inst});
1031 if (dies) try s.writeByte('!');
1032 }
1033
1034 fn typeOfIndex(w: *Writer, inst: Air.Inst.Index) Type {
1035 const zcu = w.pt.zcu;
1036 return w.air.typeOfIndex(inst, &zcu.intern_pool);
1037 }
1038};
src/target.zig+4
......@@ -223,6 +223,10 @@ pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool {
223223/// than or equal to the number of behavior tests as the respective LLVM backend.
224224pub fn selfHostedBackendIsAsRobustAsLlvm(target: std.Target) bool {
225225 if (target.cpu.arch.isSpirV()) return true;
226 if (target.cpu.arch == .x86_64 and target.ptrBitWidth() == 64) return switch (target.ofmt) {
227 .elf, .macho => true,
228 else => false,
229 };
226230 return false;
227231}
228232
test/behavior/math.zig+1
......@@ -1722,6 +1722,7 @@ test "signed zeros are represented properly" {
17221722 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
17231723 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
17241724 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1725 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
17251726
17261727 const S = struct {
17271728 fn doTheTest() !void {
test/behavior/switch.zig+9
......@@ -1056,3 +1056,12 @@ test "unlabeled break ignores switch" {
10561056 };
10571057 try expect(result == 123);
10581058}
1059
1060test "switch on a signed value smaller than the smallest prong value" {
1061 var v: i32 = undefined;
1062 v = -1;
1063 switch (v) {
1064 inline 0...10 => return error.TestFailed,
1065 else => {},
1066 }
1067}
test/cases/compile_errors/@import_zon_bad_type.zig+3-3
......@@ -117,9 +117,9 @@ export fn testMutablePointer() void {
117117// tmp.zig:37:38: note: imported here
118118// neg_inf.zon:1:1: error: expected type '?u8'
119119// tmp.zig:57:28: note: imported here
120// neg_inf.zon:1:1: error: expected type 'tmp.testNonExhaustiveEnum__enum_522'
120// neg_inf.zon:1:1: error: expected type 'tmp.testNonExhaustiveEnum__enum_525'
121121// tmp.zig:62:39: note: imported here
122// neg_inf.zon:1:1: error: expected type 'tmp.testUntaggedUnion__union_524'
122// neg_inf.zon:1:1: error: expected type 'tmp.testUntaggedUnion__union_527'
123123// tmp.zig:67:44: note: imported here
124// neg_inf.zon:1:1: error: expected type 'tmp.testTaggedUnionVoid__union_527'
124// neg_inf.zon:1:1: error: expected type 'tmp.testTaggedUnionVoid__union_530'
125125// tmp.zig:72:50: note: imported here
test/cases/compile_errors/anytype_param_requires_comptime.zig+1-1
......@@ -15,6 +15,6 @@ pub export fn entry() void {
1515// error
1616//
1717// :7:25: error: unable to resolve comptime value
18// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_496.C' must be comptime-known
18// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_499.C' must be comptime-known
1919// :4:16: note: struct requires comptime because of this field
2020// :4:16: note: types are not available at runtime
test/cases/compile_errors/bogus_method_call_on_slice.zig+1-1
......@@ -16,5 +16,5 @@ pub export fn entry2() void {
1616//
1717// :3:6: error: no field or member function named 'copy' in '[]const u8'
1818// :9:8: error: no field or member function named 'bar' in '@TypeOf(.{})'
19// :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_500'
19// :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_503'
2020// :12:6: note: struct declared here
test/cases/compile_errors/coerce_anon_struct.zig+1-1
......@@ -6,6 +6,6 @@ export fn foo() void {
66
77// error
88//
9// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_489'
9// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_492'
1010// :3:16: note: struct declared here
1111// :1:11: note: struct declared here
test/cases/compile_errors/redundant_try.zig+2-2
......@@ -44,9 +44,9 @@ comptime {
4444//
4545// :5:23: error: expected error union type, found 'comptime_int'
4646// :10:23: error: expected error union type, found '@TypeOf(.{})'
47// :15:23: error: expected error union type, found 'tmp.test2__struct_526'
47// :15:23: error: expected error union type, found 'tmp.test2__struct_529'
4848// :15:23: note: struct declared here
49// :20:27: error: expected error union type, found 'tmp.test3__struct_528'
49// :20:27: error: expected error union type, found 'tmp.test3__struct_531'
5050// :20:27: note: struct declared here
5151// :25:23: error: expected error union type, found 'struct { comptime *const [5:0]u8 = "hello" }'
5252// :31:13: error: expected error union type, found 'u32'
test/link/bss/main.zig+4-3
......@@ -6,8 +6,9 @@ var buffer: [0x1000000]u64 = [1]u64{0} ** 0x1000000;
66pub fn main() anyerror!void {
77 buffer[0x10] = 1;
88 try std.io.getStdOut().writer().print("{d}, {d}, {d}\n", .{
9 buffer[0],
10 buffer[0x10],
11 buffer[0x1000000 - 1],
9 // workaround the dreaded decl_val
10 (&buffer)[0],
11 (&buffer)[0x10],
12 (&buffer)[0x1000000 - 1],
1213 });
1314}
test/src/Debugger.zig-1
......@@ -9,7 +9,6 @@ pub const Options = struct {
99 lldb: ?[]const u8,
1010 optimize_modes: []const std.builtin.OptimizeMode,
1111 skip_single_threaded: bool,
12 skip_non_native: bool,
1312 skip_libc: bool,
1413};
1514
test/standalone/mix_c_files/build.zig+2
......@@ -24,6 +24,8 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
2424 .optimize = optimize,
2525 .link_libc = true,
2626 }),
27 // extern threadlocals are not implemented in the self-hosted linker
28 .use_llvm = true,
2729 });
2830 exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &[_][]const u8{"-std=c11"} });
2931
test/standalone/stack_iterator/build.zig+6
......@@ -52,6 +52,8 @@ pub fn build(b: *std.Build) void {
5252 .unwind_tables = .@"async",
5353 .omit_frame_pointer = true,
5454 }),
55 // self-hosted lacks omit_frame_pointer support
56 .use_llvm = true,
5557 });
5658
5759 const run_cmd = b.addRunArtifact(exe);
......@@ -97,6 +99,8 @@ pub fn build(b: *std.Build) void {
9799 .unwind_tables = if (target.result.os.tag.isDarwin()) .@"async" else null,
98100 .omit_frame_pointer = true,
99101 }),
102 // zig objcopy doesn't support incremental binaries
103 .use_llvm = true,
100104 });
101105
102106 exe.linkLibrary(c_shared_lib);
......@@ -137,6 +141,8 @@ pub fn build(b: *std.Build) void {
137141 .unwind_tables = null,
138142 .omit_frame_pointer = false,
139143 }),
144 // self-hosted lacks omit_frame_pointer support
145 .use_llvm = true,
140146 });
141147
142148 // This "freestanding" binary is runnable because it invokes the
test/tests.zig+52-15
......@@ -1113,8 +1113,6 @@ const test_targets = blk: {
11131113 .os_tag = .linux,
11141114 .abi = .none,
11151115 },
1116 .use_llvm = false,
1117 .use_lld = false,
11181116 },
11191117 .{
11201118 .target = .{
......@@ -1123,8 +1121,6 @@ const test_targets = blk: {
11231121 .os_tag = .linux,
11241122 .abi = .none,
11251123 },
1126 .use_llvm = false,
1127 .use_lld = false,
11281124 .pic = true,
11291125 },
11301126 .{
......@@ -1134,8 +1130,6 @@ const test_targets = blk: {
11341130 .os_tag = .linux,
11351131 .abi = .none,
11361132 },
1137 .use_llvm = false,
1138 .use_lld = false,
11391133 .strip = true,
11401134 },
11411135 .{
......@@ -1144,6 +1138,8 @@ const test_targets = blk: {
11441138 .os_tag = .linux,
11451139 .abi = .none,
11461140 },
1141 .use_llvm = true,
1142 .use_lld = true,
11471143 },
11481144 .{
11491145 .target = .{
......@@ -1602,7 +1598,9 @@ const c_abi_targets = blk: {
16021598 break :blk [_]CAbiTarget{
16031599 // Native Targets
16041600
1605 .{},
1601 .{
1602 .use_llvm = true,
1603 },
16061604
16071605 // Linux Targets
16081606
......@@ -1841,7 +1839,6 @@ const c_abi_targets = blk: {
18411839 .abi = .musl,
18421840 },
18431841 .use_llvm = false,
1844 .use_lld = false,
18451842 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
18461843 },
18471844 .{
......@@ -1852,7 +1849,6 @@ const c_abi_targets = blk: {
18521849 .abi = .musl,
18531850 },
18541851 .use_llvm = false,
1855 .use_lld = false,
18561852 .strip = true,
18571853 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
18581854 },
......@@ -1864,7 +1860,6 @@ const c_abi_targets = blk: {
18641860 .abi = .musl,
18651861 },
18661862 .use_llvm = false,
1867 .use_lld = false,
18681863 .pic = true,
18691864 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
18701865 },
......@@ -1874,6 +1869,7 @@ const c_abi_targets = blk: {
18741869 .os_tag = .linux,
18751870 .abi = .musl,
18761871 },
1872 .use_llvm = true,
18771873 },
18781874 .{
18791875 .target = .{
......@@ -1881,6 +1877,7 @@ const c_abi_targets = blk: {
18811877 .os_tag = .linux,
18821878 .abi = .muslx32,
18831879 },
1880 .use_llvm = true,
18841881 },
18851882
18861883 // WASI Targets
......@@ -2276,8 +2273,13 @@ const ModuleTestOptions = struct {
22762273 include_paths: []const []const u8,
22772274 skip_single_threaded: bool,
22782275 skip_non_native: bool,
2276 skip_freebsd: bool,
2277 skip_netbsd: bool,
2278 skip_windows: bool,
2279 skip_macos: bool,
2280 skip_linux: bool,
2281 skip_llvm: bool,
22792282 skip_libc: bool,
2280 use_llvm: ?bool = null,
22812283 max_rss: usize = 0,
22822284 no_builtin: bool = false,
22832285 build_options: ?*std.Build.Step.Options = null,
......@@ -2298,6 +2300,15 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
22982300 if (options.skip_non_native and !test_target.target.isNative())
22992301 continue;
23002302
2303 if (options.skip_freebsd and test_target.target.os_tag == .freebsd) continue;
2304 if (options.skip_netbsd and test_target.target.os_tag == .netbsd) continue;
2305 if (options.skip_windows and test_target.target.os_tag == .windows) continue;
2306 if (options.skip_macos and test_target.target.os_tag == .macos) continue;
2307 if (options.skip_linux and test_target.target.os_tag == .linux) continue;
2308
2309 const would_use_llvm = wouldUseLlvm(test_target.use_llvm, test_target.target, test_target.optimize_mode);
2310 if (options.skip_llvm and would_use_llvm) continue;
2311
23012312 const resolved_target = b.resolveTargetQuery(test_target.target);
23022313 const target = resolved_target.result;
23032314 const triple_txt = target.zigTriple(b.allocator) catch @panic("OOM");
......@@ -2318,10 +2329,6 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
23182329 if (options.skip_single_threaded and test_target.single_threaded == true)
23192330 continue;
23202331
2321 if (options.use_llvm) |use_llvm| {
2322 if (test_target.use_llvm != use_llvm) continue;
2323 }
2324
23252332 // TODO get compiler-rt tests passing for self-hosted backends.
23262333 if ((target.cpu.arch != .x86_64 or target.ofmt != .elf) and
23272334 test_target.use_llvm == false and mem.eql(u8, options.name, "compiler-rt"))
......@@ -2501,9 +2508,31 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
25012508 return step;
25022509}
25032510
2511fn wouldUseLlvm(use_llvm: ?bool, query: std.Target.Query, optimize_mode: OptimizeMode) bool {
2512 if (use_llvm) |x| return x;
2513 if (query.ofmt == .c) return false;
2514 switch (optimize_mode) {
2515 .Debug => {},
2516 else => return true,
2517 }
2518 const cpu_arch = query.cpu_arch orelse builtin.cpu.arch;
2519 switch (cpu_arch) {
2520 .x86_64 => if (std.Target.ptrBitWidth_arch_abi(cpu_arch, query.abi orelse .none) != 64) return true,
2521 .spirv, .spirv32, .spirv64 => return false,
2522 else => return true,
2523 }
2524 return false;
2525}
2526
25042527const CAbiTestOptions = struct {
25052528 test_target_filters: []const []const u8,
25062529 skip_non_native: bool,
2530 skip_freebsd: bool,
2531 skip_netbsd: bool,
2532 skip_windows: bool,
2533 skip_macos: bool,
2534 skip_linux: bool,
2535 skip_llvm: bool,
25072536 skip_release: bool,
25082537};
25092538
......@@ -2517,6 +2546,14 @@ pub fn addCAbiTests(b: *std.Build, options: CAbiTestOptions) *Step {
25172546
25182547 for (c_abi_targets) |c_abi_target| {
25192548 if (options.skip_non_native and !c_abi_target.target.isNative()) continue;
2549 if (options.skip_freebsd and c_abi_target.target.os_tag == .freebsd) continue;
2550 if (options.skip_netbsd and c_abi_target.target.os_tag == .netbsd) continue;
2551 if (options.skip_windows and c_abi_target.target.os_tag == .windows) continue;
2552 if (options.skip_macos and c_abi_target.target.os_tag == .macos) continue;
2553 if (options.skip_linux and c_abi_target.target.os_tag == .linux) continue;
2554
2555 const would_use_llvm = wouldUseLlvm(c_abi_target.use_llvm, c_abi_target.target, .Debug);
2556 if (options.skip_llvm and would_use_llvm) continue;
25202557
25212558 const resolved_target = b.resolveTargetQuery(c_abi_target.target);
25222559 const target = resolved_target.result;
tools/doctest.zig+44-1
......@@ -168,6 +168,15 @@ fn printOutput(
168168 try build_args.appendSlice(&[_][]const u8{ "-target", triple });
169169 try shell_out.print("-target {s} ", .{triple});
170170 }
171 if (code.use_llvm) |use_llvm| {
172 if (use_llvm) {
173 try build_args.append("-fllvm");
174 try shell_out.print("-fllvm", .{});
175 } else {
176 try build_args.append("-fno-llvm");
177 try shell_out.print("-fno-llvm", .{});
178 }
179 }
171180 if (code.verbose_cimport) {
172181 try build_args.append("--verbose-cimport");
173182 try shell_out.print("--verbose-cimport ", .{});
......@@ -224,7 +233,6 @@ fn printOutput(
224233 break :code_block;
225234 }
226235 }
227
228236 const target_query = try std.Target.Query.parse(.{
229237 .arch_os_abi = code.target_str orelse "native",
230238 });
......@@ -319,6 +327,16 @@ fn printOutput(
319327 },
320328 }
321329 }
330 if (code.use_llvm) |use_llvm| {
331 if (use_llvm) {
332 try test_args.append("-fllvm");
333 try shell_out.print("-fllvm", .{});
334 } else {
335 try test_args.append("-fno-llvm");
336 try shell_out.print("-fno-llvm", .{});
337 }
338 }
339
322340 const result = run(arena, &env_map, tmp_dir_path, test_args.items) catch
323341 fatal("test failed", .{});
324342 const escaped_stderr = try escapeHtml(arena, result.stderr);
......@@ -469,6 +487,15 @@ fn printOutput(
469487 try build_args.appendSlice(&[_][]const u8{ "-target", triple });
470488 try shell_out.print("-target {s} ", .{triple});
471489 }
490 if (code.use_llvm) |use_llvm| {
491 if (use_llvm) {
492 try build_args.append("-fllvm");
493 try shell_out.print("-fllvm", .{});
494 } else {
495 try build_args.append("-fno-llvm");
496 try shell_out.print("-fno-llvm", .{});
497 }
498 }
472499 for (code.additional_options) |option| {
473500 try build_args.append(option);
474501 try shell_out.print("{s} ", .{option});
......@@ -538,6 +565,15 @@ fn printOutput(
538565 try test_args.appendSlice(&[_][]const u8{ "-target", triple });
539566 try shell_out.print("-target {s} ", .{triple});
540567 }
568 if (code.use_llvm) |use_llvm| {
569 if (use_llvm) {
570 try test_args.append("-fllvm");
571 try shell_out.print("-fllvm", .{});
572 } else {
573 try test_args.append("-fno-llvm");
574 try shell_out.print("-fno-llvm", .{});
575 }
576 }
541577 if (code.link_mode) |link_mode| {
542578 switch (link_mode) {
543579 .static => {
......@@ -827,6 +863,7 @@ const Code = struct {
827863 verbose_cimport: bool,
828864 just_check_syntax: bool,
829865 additional_options: []const []const u8,
866 use_llvm: ?bool,
830867
831868 const Id = union(enum) {
832869 @"test",
......@@ -886,6 +923,7 @@ fn parseManifest(arena: Allocator, source_bytes: []const u8) !Code {
886923 var link_libc = false;
887924 var disable_cache = false;
888925 var verbose_cimport = false;
926 var use_llvm: ?bool = null;
889927
890928 while (it.next()) |prefixed_line| {
891929 const line = skipPrefix(prefixed_line);
......@@ -901,6 +939,10 @@ fn parseManifest(arena: Allocator, source_bytes: []const u8) !Code {
901939 try additional_options.append(arena, line["additional_option=".len..]);
902940 } else if (mem.startsWith(u8, line, "target=")) {
903941 target_str = line["target=".len..];
942 } else if (mem.eql(u8, line, "llvm=true")) {
943 use_llvm = true;
944 } else if (mem.eql(u8, line, "llvm=false")) {
945 use_llvm = false;
904946 } else if (mem.eql(u8, line, "link_libc")) {
905947 link_libc = true;
906948 } else if (mem.eql(u8, line, "disable_cache")) {
......@@ -923,6 +965,7 @@ fn parseManifest(arena: Allocator, source_bytes: []const u8) !Code {
923965 .disable_cache = disable_cache,
924966 .verbose_cimport = verbose_cimport,
925967 .just_check_syntax = just_check_syntax,
968 .use_llvm = use_llvm,
926969 };
927970}
928971