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:...@@ -20,6 +20,14 @@ jobs:
20 uses: actions/checkout@v420 uses: actions/checkout@v4
21 - name: Build and Test21 - name: Build and Test
22 run: sh ci/x86_64-linux-debug.sh22 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
23 x86_64-linux-release:31 x86_64-linux-release:
24 timeout-minutes: 54032 timeout-minutes: 540
25 runs-on: [self-hosted, Linux, x86_64]33 runs-on: [self-hosted, Linux, x86_64]
CMakeLists.txt+1-1
...@@ -519,6 +519,7 @@ set(ZIG_STAGE2_SOURCES...@@ -519,6 +519,7 @@ set(ZIG_STAGE2_SOURCES
519 src/Air/Legalize.zig519 src/Air/Legalize.zig
520 src/Air/Liveness.zig520 src/Air/Liveness.zig
521 src/Air/Liveness/Verify.zig521 src/Air/Liveness/Verify.zig
522 src/Air/print.zig
522 src/Air/types_resolved.zig523 src/Air/types_resolved.zig
523 src/Builtin.zig524 src/Builtin.zig
524 src/Compilation.zig525 src/Compilation.zig
...@@ -675,7 +676,6 @@ set(ZIG_STAGE2_SOURCES...@@ -675,7 +676,6 @@ set(ZIG_STAGE2_SOURCES
675 src/libs/mingw.zig676 src/libs/mingw.zig
676 src/libs/musl.zig677 src/libs/musl.zig
677 src/mutable_value.zig678 src/mutable_value.zig
678 src/print_air.zig
679 src/print_env.zig679 src/print_env.zig
680 src/print_targets.zig680 src/print_targets.zig
681 src/print_value.zig681 src/print_value.zig
build.zig+44-8
...@@ -92,6 +92,12 @@ pub fn build(b: *std.Build) !void {...@@ -92,6 +92,12 @@ pub fn build(b: *std.Build) !void {
92 const skip_single_threaded = b.option(bool, "skip-single-threaded", "Main test suite skips tests that are single-threaded") orelse false;92 const skip_single_threaded = b.option(bool, "skip-single-threaded", "Main test suite skips tests that are single-threaded") orelse false;
93 const skip_translate_c = b.option(bool, "skip-translate-c", "Main test suite skips translate-c tests") orelse false;93 const skip_translate_c = b.option(bool, "skip-translate-c", "Main test suite skips translate-c tests") orelse false;
94 const skip_run_translated_c = b.option(bool, "skip-run-translated-c", "Main test suite skips run-translated-c tests") orelse false;94 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
96 const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false;102 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 {...@@ -435,10 +441,15 @@ pub fn build(b: *std.Build) !void {
435 .include_paths = &.{},441 .include_paths = &.{},
436 .skip_single_threaded = skip_single_threaded,442 .skip_single_threaded = skip_single_threaded,
437 .skip_non_native = skip_non_native,443 .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,
438 .skip_libc = skip_libc,450 .skip_libc = skip_libc,
439 .use_llvm = use_llvm,451 // 2923515904 was observed on an x86_64-linux-gnu host.
440 // 2520100864 was observed on an x86_64-linux-gnu host.452 .max_rss = 3100000000,
441 .max_rss = 2772110950,
442 }));453 }));
443454
444 test_modules_step.dependOn(tests.addModuleTests(b, .{455 test_modules_step.dependOn(tests.addModuleTests(b, .{
...@@ -452,8 +463,13 @@ pub fn build(b: *std.Build) !void {...@@ -452,8 +463,13 @@ pub fn build(b: *std.Build) !void {
452 .include_paths = &.{"test/c_import"},463 .include_paths = &.{"test/c_import"},
453 .skip_single_threaded = true,464 .skip_single_threaded = true,
454 .skip_non_native = skip_non_native,465 .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,
455 .skip_libc = skip_libc,472 .skip_libc = skip_libc,
456 .use_llvm = use_llvm,
457 }));473 }));
458474
459 test_modules_step.dependOn(tests.addModuleTests(b, .{475 test_modules_step.dependOn(tests.addModuleTests(b, .{
...@@ -467,8 +483,13 @@ pub fn build(b: *std.Build) !void {...@@ -467,8 +483,13 @@ pub fn build(b: *std.Build) !void {
467 .include_paths = &.{},483 .include_paths = &.{},
468 .skip_single_threaded = true,484 .skip_single_threaded = true,
469 .skip_non_native = skip_non_native,485 .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,
470 .skip_libc = true,492 .skip_libc = true,
471 .use_llvm = use_llvm,
472 .no_builtin = true,493 .no_builtin = true,
473 }));494 }));
474495
...@@ -483,8 +504,13 @@ pub fn build(b: *std.Build) !void {...@@ -483,8 +504,13 @@ pub fn build(b: *std.Build) !void {
483 .include_paths = &.{},504 .include_paths = &.{},
484 .skip_single_threaded = true,505 .skip_single_threaded = true,
485 .skip_non_native = skip_non_native,506 .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,
486 .skip_libc = true,513 .skip_libc = true,
487 .use_llvm = use_llvm,
488 .no_builtin = true,514 .no_builtin = true,
489 }));515 }));
490516
...@@ -499,8 +525,13 @@ pub fn build(b: *std.Build) !void {...@@ -499,8 +525,13 @@ pub fn build(b: *std.Build) !void {
499 .include_paths = &.{},525 .include_paths = &.{},
500 .skip_single_threaded = skip_single_threaded,526 .skip_single_threaded = skip_single_threaded,
501 .skip_non_native = skip_non_native,527 .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,
502 .skip_libc = skip_libc,534 .skip_libc = skip_libc,
503 .use_llvm = use_llvm,
504 // I observed a value of 5605064704 on the M2 CI.535 // I observed a value of 5605064704 on the M2 CI.
505 .max_rss = 6165571174,536 .max_rss = 6165571174,
506 }));537 }));
...@@ -536,6 +567,12 @@ pub fn build(b: *std.Build) !void {...@@ -536,6 +567,12 @@ pub fn build(b: *std.Build) !void {
536 test_step.dependOn(tests.addCAbiTests(b, .{567 test_step.dependOn(tests.addCAbiTests(b, .{
537 .test_target_filters = test_target_filters,568 .test_target_filters = test_target_filters,
538 .skip_non_native = skip_non_native,569 .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,
539 .skip_release = skip_release,576 .skip_release = skip_release,
540 }));577 }));
541 test_step.dependOn(tests.addLinkTests(b, enable_macos_sdk, enable_ios_sdk, enable_symlinks_windows));578 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 {...@@ -549,7 +586,6 @@ pub fn build(b: *std.Build) !void {
549 .lldb = b.option([]const u8, "lldb", "path to lldb binary"),586 .lldb = b.option([]const u8, "lldb", "path to lldb binary"),
550 .optimize_modes = optimization_modes,587 .optimize_modes = optimization_modes,
551 .skip_single_threaded = skip_single_threaded,588 .skip_single_threaded = skip_single_threaded,
552 .skip_non_native = skip_non_native,
553 .skip_libc = skip_libc,589 .skip_libc = skip_libc,
554 })) |test_debugger_step| test_step.dependOn(test_debugger_step);590 })) |test_debugger_step| test_step.dependOn(test_debugger_step);
555 if (tests.addLlvmIrTests(b, .{591 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...@@ -25,12 +25,6 @@ git fetch --tags
25export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache"25export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache"
26export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"26export 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
34mkdir build-debug28mkdir build-debug
35cd build-debug29cd build-debug
3630
...@@ -65,39 +59,12 @@ stage3-debug/bin/zig build test docs \...@@ -65,39 +59,12 @@ stage3-debug/bin/zig build test docs \
65 -fqemu \59 -fqemu \
66 -fwasmtime \60 -fwasmtime \
67 -Dstatic-llvm \61 -Dstatic-llvm \
62 -Dskip-freebsd \
63 -Dskip-netbsd \
64 -Dskip-windows \
65 -Dskip-macos \
66 -Dskip-llvm \
68 -Dtarget=native-native-musl \67 -Dtarget=native-native-musl \
69 --search-prefix "$PREFIX" \68 --search-prefix "$PREFIX" \
70 --zig-lib-dir "$PWD/../lib" \69 --zig-lib-dir "$PWD/../lib" \
71 -Denable-superhtml70 -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" {...@@ -19,3 +19,4 @@ test "global assembly" {
1919
20// test20// test
21// target=x86_64-linux21// target=x86_64-linux
22// llvm=true
lib/std/Target.zig+5-1
...@@ -2581,12 +2581,16 @@ pub fn standardDynamicLinkerPath(target: Target) DynamicLinker {...@@ -2581,12 +2581,16 @@ pub fn standardDynamicLinkerPath(target: Target) DynamicLinker {
2581}2581}
25822582
2583pub fn ptrBitWidth_cpu_abi(cpu: Cpu, abi: Abi) u16 {2583pub 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 {
2584 switch (abi) {2588 switch (abi) {
2585 .gnux32, .muslx32, .gnuabin32, .muslabin32, .ilp32 => return 32,2589 .gnux32, .muslx32, .gnuabin32, .muslabin32, .ilp32 => return 32,
2586 .gnuabi64, .muslabi64 => return 64,2590 .gnuabi64, .muslabi64 => return 64,
2587 else => {},2591 else => {},
2588 }2592 }
2589 return switch (cpu.arch) {2593 return switch (cpu_arch) {
2590 .avr,2594 .avr,
2591 .msp430,2595 .msp430,
2592 => 16,2596 => 16,
lib/std/builtin.zig+13-2
...@@ -61,7 +61,7 @@ pub const StackTrace = struct {...@@ -61,7 +61,7 @@ pub const StackTrace = struct {
6161
62/// This data structure is used by the Zig language code generation and62/// This data structure is used by the Zig language code generation and
63/// therefore must be kept in sync with the compiler implementation.63/// therefore must be kept in sync with the compiler implementation.
64pub const GlobalLinkage = enum {64pub const GlobalLinkage = enum(u2) {
65 internal,65 internal,
66 strong,66 strong,
67 weak,67 weak,
...@@ -70,7 +70,7 @@ pub const GlobalLinkage = enum {...@@ -70,7 +70,7 @@ pub const GlobalLinkage = enum {
7070
71/// This data structure is used by the Zig language code generation and71/// This data structure is used by the Zig language code generation and
72/// therefore must be kept in sync with the compiler implementation.72/// therefore must be kept in sync with the compiler implementation.
73pub const SymbolVisibility = enum {73pub const SymbolVisibility = enum(u2) {
74 default,74 default,
75 hidden,75 hidden,
76 protected,76 protected,
...@@ -1030,8 +1030,19 @@ pub const ExternOptions = struct {...@@ -1030,8 +1030,19 @@ pub const ExternOptions = struct {
1030 name: []const u8,1030 name: []const u8,
1031 library_name: ?[]const u8 = null,1031 library_name: ?[]const u8 = null,
1032 linkage: GlobalLinkage = .strong,1032 linkage: GlobalLinkage = .strong,
1033 visibility: SymbolVisibility = .default,
1034 /// Setting this to `true` makes the `@extern` a runtime value.
1033 is_thread_local: bool = false,1035 is_thread_local: bool = false,
1034 is_dll_import: bool = false,1036 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 };
1035};1046};
10361047
1037/// This data structure is used by the Zig language code generation and1048/// 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 {...@@ -83,13 +83,16 @@ const RDebug = extern struct {
83 r_ldbase: usize,83 r_ldbase: usize,
84};84};
8585
86/// TODO make it possible to reference this same external symbol 2x so we don't need this86/// TODO fix comparisons of extern symbol pointers so we don't need this helper function.
87/// helper function.87pub fn get_DYNAMIC() ?[*]const elf.Dyn {
88pub fn get_DYNAMIC() ?[*]elf.Dyn {88 return @extern([*]const elf.Dyn, .{
89 return @extern([*]elf.Dyn, .{ .name = "_DYNAMIC", .linkage = .weak });89 .name = "_DYNAMIC",
90 .linkage = .weak,
91 .visibility = .hidden,
92 });
90}93}
9194
92pub fn linkmap_iterator(phdrs: []elf.Phdr) error{InvalidExe}!LinkMap.Iterator {95pub fn linkmap_iterator(phdrs: []const elf.Phdr) error{InvalidExe}!LinkMap.Iterator {
93 _ = phdrs;96 _ = phdrs;
94 const _DYNAMIC = get_DYNAMIC() orelse {97 const _DYNAMIC = get_DYNAMIC() orelse {
95 // No PT_DYNAMIC means this is either a statically-linked program or a98 // 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) {...@@ -39,167 +39,175 @@ const R_RELATIVE = switch (builtin.cpu.arch) {
39// Obtain a pointer to the _DYNAMIC array.39// Obtain a pointer to the _DYNAMIC array.
40// We have to compute its address as a PC-relative quantity not to require a40// We have to compute its address as a PC-relative quantity not to require a
41// relocation that, at this point, is not yet applied.41// relocation that, at this point, is not yet applied.
42inline fn getDynamicSymbol() [*]elf.Dyn {42inline fn getDynamicSymbol() [*]const elf.Dyn {
43 return switch (builtin.cpu.arch) {43 return switch (builtin.zig_backend) {
44 .x86 => asm volatile (44 else => switch (builtin.cpu.arch) {
45 \\ .weak _DYNAMIC45 .x86 => asm volatile (
46 \\ .hidden _DYNAMIC46 \\ .weak _DYNAMIC
47 \\ call 1f47 \\ .hidden _DYNAMIC
48 \\ 1: pop %[ret]48 \\ call 1f
49 \\ lea _DYNAMIC-1b(%[ret]), %[ret]49 \\ 1: pop %[ret]
50 : [ret] "=r" (-> [*]elf.Dyn),50 \\ lea _DYNAMIC-1b(%[ret]), %[ret]
51 ),51 : [ret] "=r" (-> [*]const elf.Dyn),
52 .x86_64 => asm volatile (52 ),
53 \\ .weak _DYNAMIC53 .x86_64 => asm volatile (
54 \\ .hidden _DYNAMIC54 \\ .weak _DYNAMIC
55 \\ lea _DYNAMIC(%%rip), %[ret]55 \\ .hidden _DYNAMIC
56 : [ret] "=r" (-> [*]elf.Dyn),56 \\ lea _DYNAMIC(%%rip), %[ret]
57 ),57 : [ret] "=r" (-> [*]const elf.Dyn),
58 .arc => asm volatile (58 ),
59 \\ .weak _DYNAMIC59 .arc => asm volatile (
60 \\ .hidden _DYNAMIC60 \\ .weak _DYNAMIC
61 \\ add %[ret], pcl, _DYNAMIC@pcl61 \\ .hidden _DYNAMIC
62 : [ret] "=r" (-> [*]elf.Dyn),62 \\ add %[ret], pcl, _DYNAMIC@pcl
63 ),63 : [ret] "=r" (-> [*]const elf.Dyn),
64 // Work around the limited offset range of `ldr`64 ),
65 .arm, .armeb, .thumb, .thumbeb => asm volatile (65 // Work around the limited offset range of `ldr`
66 \\ .weak _DYNAMIC66 .arm, .armeb, .thumb, .thumbeb => asm volatile (
67 \\ .hidden _DYNAMIC67 \\ .weak _DYNAMIC
68 \\ ldr %[ret], 1f68 \\ .hidden _DYNAMIC
69 \\ add %[ret], pc69 \\ ldr %[ret], 1f
70 \\ b 2f70 \\ add %[ret], pc
71 \\ 1: .word _DYNAMIC-1b71 \\ b 2f
72 \\ 2:72 \\ 1: .word _DYNAMIC-1b
73 : [ret] "=r" (-> [*]elf.Dyn),73 \\ 2:
74 ),74 : [ret] "=r" (-> [*]const elf.Dyn),
75 // A simple `adr` is not enough as it has a limited offset range75 ),
76 .aarch64, .aarch64_be => asm volatile (76 // A simple `adr` is not enough as it has a limited offset range
77 \\ .weak _DYNAMIC77 .aarch64, .aarch64_be => asm volatile (
78 \\ .hidden _DYNAMIC78 \\ .weak _DYNAMIC
79 \\ adrp %[ret], _DYNAMIC79 \\ .hidden _DYNAMIC
80 \\ add %[ret], %[ret], #:lo12:_DYNAMIC80 \\ adrp %[ret], _DYNAMIC
81 : [ret] "=r" (-> [*]elf.Dyn),81 \\ add %[ret], %[ret], #:lo12:_DYNAMIC
82 ),82 : [ret] "=r" (-> [*]const elf.Dyn),
83 // The CSKY ABI requires the gb register to point to the GOT. Additionally, the first83 ),
84 // entry in the GOT is defined to hold the address of _DYNAMIC.84 // The CSKY ABI requires the gb register to point to the GOT. Additionally, the first
85 .csky => asm volatile (85 // entry in the GOT is defined to hold the address of _DYNAMIC.
86 \\ mov %[ret], gb86 .csky => asm volatile (
87 \\ ldw %[ret], %[ret]87 \\ mov %[ret], gb
88 : [ret] "=r" (-> [*]elf.Dyn),88 \\ ldw %[ret], %[ret]
89 ),89 : [ret] "=r" (-> [*]const elf.Dyn),
90 .hexagon => asm volatile (90 ),
91 \\ .weak _DYNAMIC91 .hexagon => asm volatile (
92 \\ .hidden _DYNAMIC92 \\ .weak _DYNAMIC
93 \\ jump 1f93 \\ .hidden _DYNAMIC
94 \\ .word _DYNAMIC - .94 \\ jump 1f
95 \\ 1:95 \\ .word _DYNAMIC - .
96 \\ r1 = pc96 \\ 1:
97 \\ r1 = add(r1, #-4)97 \\ r1 = pc
98 \\ %[ret] = memw(r1)98 \\ r1 = add(r1, #-4)
99 \\ %[ret] = add(r1, %[ret])99 \\ %[ret] = memw(r1)
100 : [ret] "=r" (-> [*]elf.Dyn),100 \\ %[ret] = add(r1, %[ret])
101 :101 : [ret] "=r" (-> [*]const elf.Dyn),
102 : "r1"102 :
103 ),103 : "r1"
104 .loongarch32, .loongarch64 => asm volatile (104 ),
105 \\ .weak _DYNAMIC105 .loongarch32, .loongarch64 => asm volatile (
106 \\ .hidden _DYNAMIC106 \\ .weak _DYNAMIC
107 \\ la.local %[ret], _DYNAMIC107 \\ .hidden _DYNAMIC
108 : [ret] "=r" (-> [*]elf.Dyn),108 \\ la.local %[ret], _DYNAMIC
109 ),109 : [ret] "=r" (-> [*]const elf.Dyn),
110 // Note that the - 8 is needed because pc in the second lea instruction points into the110 ),
111 // middle of that instruction. (The first lea is 6 bytes, the second is 4 bytes.)111 // Note that the - 8 is needed because pc in the second lea instruction points into the
112 .m68k => asm volatile (112 // middle of that instruction. (The first lea is 6 bytes, the second is 4 bytes.)
113 \\ .weak _DYNAMIC113 .m68k => asm volatile (
114 \\ .hidden _DYNAMIC114 \\ .weak _DYNAMIC
115 \\ lea _DYNAMIC - . - 8, %[ret]115 \\ .hidden _DYNAMIC
116 \\ lea (%[ret], %%pc), %[ret]116 \\ lea _DYNAMIC - . - 8, %[ret]
117 : [ret] "=r" (-> [*]elf.Dyn),117 \\ lea (%[ret], %%pc), %[ret]
118 ),118 : [ret] "=r" (-> [*]const elf.Dyn),
119 .mips, .mipsel => asm volatile (119 ),
120 \\ .weak _DYNAMIC120 .mips, .mipsel => asm volatile (
121 \\ .hidden _DYNAMIC121 \\ .weak _DYNAMIC
122 \\ bal 1f122 \\ .hidden _DYNAMIC
123 \\ .gpword _DYNAMIC123 \\ bal 1f
124 \\ 1:124 \\ .gpword _DYNAMIC
125 \\ lw %[ret], 0($ra)125 \\ 1:
126 \\ addu %[ret], %[ret], $gp126 \\ lw %[ret], 0($ra)
127 : [ret] "=r" (-> [*]elf.Dyn),127 \\ addu %[ret], %[ret], $gp
128 :128 : [ret] "=r" (-> [*]const elf.Dyn),
129 : "lr"129 :
130 ),130 : "lr"
131 .mips64, .mips64el => asm volatile (131 ),
132 \\ .weak _DYNAMIC132 .mips64, .mips64el => asm volatile (
133 \\ .hidden _DYNAMIC133 \\ .weak _DYNAMIC
134 \\ .balign 8134 \\ .hidden _DYNAMIC
135 \\ bal 1f135 \\ .balign 8
136 \\ .gpdword _DYNAMIC136 \\ bal 1f
137 \\ 1:137 \\ .gpdword _DYNAMIC
138 \\ ld %[ret], 0($ra)138 \\ 1:
139 \\ daddu %[ret], %[ret], $gp139 \\ ld %[ret], 0($ra)
140 : [ret] "=r" (-> [*]elf.Dyn),140 \\ daddu %[ret], %[ret], $gp
141 :141 : [ret] "=r" (-> [*]const elf.Dyn),
142 : "lr"142 :
143 ),143 : "lr"
144 .powerpc, .powerpcle => asm volatile (144 ),
145 \\ .weak _DYNAMIC145 .powerpc, .powerpcle => asm volatile (
146 \\ .hidden _DYNAMIC146 \\ .weak _DYNAMIC
147 \\ bl 1f147 \\ .hidden _DYNAMIC
148 \\ .long _DYNAMIC - .148 \\ bl 1f
149 \\ 1:149 \\ .long _DYNAMIC - .
150 \\ mflr %[ret]150 \\ 1:
151 \\ lwz 4, 0(%[ret])151 \\ mflr %[ret]
152 \\ add %[ret], 4, %[ret]152 \\ lwz 4, 0(%[ret])
153 : [ret] "=r" (-> [*]elf.Dyn),153 \\ add %[ret], 4, %[ret]
154 :154 : [ret] "=r" (-> [*]const elf.Dyn),
155 : "lr", "r4"155 :
156 ),156 : "lr", "r4"
157 .powerpc64, .powerpc64le => asm volatile (157 ),
158 \\ .weak _DYNAMIC158 .powerpc64, .powerpc64le => asm volatile (
159 \\ .hidden _DYNAMIC159 \\ .weak _DYNAMIC
160 \\ bl 1f160 \\ .hidden _DYNAMIC
161 \\ .quad _DYNAMIC - .161 \\ bl 1f
162 \\ 1:162 \\ .quad _DYNAMIC - .
163 \\ mflr %[ret]163 \\ 1:
164 \\ ld 4, 0(%[ret])164 \\ mflr %[ret]
165 \\ add %[ret], 4, %[ret]165 \\ ld 4, 0(%[ret])
166 : [ret] "=r" (-> [*]elf.Dyn),166 \\ add %[ret], 4, %[ret]
167 :167 : [ret] "=r" (-> [*]const elf.Dyn),
168 : "lr", "r4"168 :
169 ),169 : "lr", "r4"
170 .riscv32, .riscv64 => asm volatile (170 ),
171 \\ .weak _DYNAMIC171 .riscv32, .riscv64 => asm volatile (
172 \\ .hidden _DYNAMIC172 \\ .weak _DYNAMIC
173 \\ lla %[ret], _DYNAMIC173 \\ .hidden _DYNAMIC
174 : [ret] "=r" (-> [*]elf.Dyn),174 \\ lla %[ret], _DYNAMIC
175 ),175 : [ret] "=r" (-> [*]const elf.Dyn),
176 .s390x => asm volatile (176 ),
177 \\ .weak _DYNAMIC177 .s390x => asm volatile (
178 \\ .hidden _DYNAMIC178 \\ .weak _DYNAMIC
179 \\ larl %[ret], 1f179 \\ .hidden _DYNAMIC
180 \\ ag %[ret], 0(%[ret])180 \\ larl %[ret], 1f
181 \\ jg 2f181 \\ ag %[ret], 0(%[ret])
182 \\ 1: .quad _DYNAMIC - .182 \\ jg 2f
183 \\ 2:183 \\ 1: .quad _DYNAMIC - .
184 : [ret] "=r" (-> [*]elf.Dyn),184 \\ 2:
185 ),185 : [ret] "=r" (-> [*]const elf.Dyn),
186 // The compiler does not necessarily have any obligation to load the `l7` register (pointing186 ),
187 // to the GOT), so do it ourselves just in case.187 // The compiler does not necessarily have any obligation to load the `l7` register (pointing
188 .sparc, .sparc64 => asm volatile (188 // to the GOT), so do it ourselves just in case.
189 \\ sethi %%hi(_GLOBAL_OFFSET_TABLE_ - 4), %%l7189 .sparc, .sparc64 => asm volatile (
190 \\ call 1f190 \\ sethi %%hi(_GLOBAL_OFFSET_TABLE_ - 4), %%l7
191 \\ add %%l7, %%lo(_GLOBAL_OFFSET_TABLE_ + 4), %%l7191 \\ call 1f
192 \\ 1:192 \\ add %%l7, %%lo(_GLOBAL_OFFSET_TABLE_ + 4), %%l7
193 \\ add %%l7, %%o7, %[ret]193 \\ 1:
194 : [ret] "=r" (-> [*]elf.Dyn),194 \\ add %%l7, %%o7, %[ret]
195 ),195 : [ret] "=r" (-> [*]const elf.Dyn),
196 else => {196 ),
197 @compileError("PIE startup is not yet supported for this target!");197 else => {
198 @compileError("PIE startup is not yet supported for this target!");
199 },
198 },200 },
201 .stage2_x86_64 => @extern([*]const elf.Dyn, .{
202 .name = "_DYNAMIC",
203 .linkage = .weak,
204 .visibility = .hidden,
205 .relocation = .pcrel,
206 }).?,
199 };207 };
200}208}
201209
202pub fn relocate(phdrs: []elf.Phdr) void {210pub fn relocate(phdrs: []const elf.Phdr) void {
203 @setRuntimeSafety(false);211 @setRuntimeSafety(false);
204 @disableInstrumentation();212 @disableInstrumentation();
205213
...@@ -256,10 +264,9 @@ pub fn relocate(phdrs: []elf.Phdr) void {...@@ -256,10 +264,9 @@ pub fn relocate(phdrs: []elf.Phdr) void {
256264
257 const rel = sorted_dynv[elf.DT_REL];265 const rel = sorted_dynv[elf.DT_REL];
258 if (rel != 0) {266 if (rel != 0) {
259 const rels = @call(.always_inline, std.mem.bytesAsSlice, .{267 const rels: []const elf.Rel = @alignCast(@ptrCast(
260 elf.Rel,268 @as([*]align(@alignOf(elf.Rel)) const u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]],
261 @as([*]u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]],269 ));
262 });
263 for (rels) |r| {270 for (rels) |r| {
264 if (r.r_type() != R_RELATIVE) continue;271 if (r.r_type() != R_RELATIVE) continue;
265 @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr;272 @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr;
...@@ -268,10 +275,9 @@ pub fn relocate(phdrs: []elf.Phdr) void {...@@ -268,10 +275,9 @@ pub fn relocate(phdrs: []elf.Phdr) void {
268275
269 const rela = sorted_dynv[elf.DT_RELA];276 const rela = sorted_dynv[elf.DT_RELA];
270 if (rela != 0) {277 if (rela != 0) {
271 const relas = @call(.always_inline, std.mem.bytesAsSlice, .{278 const relas: []const elf.Rela = @alignCast(@ptrCast(
272 elf.Rela,279 @as([*]align(@alignOf(elf.Rela)) const u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]],
273 @as([*]u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]],280 ));
274 });
275 for (relas) |r| {281 for (relas) |r| {
276 if (r.r_type() != R_RELATIVE) continue;282 if (r.r_type() != R_RELATIVE) continue;
277 @as(*usize, @ptrFromInt(base_addr + r.r_offset)).* = base_addr + @as(usize, @bitCast(r.r_addend));283 @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 {...@@ -280,10 +286,9 @@ pub fn relocate(phdrs: []elf.Phdr) void {
280286
281 const relr = sorted_dynv[elf.DT_RELR];287 const relr = sorted_dynv[elf.DT_RELR];
282 if (relr != 0) {288 if (relr != 0) {
283 const relrs = @call(.always_inline, std.mem.bytesAsSlice, .{289 const relrs: []const elf.Relr = @ptrCast(
284 elf.Relr,290 @as([*]align(@alignOf(elf.Relr)) const u8, @ptrFromInt(base_addr + relr))[0..sorted_dynv[elf.DT_RELRSZ]],
285 @as([*]u8, @ptrFromInt(base_addr + relr))[0..sorted_dynv[elf.DT_RELRSZ]],291 );
286 });
287 var current: [*]usize = undefined;292 var current: [*]usize = undefined;
288 for (relrs) |r| {293 for (relrs) |r| {
289 if ((r & 1) == 0) {294 if ((r & 1) == 0) {
lib/std/start.zig+6-6
...@@ -163,7 +163,7 @@ fn exit2(code: usize) noreturn {...@@ -163,7 +163,7 @@ fn exit2(code: usize) noreturn {
163 // exits(0)163 // exits(0)
164 .plan9 => std.os.plan9.exits(null),164 .plan9 => std.os.plan9.exits(null),
165 .windows => {165 .windows => {
166 std.os.windows.ntdll.RtlExitUserProcess(@as(u32, @truncate(code)));166 std.os.windows.ntdll.RtlExitUserProcess(@truncate(code));
167 },167 },
168 else => @compileError("TODO"),168 else => @compileError("TODO"),
169 }169 }
...@@ -511,7 +511,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {...@@ -511,7 +511,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
511 // Code coverage instrumentation might try to use thread local variables.511 // Code coverage instrumentation might try to use thread local variables.
512 @disableInstrumentation();512 @disableInstrumentation();
513 const argc = argc_argv_ptr[0];513 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
516 const envp_optional: [*:null]?[*:0]u8 = @ptrCast(@alignCast(argv + argc + 1));516 const envp_optional: [*:null]?[*:0]u8 = @ptrCast(@alignCast(argv + argc + 1));
517 var envp_count: usize = 0;517 var envp_count: usize = 0;
...@@ -573,11 +573,11 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {...@@ -573,11 +573,11 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
573 expandStackSize(phdrs);573 expandStackSize(phdrs);
574 }574 }
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, .{
577 .name = "__init_array_start",577 .name = "__init_array_start",
578 .linkage = .weak,578 .linkage = .weak,
579 });579 });
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, .{
581 .name = "__init_array_end",581 .name = "__init_array_end",
582 .linkage = .weak,582 .linkage = .weak,
583 });583 });
...@@ -651,7 +651,7 @@ fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) cal...@@ -651,7 +651,7 @@ fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) cal
651}651}
652652
653fn mainWithoutEnv(c_argc: c_int, c_argv: [*][*:0]c_char) callconv(.c) c_int {653fn 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)];
655 return callMain();655 return callMain();
656}656}
657657
...@@ -701,7 +701,7 @@ pub inline fn callMain() u8 {...@@ -701,7 +701,7 @@ pub inline fn callMain() u8 {
701pub fn call_wWinMain() std.os.windows.INT {701pub fn call_wWinMain() std.os.windows.INT {
702 const peb = std.os.windows.peb();702 const peb = std.os.windows.peb();
703 const MAIN_HINSTANCE = @typeInfo(@TypeOf(root.wWinMain)).@"fn".params[0].type.?;703 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);
705 const lpCmdLine: [*:0]u16 = @ptrCast(peb.ProcessParameters.CommandLine.Buffer);705 const lpCmdLine: [*:0]u16 = @ptrCast(peb.ProcessParameters.CommandLine.Buffer);
706706
707 // There are various types used for the 'show window' variable through the Win32 APIs:707 // 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) {...@@ -1823,6 +1823,14 @@ pub const Visibility = enum(u2) {
1823 hidden = 1,1823 hidden = 1,
1824 protected = 2,1824 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
1826 pub fn format(1834 pub fn format(
1827 self: Visibility,1835 self: Visibility,
1828 comptime _: []const u8,1836 comptime _: []const u8,
...@@ -2555,6 +2563,10 @@ pub const Variable = struct {...@@ -2555,6 +2563,10 @@ pub const Variable = struct {
2555 return self.ptrConst(builder).global.setLinkage(linkage, builder);2563 return self.ptrConst(builder).global.setLinkage(linkage, builder);
2556 }2564 }
25572565
2566 pub fn setVisibility(self: Index, visibility: Visibility, builder: *Builder) void {
2567 return self.ptrConst(builder).global.setVisibility(visibility, builder);
2568 }
2569
2558 pub fn setDllStorageClass(self: Index, class: DllStorageClass, builder: *Builder) void {2570 pub fn setDllStorageClass(self: Index, class: DllStorageClass, builder: *Builder) void {
2559 return self.ptrConst(builder).global.setDllStorageClass(class, builder);2571 return self.ptrConst(builder).global.setDllStorageClass(class, builder);
2560 }2572 }
lib/zig.h+9
...@@ -272,6 +272,15 @@...@@ -272,6 +272,15 @@
272#define zig_linksection_fn zig_linksection272#define zig_linksection_fn zig_linksection
273#endif273#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
275#if zig_has_builtin(unreachable) || defined(zig_gcc) || defined(zig_tinyc)284#if zig_has_builtin(unreachable) || defined(zig_gcc) || defined(zig_tinyc)
276#define zig_unreachable() __builtin_unreachable()285#define zig_unreachable() __builtin_unreachable()
277#elif defined(zig_msvc)286#elif defined(zig_msvc)
src/Air.zig+10-4
...@@ -13,6 +13,7 @@ const InternPool = @import("InternPool.zig");...@@ -13,6 +13,7 @@ const InternPool = @import("InternPool.zig");
13const Type = @import("Type.zig");13const Type = @import("Type.zig");
14const Value = @import("Value.zig");14const Value = @import("Value.zig");
15const Zcu = @import("Zcu.zig");15const Zcu = @import("Zcu.zig");
16const print = @import("Air/print.zig");
16const types_resolved = @import("Air/types_resolved.zig");17const types_resolved = @import("Air/types_resolved.zig");
1718
18pub const Legalize = @import("Air/Legalize.zig");19pub const Legalize = @import("Air/Legalize.zig");
...@@ -863,16 +864,17 @@ pub const Inst = struct {...@@ -863,16 +864,17 @@ pub const Inst = struct {
863 /// Uses the `vector_store_elem` field.864 /// Uses the `vector_store_elem` field.
864 vector_store_elem,865 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:
867 ///868 ///
868 /// * `threadlocal var`869 /// * `threadlocal var`
869 /// * `extern threadlocal var` (or corresponding `@extern`)870 /// * `extern threadlocal var` (or corresponding `@extern`)
870 /// * `@extern` with `.is_dll_import = true`871 /// * `@extern` with `.is_dll_import = true`
872 /// * `@extern` with `.relocation = .pcrel`
871 ///873 ///
872 /// Such pointers are runtime values, so cannot be represented with an InternPool index.874 /// Such pointers are runtime values, so cannot be represented with an InternPool index.
873 ///875 ///
874 /// Uses the `ty_nav` field.876 /// Uses the `ty_nav` field.
875 tlv_dllimport_ptr,877 runtime_nav_ptr,
876878
877 /// Implements @cVaArg builtin.879 /// Implements @cVaArg builtin.
878 /// Uses the `ty_op` field.880 /// Uses the `ty_op` field.
...@@ -1708,7 +1710,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)...@@ -1708,7 +1710,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
1708 return .fromInterned(ip.indexToKey(err_union_ty.ip_index).error_union_type.payload_type);1710 return .fromInterned(ip.indexToKey(err_union_ty.ip_index).error_union_type.payload_type);
1709 },1711 },
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
1713 .work_item_id,1715 .work_item_id,
1714 .work_group_size,1716 .work_group_size,
...@@ -1983,7 +1985,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {...@@ -1983,7 +1985,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
1983 .err_return_trace,1985 .err_return_trace,
1984 .addrspace_cast,1986 .addrspace_cast,
1985 .save_err_return_trace_index,1987 .save_err_return_trace_index,
1986 .tlv_dllimport_ptr,1988 .runtime_nav_ptr,
1987 .work_item_id,1989 .work_item_id,
1988 .work_group_size,1990 .work_group_size,
1989 .work_group_id,1991 .work_group_id,
...@@ -2141,6 +2143,10 @@ pub const typesFullyResolved = types_resolved.typesFullyResolved;...@@ -2141,6 +2143,10 @@ pub const typesFullyResolved = types_resolved.typesFullyResolved;
2141pub const typeFullyResolved = types_resolved.checkType;2143pub const typeFullyResolved = types_resolved.checkType;
2142pub const valFullyResolved = types_resolved.checkVal;2144pub const valFullyResolved = types_resolved.checkVal;
2143pub const legalize = Legalize.legalize;2145pub 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
2145pub const CoveragePoint = enum(u1) {2151pub const CoveragePoint = enum(u1) {
2146 /// Indicates the block is not a place of interest corresponding to2152 /// 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 {...@@ -622,7 +622,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
622 .addrspace_cast,622 .addrspace_cast,
623 .save_err_return_trace_index,623 .save_err_return_trace_index,
624 .vector_store_elem,624 .vector_store_elem,
625 .tlv_dllimport_ptr,625 .runtime_nav_ptr,
626 .c_va_arg,626 .c_va_arg,
627 .c_va_copy,627 .c_va_copy,
628 .c_va_end,628 .c_va_end,
src/Air/Liveness.zig+2-2
...@@ -339,7 +339,7 @@ pub fn categorizeOperand(...@@ -339,7 +339,7 @@ pub fn categorizeOperand(
339 .wasm_memory_size,339 .wasm_memory_size,
340 .err_return_trace,340 .err_return_trace,
341 .save_err_return_trace_index,341 .save_err_return_trace_index,
342 .tlv_dllimport_ptr,342 .runtime_nav_ptr,
343 .c_va_start,343 .c_va_start,
344 .work_item_id,344 .work_item_id,
345 .work_group_size,345 .work_group_size,
...@@ -972,7 +972,7 @@ fn analyzeInst(...@@ -972,7 +972,7 @@ fn analyzeInst(
972 .wasm_memory_size,972 .wasm_memory_size,
973 .err_return_trace,973 .err_return_trace,
974 .save_err_return_trace_index,974 .save_err_return_trace_index,
975 .tlv_dllimport_ptr,975 .runtime_nav_ptr,
976 .c_va_start,976 .c_va_start,
977 .work_item_id,977 .work_item_id,
978 .work_group_size,978 .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 {...@@ -63,7 +63,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
63 .wasm_memory_size,63 .wasm_memory_size,
64 .err_return_trace,64 .err_return_trace,
65 .save_err_return_trace_index,65 .save_err_return_trace_index,
66 .tlv_dllimport_ptr,66 .runtime_nav_ptr,
67 .c_va_start,67 .c_va_start,
68 .work_item_id,68 .work_item_id,
69 .work_group_size,69 .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 {...@@ -321,7 +321,7 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
321 if (!checkRef(bin.rhs, zcu)) return false;321 if (!checkRef(bin.rhs, zcu)) return false;
322 },322 },
323323
324 .tlv_dllimport_ptr => {324 .runtime_nav_ptr => {
325 if (!checkType(.fromInterned(data.ty_nav.ty), zcu)) return false;325 if (!checkType(.fromInterned(data.ty_nav.ty), zcu)) return false;
326 },326 },
327327
src/Compilation.zig+9-6
...@@ -774,7 +774,7 @@ pub const Directories = struct {...@@ -774,7 +774,7 @@ pub const Directories = struct {
774/// `comp.debug_incremental`. It is inline so that comptime-known `false` propagates to the caller,774/// `comp.debug_incremental`. It is inline so that comptime-known `false` propagates to the caller,
775/// preventing debugging features from making it into release builds of the compiler.775/// preventing debugging features from making it into release builds of the compiler.
776pub inline fn debugIncremental(comp: *const Compilation) bool {776pub 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;
778 return comp.debug_incremental;778 return comp.debug_incremental;
779}779}
780780
...@@ -7225,7 +7225,7 @@ fn buildOutputFromZig(...@@ -7225,7 +7225,7 @@ fn buildOutputFromZig(
7225 assert(out.* == null);7225 assert(out.* == null);
7226 out.* = crt_file;7226 out.* = crt_file;
72277227
7228 comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);7228 comp.queueLinkTaskMode(crt_file.full_object_path, &config);
7229}7229}
72307230
7231pub const CrtFileOptions = struct {7231pub const CrtFileOptions = struct {
...@@ -7349,7 +7349,7 @@ pub fn build_crt_file(...@@ -7349,7 +7349,7 @@ pub fn build_crt_file(
7349 try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node);7349 try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node);
73507350
7351 const crt_file = try sub_compilation.toCrtFile();7351 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
7354 {7354 {
7355 comp.mutex.lock();7355 comp.mutex.lock();
...@@ -7359,11 +7359,14 @@ pub fn build_crt_file(...@@ -7359,11 +7359,14 @@ pub fn build_crt_file(
7359 }7359 }
7360}7360}
73617361
7362pub fn queueLinkTaskMode(comp: *Compilation, path: Cache.Path, output_mode: std.builtin.OutputMode) void {7362pub fn queueLinkTaskMode(comp: *Compilation, path: Cache.Path, config: *const Compilation.Config) void {
7363 comp.queueLinkTasks(switch (output_mode) {7363 comp.queueLinkTasks(switch (config.output_mode) {
7364 .Exe => unreachable,7364 .Exe => unreachable,
7365 .Obj => &.{.{ .load_object = path }},7365 .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 }},
7367 });7370 });
7368}7371}
73697372
src/Compilation/Config.zig+125-113
...@@ -191,91 +191,6 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -191,91 +191,6 @@ pub fn resolve(options: Options) ResolveError!Config {
191191
192 const root_optimize_mode = options.root_optimize_mode orelse .Debug;192 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
279 // Make a decision on whether to use Clang or Aro for translate-c and compiling C files.194 // Make a decision on whether to use Clang or Aro for translate-c and compiling C files.
280 const c_frontend: CFrontend = b: {195 const c_frontend: CFrontend = b: {
281 if (!build_options.have_llvm) {196 if (!build_options.have_llvm) {
...@@ -288,19 +203,6 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -288,19 +203,6 @@ pub fn resolve(options: Options) ResolveError!Config {
288 break :b .clang;203 break :b .clang;
289 };204 };
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
304 const link_libcpp = b: {206 const link_libcpp = b: {
305 if (options.link_libcpp == true) break :b true;207 if (options.link_libcpp == true) break :b true;
306 if (options.any_sanitize_thread) {208 if (options.any_sanitize_thread) {
...@@ -314,14 +216,6 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -314,14 +216,6 @@ pub fn resolve(options: Options) ResolveError!Config {
314 break :b false;216 break :b false;
315 };217 };
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
325 const link_libc = b: {219 const link_libc = b: {
326 if (target_util.osRequiresLibC(target)) {220 if (target_util.osRequiresLibC(target)) {
327 if (options.link_libc == false) return error.OsRequiresLibC;221 if (options.link_libc == false) return error.OsRequiresLibC;
...@@ -331,7 +225,7 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -331,7 +225,7 @@ pub fn resolve(options: Options) ResolveError!Config {
331 if (options.link_libc == false) return error.LibCppRequiresLibC;225 if (options.link_libc == false) return error.LibCppRequiresLibC;
332 break :b true;226 break :b true;
333 }227 }
334 if (link_libunwind) {228 if (options.link_libunwind == true) {
335 if (options.link_libc == false) return error.LibUnwindRequiresLibC;229 if (options.link_libc == false) return error.LibUnwindRequiresLibC;
336 break :b true;230 break :b true;
337 }231 }
...@@ -402,12 +296,17 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -402,12 +296,17 @@ pub fn resolve(options: Options) ResolveError!Config {
402 break :b .static;296 break :b .static;
403 };297 };
404298
405 // This is done here to avoid excessive duplicated logic due to the complex dependencies between these options.299 const link_libunwind = b: {
406 if (options.output_mode == .Exe and link_libc and target_util.libCNeedsLibUnwind(target, link_mode)) {300 if (options.output_mode == .Exe and link_libc and target_util.libCNeedsLibUnwind(target, link_mode)) {
407 if (options.link_libunwind == false) return error.LibCRequiresLibUnwind;301 if (options.link_libunwind == false) return error.LibCRequiresLibUnwind;
408302 break :b true;
409 link_libunwind = true;303 }
410 }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
412 const import_memory = options.import_memory orelse (options.output_mode == .Obj);311 const import_memory = options.import_memory orelse (options.output_mode == .Obj);
413 const export_memory = b: {312 const export_memory = b: {
...@@ -446,6 +345,119 @@ pub fn resolve(options: Options) ResolveError!Config {...@@ -446,6 +345,119 @@ pub fn resolve(options: Options) ResolveError!Config {
446 } else false;345 } else false;
447 };346 };
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
449 const root_strip = b: {461 const root_strip = b: {
450 if (options.root_strip) |x| break :b x;462 if (options.root_strip) |x| break :b x;
451 if (root_optimize_mode == .ReleaseSmall) break :b true;463 if (root_optimize_mode == .ReleaseSmall) break :b true;
src/IncrementalDebugServer.zig+1-1
...@@ -10,7 +10,7 @@...@@ -10,7 +10,7 @@
1010
11comptime {11comptime {
12 // This file should only be referenced when debug extensions are enabled.12 // 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);
14}14}
1515
16zcu: *Zcu,16zcu: *Zcu,
src/InternPool.zig+71-49
...@@ -526,10 +526,10 @@ pub const Nav = struct {...@@ -526,10 +526,10 @@ pub const Nav = struct {
526 /// The type of this `Nav` is resolved; the value is queued for resolution.526 /// The type of this `Nav` is resolved; the value is queued for resolution.
527 type_resolved: struct {527 type_resolved: struct {
528 type: InternPool.Index,528 type: InternPool.Index,
529 is_const: bool,
529 alignment: Alignment,530 alignment: Alignment,
530 @"linksection": OptionalNullTerminatedString,531 @"linksection": OptionalNullTerminatedString,
531 @"addrspace": std.builtin.AddressSpace,532 @"addrspace": std.builtin.AddressSpace,
532 is_const: bool,
533 is_threadlocal: bool,533 is_threadlocal: bool,
534 /// This field is whether this `Nav` is a literal `extern` definition.534 /// This field is whether this `Nav` is a literal `extern` definition.
535 /// It does *not* tell you whether this might alias an extern fn (see #21027).535 /// It does *not* tell you whether this might alias an extern fn (see #21027).
...@@ -538,6 +538,7 @@ pub const Nav = struct {...@@ -538,6 +538,7 @@ pub const Nav = struct {
538 /// The value of this `Nav` is resolved.538 /// The value of this `Nav` is resolved.
539 fully_resolved: struct {539 fully_resolved: struct {
540 val: InternPool.Index,540 val: InternPool.Index,
541 is_const: bool,
541 alignment: Alignment,542 alignment: Alignment,
542 @"linksection": OptionalNullTerminatedString,543 @"linksection": OptionalNullTerminatedString,
543 @"addrspace": std.builtin.AddressSpace,544 @"addrspace": std.builtin.AddressSpace,
...@@ -727,12 +728,12 @@ pub const Nav = struct {...@@ -727,12 +728,12 @@ pub const Nav = struct {
727 const Bits = packed struct(u16) {728 const Bits = packed struct(u16) {
728 status: enum(u2) { unresolved, type_resolved, fully_resolved, type_resolved_extern_decl },729 status: enum(u2) { unresolved, type_resolved, fully_resolved, type_resolved_extern_decl },
729 /// Populated only if `bits.status != .unresolved`.730 /// Populated only if `bits.status != .unresolved`.
731 is_const: bool,
732 /// Populated only if `bits.status != .unresolved`.
730 alignment: Alignment,733 alignment: Alignment,
731 /// Populated only if `bits.status != .unresolved`.734 /// Populated only if `bits.status != .unresolved`.
732 @"addrspace": std.builtin.AddressSpace,735 @"addrspace": std.builtin.AddressSpace,
733 /// Populated only if `bits.status == .type_resolved`.736 /// Populated only if `bits.status == .type_resolved`.
734 is_const: bool,
735 /// Populated only if `bits.status == .type_resolved`.
736 is_threadlocal: bool,737 is_threadlocal: bool,
737 is_usingnamespace: bool,738 is_usingnamespace: bool,
738 };739 };
...@@ -753,15 +754,16 @@ pub const Nav = struct {...@@ -753,15 +754,16 @@ pub const Nav = struct {
753 .unresolved => .unresolved,754 .unresolved => .unresolved,
754 .type_resolved, .type_resolved_extern_decl => .{ .type_resolved = .{755 .type_resolved, .type_resolved_extern_decl => .{ .type_resolved = .{
755 .type = repr.type_or_val,756 .type = repr.type_or_val,
757 .is_const = repr.bits.is_const,
756 .alignment = repr.bits.alignment,758 .alignment = repr.bits.alignment,
757 .@"linksection" = repr.@"linksection",759 .@"linksection" = repr.@"linksection",
758 .@"addrspace" = repr.bits.@"addrspace",760 .@"addrspace" = repr.bits.@"addrspace",
759 .is_const = repr.bits.is_const,
760 .is_threadlocal = repr.bits.is_threadlocal,761 .is_threadlocal = repr.bits.is_threadlocal,
761 .is_extern_decl = repr.bits.status == .type_resolved_extern_decl,762 .is_extern_decl = repr.bits.status == .type_resolved_extern_decl,
762 } },763 } },
763 .fully_resolved => .{ .fully_resolved = .{764 .fully_resolved => .{ .fully_resolved = .{
764 .val = repr.type_or_val,765 .val = repr.type_or_val,
766 .is_const = repr.bits.is_const,
765 .alignment = repr.bits.alignment,767 .alignment = repr.bits.alignment,
766 .@"linksection" = repr.@"linksection",768 .@"linksection" = repr.@"linksection",
767 .@"addrspace" = repr.bits.@"addrspace",769 .@"addrspace" = repr.bits.@"addrspace",
...@@ -792,26 +794,26 @@ pub const Nav = struct {...@@ -792,26 +794,26 @@ pub const Nav = struct {
792 .bits = switch (nav.status) {794 .bits = switch (nav.status) {
793 .unresolved => .{795 .unresolved => .{
794 .status = .unresolved,796 .status = .unresolved,
797 .is_const = false,
795 .alignment = .none,798 .alignment = .none,
796 .@"addrspace" = .generic,799 .@"addrspace" = .generic,
797 .is_usingnamespace = nav.is_usingnamespace,800 .is_usingnamespace = nav.is_usingnamespace,
798 .is_const = false,
799 .is_threadlocal = false,801 .is_threadlocal = false,
800 },802 },
801 .type_resolved => |r| .{803 .type_resolved => |r| .{
802 .status = if (r.is_extern_decl) .type_resolved_extern_decl else .type_resolved,804 .status = if (r.is_extern_decl) .type_resolved_extern_decl else .type_resolved,
805 .is_const = r.is_const,
803 .alignment = r.alignment,806 .alignment = r.alignment,
804 .@"addrspace" = r.@"addrspace",807 .@"addrspace" = r.@"addrspace",
805 .is_usingnamespace = nav.is_usingnamespace,808 .is_usingnamespace = nav.is_usingnamespace,
806 .is_const = r.is_const,
807 .is_threadlocal = r.is_threadlocal,809 .is_threadlocal = r.is_threadlocal,
808 },810 },
809 .fully_resolved => |r| .{811 .fully_resolved => |r| .{
810 .status = .fully_resolved,812 .status = .fully_resolved,
813 .is_const = r.is_const,
811 .alignment = r.alignment,814 .alignment = r.alignment,
812 .@"addrspace" = r.@"addrspace",815 .@"addrspace" = r.@"addrspace",
813 .is_usingnamespace = nav.is_usingnamespace,816 .is_usingnamespace = nav.is_usingnamespace,
814 .is_const = false,
815 .is_threadlocal = false,817 .is_threadlocal = false,
816 },818 },
817 },819 },
...@@ -2221,7 +2223,6 @@ pub const Key = union(enum) {...@@ -2221,7 +2223,6 @@ pub const Key = union(enum) {
2221 init: Index,2223 init: Index,
2222 owner_nav: Nav.Index,2224 owner_nav: Nav.Index,
2223 is_threadlocal: bool,2225 is_threadlocal: bool,
2224 is_weak_linkage: bool,
2225 };2226 };
22262227
2227 pub const Extern = struct {2228 pub const Extern = struct {
...@@ -2234,10 +2235,12 @@ pub const Key = union(enum) {...@@ -2234,10 +2235,12 @@ pub const Key = union(enum) {
2234 /// For example `extern "c" fn write(...) usize` would have 'c' as library name.2235 /// For example `extern "c" fn write(...) usize` would have 'c' as library name.
2235 /// Index into the string table bytes.2236 /// Index into the string table bytes.
2236 lib_name: OptionalNullTerminatedString,2237 lib_name: OptionalNullTerminatedString,
2237 is_const: bool,2238 linkage: std.builtin.GlobalLinkage,
2239 visibility: std.builtin.SymbolVisibility,
2238 is_threadlocal: bool,2240 is_threadlocal: bool,
2239 is_weak_linkage: bool,
2240 is_dll_import: bool,2241 is_dll_import: bool,
2242 relocation: std.builtin.ExternOptions.Relocation,
2243 is_const: bool,
2241 alignment: Alignment,2244 alignment: Alignment,
2242 @"addrspace": std.builtin.AddressSpace,2245 @"addrspace": std.builtin.AddressSpace,
2243 /// The ZIR instruction which created this extern; used only for source locations.2246 /// The ZIR instruction which created this extern; used only for source locations.
...@@ -2844,9 +2847,10 @@ pub const Key = union(enum) {...@@ -2844,9 +2847,10 @@ pub const Key = union(enum) {
28442847
2845 .@"extern" => |e| Hash.hash(seed, asBytes(&e.name) ++2848 .@"extern" => |e| Hash.hash(seed, asBytes(&e.name) ++
2846 asBytes(&e.ty) ++ asBytes(&e.lib_name) ++2849 asBytes(&e.ty) ++ asBytes(&e.lib_name) ++
2847 asBytes(&e.is_const) ++ asBytes(&e.is_threadlocal) ++2850 asBytes(&e.linkage) ++ asBytes(&e.visibility) ++
2848 asBytes(&e.is_weak_linkage) ++ asBytes(&e.alignment) ++2851 asBytes(&e.is_threadlocal) ++ asBytes(&e.is_dll_import) ++
2849 asBytes(&e.is_dll_import) ++ asBytes(&e.@"addrspace") ++2852 asBytes(&e.relocation) ++
2853 asBytes(&e.is_const) ++ asBytes(&e.alignment) ++ asBytes(&e.@"addrspace") ++
2850 asBytes(&e.zir_index)),2854 asBytes(&e.zir_index)),
2851 };2855 };
2852 }2856 }
...@@ -2928,21 +2932,22 @@ pub const Key = union(enum) {...@@ -2928,21 +2932,22 @@ pub const Key = union(enum) {
29282932
2929 .variable => |a_info| {2933 .variable => |a_info| {
2930 const b_info = b.variable;2934 const b_info = b.variable;
2931 return a_info.owner_nav == b_info.owner_nav and2935 return a_info.ty == b_info.ty and
2932 a_info.ty == b_info.ty and
2933 a_info.init == b_info.init and2936 a_info.init == b_info.init and
2934 a_info.is_threadlocal == b_info.is_threadlocal and2937 a_info.owner_nav == b_info.owner_nav and
2935 a_info.is_weak_linkage == b_info.is_weak_linkage;2938 a_info.is_threadlocal == b_info.is_threadlocal;
2936 },2939 },
2937 .@"extern" => |a_info| {2940 .@"extern" => |a_info| {
2938 const b_info = b.@"extern";2941 const b_info = b.@"extern";
2939 return a_info.name == b_info.name and2942 return a_info.name == b_info.name and
2940 a_info.ty == b_info.ty and2943 a_info.ty == b_info.ty and
2941 a_info.lib_name == b_info.lib_name and2944 a_info.lib_name == b_info.lib_name and
2942 a_info.is_const == b_info.is_const and2945 a_info.linkage == b_info.linkage and
2946 a_info.visibility == b_info.visibility and
2943 a_info.is_threadlocal == b_info.is_threadlocal and2947 a_info.is_threadlocal == b_info.is_threadlocal and
2944 a_info.is_weak_linkage == b_info.is_weak_linkage and
2945 a_info.is_dll_import == b_info.is_dll_import and2948 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
2946 a_info.alignment == b_info.alignment and2951 a_info.alignment == b_info.alignment and
2947 a_info.@"addrspace" == b_info.@"addrspace" and2952 a_info.@"addrspace" == b_info.@"addrspace" and
2948 a_info.zir_index == b_info.zir_index;2953 a_info.zir_index == b_info.zir_index;
...@@ -4889,6 +4894,7 @@ pub const Index = enum(u32) {...@@ -4889,6 +4894,7 @@ pub const Index = enum(u32) {
4889 float_c_longdouble_f128: struct { data: *Float128 },4894 float_c_longdouble_f128: struct { data: *Float128 },
4890 float_comptime_float: struct { data: *Float128 },4895 float_comptime_float: struct { data: *Float128 },
4891 variable: struct { data: *Tag.Variable },4896 variable: struct { data: *Tag.Variable },
4897 threadlocal_variable: struct { data: *Tag.Variable },
4892 @"extern": struct { data: *Tag.Extern },4898 @"extern": struct { data: *Tag.Extern },
4893 func_decl: struct {4899 func_decl: struct {
4894 const @"data.analysis.inferred_error_set" = opaque {};4900 const @"data.analysis.inferred_error_set" = opaque {};
...@@ -5548,6 +5554,9 @@ pub const Tag = enum(u8) {...@@ -5548,6 +5554,9 @@ pub const Tag = enum(u8) {
5548 /// A global variable.5554 /// A global variable.
5549 /// data is extra index to Variable.5555 /// data is extra index to Variable.
5550 variable,5556 variable,
5557 /// A global threadlocal variable.
5558 /// data is extra index to Variable.
5559 threadlocal_variable,
5551 /// An extern function or variable.5560 /// An extern function or variable.
5552 /// data is extra index to Extern.5561 /// data is extra index to Extern.
5553 /// Some parts of the key are stored in `owner_nav`.5562 /// Some parts of the key are stored in `owner_nav`.
...@@ -5863,6 +5872,7 @@ pub const Tag = enum(u8) {...@@ -5863,6 +5872,7 @@ pub const Tag = enum(u8) {
5863 .float_c_longdouble_f128 = .{ .summary = .@"@as(c_longdouble, {.payload%value})", .payload = f128 },5872 .float_c_longdouble_f128 = .{ .summary = .@"@as(c_longdouble, {.payload%value})", .payload = f128 },
5864 .float_comptime_float = .{ .summary = .@"{.payload%value}", .payload = f128 },5873 .float_comptime_float = .{ .summary = .@"{.payload%value}", .payload = f128 },
5865 .variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable },5874 .variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable },
5875 .threadlocal_variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable },
5866 .@"extern" = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Extern },5876 .@"extern" = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Extern },
5867 .func_decl = .{5877 .func_decl = .{
5868 .summary = .@"{.payload.owner_nav.fqn%summary#\"}",5878 .summary = .@"{.payload.owner_nav.fqn%summary#\"}",
...@@ -5913,24 +5923,24 @@ pub const Tag = enum(u8) {...@@ -5913,24 +5923,24 @@ pub const Tag = enum(u8) {
5913 /// May be `none`.5923 /// May be `none`.
5914 init: Index,5924 init: Index,
5915 owner_nav: Nav.Index,5925 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 };
5925 };5926 };
59265927
5927 pub const Extern = struct {5928 pub const Extern = struct {
5928 // name, alignment, addrspace come from `owner_nav`.5929 // name, is_const, alignment, addrspace come from `owner_nav`.
5929 ty: Index,5930 ty: Index,
5930 lib_name: OptionalNullTerminatedString,5931 lib_name: OptionalNullTerminatedString,
5931 flags: Variable.Flags,5932 flags: Flags,
5932 owner_nav: Nav.Index,5933 owner_nav: Nav.Index,
5933 zir_index: TrackedInst.Index,5934 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 };
5934 };5944 };
59355945
5936 /// Trailing:5946 /// Trailing:
...@@ -7248,14 +7258,17 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -7248,14 +7258,17 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
7248 .ty = .comptime_float_type,7258 .ty = .comptime_float_type,
7249 .storage = .{ .f128 = extraData(unwrapped_index.getExtra(ip), Float128, data).get() },7259 .storage = .{ .f128 = extraData(unwrapped_index.getExtra(ip), Float128, data).get() },
7250 } },7260 } },
7251 .variable => {7261 .variable, .threadlocal_variable => {
7252 const extra = extraData(unwrapped_index.getExtra(ip), Tag.Variable, data);7262 const extra = extraData(unwrapped_index.getExtra(ip), Tag.Variable, data);
7253 return .{ .variable = .{7263 return .{ .variable = .{
7254 .ty = extra.ty,7264 .ty = extra.ty,
7255 .init = extra.init,7265 .init = extra.init,
7256 .owner_nav = extra.owner_nav,7266 .owner_nav = extra.owner_nav,
7257 .is_threadlocal = extra.flags.is_threadlocal,7267 .is_threadlocal = switch (item.tag) {
7258 .is_weak_linkage = extra.flags.is_weak_linkage,7268 else => unreachable,
7269 .variable => false,
7270 .threadlocal_variable => true,
7271 },
7259 } };7272 } };
7260 },7273 },
7261 .@"extern" => {7274 .@"extern" => {
...@@ -7265,10 +7278,12 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -7265,10 +7278,12 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
7265 .name = nav.name,7278 .name = nav.name,
7266 .ty = extra.ty,7279 .ty = extra.ty,
7267 .lib_name = extra.lib_name,7280 .lib_name = extra.lib_name,
7268 .is_const = extra.flags.is_const,7281 .linkage = extra.flags.linkage,
7282 .visibility = extra.flags.visibility,
7269 .is_threadlocal = extra.flags.is_threadlocal,7283 .is_threadlocal = extra.flags.is_threadlocal,
7270 .is_weak_linkage = extra.flags.is_weak_linkage,
7271 .is_dll_import = extra.flags.is_dll_import,7284 .is_dll_import = extra.flags.is_dll_import,
7285 .relocation = extra.flags.relocation,
7286 .is_const = nav.status.fully_resolved.is_const,
7272 .alignment = nav.status.fully_resolved.alignment,7287 .alignment = nav.status.fully_resolved.alignment,
7273 .@"addrspace" = nav.status.fully_resolved.@"addrspace",7288 .@"addrspace" = nav.status.fully_resolved.@"addrspace",
7274 .zir_index = extra.zir_index,7289 .zir_index = extra.zir_index,
...@@ -7895,17 +7910,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All...@@ -7895,17 +7910,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
7895 const has_init = variable.init != .none;7910 const has_init = variable.init != .none;
7896 if (has_init) assert(variable.ty == ip.typeOf(variable.init));7911 if (has_init) assert(variable.ty == ip.typeOf(variable.init));
7897 items.appendAssumeCapacity(.{7912 items.appendAssumeCapacity(.{
7898 .tag = .variable,7913 .tag = switch (variable.is_threadlocal) {
7914 false => .variable,
7915 true => .threadlocal_variable,
7916 },
7899 .data = try addExtra(extra, Tag.Variable{7917 .data = try addExtra(extra, Tag.Variable{
7900 .ty = variable.ty,7918 .ty = variable.ty,
7901 .init = variable.init,7919 .init = variable.init,
7902 .owner_nav = variable.owner_nav,7920 .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 },
7909 }),7921 }),
7910 });7922 });
7911 },7923 },
...@@ -9128,6 +9140,7 @@ pub fn getExtern(...@@ -9128,6 +9140,7 @@ pub fn getExtern(
9128 .name = key.name,9140 .name = key.name,
9129 .fqn = key.name,9141 .fqn = key.name,
9130 .val = extern_index,9142 .val = extern_index,
9143 .is_const = key.is_const,
9131 .alignment = key.alignment,9144 .alignment = key.alignment,
9132 .@"linksection" = .none,9145 .@"linksection" = .none,
9133 .@"addrspace" = key.@"addrspace",9146 .@"addrspace" = key.@"addrspace",
...@@ -9136,10 +9149,11 @@ pub fn getExtern(...@@ -9136,10 +9149,11 @@ pub fn getExtern(
9136 .ty = key.ty,9149 .ty = key.ty,
9137 .lib_name = key.lib_name,9150 .lib_name = key.lib_name,
9138 .flags = .{9151 .flags = .{
9139 .is_const = key.is_const,9152 .linkage = key.linkage,
9153 .visibility = key.visibility,
9140 .is_threadlocal = key.is_threadlocal,9154 .is_threadlocal = key.is_threadlocal,
9141 .is_weak_linkage = key.is_weak_linkage,
9142 .is_dll_import = key.is_dll_import,9155 .is_dll_import = key.is_dll_import,
9156 .relocation = key.relocation,
9143 },9157 },
9144 .zir_index = key.zir_index,9158 .zir_index = key.zir_index,
9145 .owner_nav = owner_nav,9159 .owner_nav = owner_nav,
...@@ -9714,6 +9728,7 @@ fn finishFuncInstance(...@@ -9714,6 +9728,7 @@ fn finishFuncInstance(
9714 .name = nav_name,9728 .name = nav_name,
9715 .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, tid, nav_name),9729 .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, tid, nav_name),
9716 .val = func_index,9730 .val = func_index,
9731 .is_const = fn_owner_nav.status.fully_resolved.is_const,
9717 .alignment = fn_owner_nav.status.fully_resolved.alignment,9732 .alignment = fn_owner_nav.status.fully_resolved.alignment,
9718 .@"linksection" = fn_owner_nav.status.fully_resolved.@"linksection",9733 .@"linksection" = fn_owner_nav.status.fully_resolved.@"linksection",
9719 .@"addrspace" = fn_owner_nav.status.fully_resolved.@"addrspace",9734 .@"addrspace" = fn_owner_nav.status.fully_resolved.@"addrspace",
...@@ -10300,13 +10315,13 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 {...@@ -10300,13 +10315,13 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 {
10300 u32,10315 u32,
10301 i32,10316 i32,
10302 FuncAnalysis,10317 FuncAnalysis,
10318 Tag.Extern.Flags,
10303 Tag.TypePointer.Flags,10319 Tag.TypePointer.Flags,
10304 Tag.TypeFunction.Flags,10320 Tag.TypeFunction.Flags,
10305 Tag.TypePointer.PackedOffset,10321 Tag.TypePointer.PackedOffset,
10306 Tag.TypeUnion.Flags,10322 Tag.TypeUnion.Flags,
10307 Tag.TypeStruct.Flags,10323 Tag.TypeStruct.Flags,
10308 Tag.TypeStructPacked.Flags,10324 Tag.TypeStructPacked.Flags,
10309 Tag.Variable.Flags,
10310 => @bitCast(@field(item, field.name)),10325 => @bitCast(@field(item, field.name)),
1031110326
10312 else => @compileError("bad field type: " ++ @typeName(field.type)),10327 else => @compileError("bad field type: " ++ @typeName(field.type)),
...@@ -10361,13 +10376,13 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat...@@ -10361,13 +10376,13 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat
1036110376
10362 u32,10377 u32,
10363 i32,10378 i32,
10379 Tag.Extern.Flags,
10364 Tag.TypePointer.Flags,10380 Tag.TypePointer.Flags,
10365 Tag.TypeFunction.Flags,10381 Tag.TypeFunction.Flags,
10366 Tag.TypePointer.PackedOffset,10382 Tag.TypePointer.PackedOffset,
10367 Tag.TypeUnion.Flags,10383 Tag.TypeUnion.Flags,
10368 Tag.TypeStruct.Flags,10384 Tag.TypeStruct.Flags,
10369 Tag.TypeStructPacked.Flags,10385 Tag.TypeStructPacked.Flags,
10370 Tag.Variable.Flags,
10371 FuncAnalysis,10386 FuncAnalysis,
10372 => @bitCast(extra_item),10387 => @bitCast(extra_item),
1037310388
...@@ -11162,7 +11177,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -11162,7 +11177,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
11162 .float_c_longdouble_f80 => @sizeOf(Float80),11177 .float_c_longdouble_f80 => @sizeOf(Float80),
11163 .float_c_longdouble_f128 => @sizeOf(Float128),11178 .float_c_longdouble_f128 => @sizeOf(Float128),
11164 .float_comptime_float => @sizeOf(Float128),11179 .float_comptime_float => @sizeOf(Float128),
11165 .variable => @sizeOf(Tag.Variable),11180 .variable, .threadlocal_variable => @sizeOf(Tag.Variable),
11166 .@"extern" => @sizeOf(Tag.Extern),11181 .@"extern" => @sizeOf(Tag.Extern),
11167 .func_decl => @sizeOf(Tag.FuncDecl),11182 .func_decl => @sizeOf(Tag.FuncDecl),
11168 .func_instance => b: {11183 .func_instance => b: {
...@@ -11282,6 +11297,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {...@@ -11282,6 +11297,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
11282 .float_c_longdouble_f128,11297 .float_c_longdouble_f128,
11283 .float_comptime_float,11298 .float_comptime_float,
11284 .variable,11299 .variable,
11300 .threadlocal_variable,
11285 .@"extern",11301 .@"extern",
11286 .func_decl,11302 .func_decl,
11287 .func_instance,11303 .func_instance,
...@@ -11414,6 +11430,7 @@ pub fn createNav(...@@ -11414,6 +11430,7 @@ pub fn createNav(
11414 name: NullTerminatedString,11430 name: NullTerminatedString,
11415 fqn: NullTerminatedString,11431 fqn: NullTerminatedString,
11416 val: InternPool.Index,11432 val: InternPool.Index,
11433 is_const: bool,
11417 alignment: Alignment,11434 alignment: Alignment,
11418 @"linksection": OptionalNullTerminatedString,11435 @"linksection": OptionalNullTerminatedString,
11419 @"addrspace": std.builtin.AddressSpace,11436 @"addrspace": std.builtin.AddressSpace,
...@@ -11430,6 +11447,7 @@ pub fn createNav(...@@ -11430,6 +11447,7 @@ pub fn createNav(
11430 .analysis = null,11447 .analysis = null,
11431 .status = .{ .fully_resolved = .{11448 .status = .{ .fully_resolved = .{
11432 .val = opts.val,11449 .val = opts.val,
11450 .is_const = opts.is_const,
11433 .alignment = opts.alignment,11451 .alignment = opts.alignment,
11434 .@"linksection" = opts.@"linksection",11452 .@"linksection" = opts.@"linksection",
11435 .@"addrspace" = opts.@"addrspace",11453 .@"addrspace" = opts.@"addrspace",
...@@ -11482,10 +11500,10 @@ pub fn resolveNavType(...@@ -11482,10 +11500,10 @@ pub fn resolveNavType(
11482 nav: Nav.Index,11500 nav: Nav.Index,
11483 resolved: struct {11501 resolved: struct {
11484 type: InternPool.Index,11502 type: InternPool.Index,
11503 is_const: bool,
11485 alignment: Alignment,11504 alignment: Alignment,
11486 @"linksection": OptionalNullTerminatedString,11505 @"linksection": OptionalNullTerminatedString,
11487 @"addrspace": std.builtin.AddressSpace,11506 @"addrspace": std.builtin.AddressSpace,
11488 is_const: bool,
11489 is_threadlocal: bool,11507 is_threadlocal: bool,
11490 is_extern_decl: bool,11508 is_extern_decl: bool,
11491 },11509 },
...@@ -11512,9 +11530,9 @@ pub fn resolveNavType(...@@ -11512,9 +11530,9 @@ pub fn resolveNavType(
1151211530
11513 var bits = nav_bits[unwrapped.index];11531 var bits = nav_bits[unwrapped.index];
11514 bits.status = if (resolved.is_extern_decl) .type_resolved_extern_decl else .type_resolved;11532 bits.status = if (resolved.is_extern_decl) .type_resolved_extern_decl else .type_resolved;
11533 bits.is_const = resolved.is_const;
11515 bits.alignment = resolved.alignment;11534 bits.alignment = resolved.alignment;
11516 bits.@"addrspace" = resolved.@"addrspace";11535 bits.@"addrspace" = resolved.@"addrspace";
11517 bits.is_const = resolved.is_const;
11518 bits.is_threadlocal = resolved.is_threadlocal;11536 bits.is_threadlocal = resolved.is_threadlocal;
11519 @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);11537 @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);
11520}11538}
...@@ -11526,6 +11544,7 @@ pub fn resolveNavValue(...@@ -11526,6 +11544,7 @@ pub fn resolveNavValue(
11526 nav: Nav.Index,11544 nav: Nav.Index,
11527 resolved: struct {11545 resolved: struct {
11528 val: InternPool.Index,11546 val: InternPool.Index,
11547 is_const: bool,
11529 alignment: Alignment,11548 alignment: Alignment,
11530 @"linksection": OptionalNullTerminatedString,11549 @"linksection": OptionalNullTerminatedString,
11531 @"addrspace": std.builtin.AddressSpace,11550 @"addrspace": std.builtin.AddressSpace,
...@@ -11553,6 +11572,7 @@ pub fn resolveNavValue(...@@ -11553,6 +11572,7 @@ pub fn resolveNavValue(
1155311572
11554 var bits = nav_bits[unwrapped.index];11573 var bits = nav_bits[unwrapped.index];
11555 bits.status = .fully_resolved;11574 bits.status = .fully_resolved;
11575 bits.is_const = resolved.is_const;
11556 bits.alignment = resolved.alignment;11576 bits.alignment = resolved.alignment;
11557 bits.@"addrspace" = resolved.@"addrspace";11577 bits.@"addrspace" = resolved.@"addrspace";
11558 @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);11578 @atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);
...@@ -12007,6 +12027,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {...@@ -12007,6 +12027,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
12007 .error_union_error,12027 .error_union_error,
12008 .enum_tag,12028 .enum_tag,
12009 .variable,12029 .variable,
12030 .threadlocal_variable,
12010 .@"extern",12031 .@"extern",
12011 .func_decl,12032 .func_decl,
12012 .func_instance,12033 .func_instance,
...@@ -12391,6 +12412,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {...@@ -12391,6 +12412,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
12391 .float_c_longdouble_f128,12412 .float_c_longdouble_f128,
12392 .float_comptime_float,12413 .float_comptime_float,
12393 .variable,12414 .variable,
12415 .threadlocal_variable,
12394 .@"extern",12416 .@"extern",
12395 .func_decl,12417 .func_decl,
12396 .func_instance,12418 .func_instance,
src/Sema.zig+45-14
...@@ -26089,10 +26089,12 @@ fn resolveExternOptions(...@@ -26089,10 +26089,12 @@ fn resolveExternOptions(
26089 zir_ref: Zir.Inst.Ref,26089 zir_ref: Zir.Inst.Ref,
26090) CompileError!struct {26090) CompileError!struct {
26091 name: InternPool.NullTerminatedString,26091 name: InternPool.NullTerminatedString,
26092 library_name: InternPool.OptionalNullTerminatedString = .none,26092 library_name: InternPool.OptionalNullTerminatedString,
26093 linkage: std.builtin.GlobalLinkage = .strong,26093 linkage: std.builtin.GlobalLinkage,
26094 is_thread_local: bool = false,26094 visibility: std.builtin.SymbolVisibility,
26095 is_dll_import: bool = false,26095 is_thread_local: bool,
26096 is_dll_import: bool,
26097 relocation: std.builtin.ExternOptions.Relocation,
26096} {26098} {
26097 const pt = sema.pt;26099 const pt = sema.pt;
26098 const zcu = pt.zcu;26100 const zcu = pt.zcu;
...@@ -26105,8 +26107,10 @@ fn resolveExternOptions(...@@ -26105,8 +26107,10 @@ fn resolveExternOptions(
26105 const name_src = block.src(.{ .init_field_name = src.offset.node_offset_builtin_call_arg.builtin_call_node });26107 const name_src = block.src(.{ .init_field_name = src.offset.node_offset_builtin_call_arg.builtin_call_node });
26106 const library_src = block.src(.{ .init_field_library = src.offset.node_offset_builtin_call_arg.builtin_call_node });26108 const library_src = block.src(.{ .init_field_library = src.offset.node_offset_builtin_call_arg.builtin_call_node });
26107 const linkage_src = block.src(.{ .init_field_linkage = src.offset.node_offset_builtin_call_arg.builtin_call_node });26109 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 });
26108 const thread_local_src = block.src(.{ .init_field_thread_local = src.offset.node_offset_builtin_call_arg.builtin_call_node });26111 const thread_local_src = block.src(.{ .init_field_thread_local = src.offset.node_offset_builtin_call_arg.builtin_call_node });
26109 const dll_import_src = block.src(.{ .init_field_dll_import = src.offset.node_offset_builtin_call_arg.builtin_call_node });26112 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
26111 const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), name_src);26115 const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), name_src);
26112 const name = try sema.toConstString(block, name_src, name_ref, .{ .simple = .extern_options });26116 const name = try sema.toConstString(block, name_src, name_ref, .{ .simple = .extern_options });
...@@ -26118,6 +26122,10 @@ fn resolveExternOptions(...@@ -26118,6 +26122,10 @@ fn resolveExternOptions(
26118 const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_ref, .{ .simple = .extern_options });26122 const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_ref, .{ .simple = .extern_options });
26119 const linkage = try sema.interpretBuiltinType(block, linkage_src, linkage_val, std.builtin.GlobalLinkage);26123 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
26121 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);26129 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);
26122 const is_thread_local_val = try sema.resolveConstDefinedValue(block, thread_local_src, is_thread_local, .{ .simple = .extern_options });26130 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(...@@ -26133,6 +26141,10 @@ fn resolveExternOptions(
26133 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);26141 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);
26134 const is_dll_import_val = try sema.resolveConstDefinedValue(block, dll_import_src, is_dll_import_ref, .{ .simple = .extern_options });26142 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
26136 if (name.len == 0) {26148 if (name.len == 0) {
26137 return sema.fail(block, name_src, "extern symbol name cannot be empty", .{});26149 return sema.fail(block, name_src, "extern symbol name cannot be empty", .{});
26138 }26150 }
...@@ -26145,8 +26157,10 @@ fn resolveExternOptions(...@@ -26145,8 +26157,10 @@ fn resolveExternOptions(
26145 .name = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls),26157 .name = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls),
26146 .library_name = try ip.getOrPutStringOpt(gpa, pt.tid, library_name, .no_embedded_nulls),26158 .library_name = try ip.getOrPutStringOpt(gpa, pt.tid, library_name, .no_embedded_nulls),
26147 .linkage = linkage,26159 .linkage = linkage,
26160 .visibility = visibility,
26148 .is_thread_local = is_thread_local_val.toBool(),26161 .is_thread_local = is_thread_local_val.toBool(),
26149 .is_dll_import = is_dll_import_val.toBool(),26162 .is_dll_import = is_dll_import_val.toBool(),
26163 .relocation = relocation,
26150 };26164 };
26151}26165}
2615226166
...@@ -26178,6 +26192,17 @@ fn zirBuiltinExtern(...@@ -26178,6 +26192,17 @@ fn zirBuiltinExtern(
26178 }26192 }
2617926193
26180 const options = try sema.resolveExternOptions(block, options_src, extra.rhs);26194 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
26182 // TODO: error for threadlocal functions, non-const functions, etc26207 // TODO: error for threadlocal functions, non-const functions, etc
2618326208
...@@ -26190,10 +26215,12 @@ fn zirBuiltinExtern(...@@ -26190,10 +26215,12 @@ fn zirBuiltinExtern(
26190 .name = options.name,26215 .name = options.name,
26191 .ty = ptr_info.child,26216 .ty = ptr_info.child,
26192 .lib_name = options.library_name,26217 .lib_name = options.library_name,
26193 .is_const = ptr_info.flags.is_const,26218 .linkage = options.linkage,
26219 .visibility = options.visibility,
26194 .is_threadlocal = options.is_thread_local,26220 .is_threadlocal = options.is_thread_local,
26195 .is_weak_linkage = options.linkage == .weak,
26196 .is_dll_import = options.is_dll_import,26221 .is_dll_import = options.is_dll_import,
26222 .relocation = options.relocation,
26223 .is_const = ptr_info.flags.is_const,
26197 .alignment = ptr_info.flags.alignment,26224 .alignment = ptr_info.flags.alignment,
26198 .@"addrspace" = ptr_info.flags.address_space,26225 .@"addrspace" = ptr_info.flags.address_space,
26199 // This instruction is just for source locations.26226 // This instruction is just for source locations.
...@@ -31685,12 +31712,15 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde...@@ -31685,12 +31712,15 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
3168531712
31686 const nav_status = ip.getNav(nav_index).status;31713 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) {
31689 .unresolved => unreachable,31716 .unresolved => unreachable,
31690 // dllimports go straight to `fully_resolved`; the only option is threadlocal31717 // dllimports go straight to `fully_resolved`; the only option is threadlocal
31691 .type_resolved => |r| r.is_threadlocal,31718 .type_resolved => |r| r.is_threadlocal,
31692 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {31719 .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 },
31694 .variable => |v| v.is_threadlocal,31724 .variable => |v| v.is_threadlocal,
31695 else => false,31725 else => false,
31696 },31726 },
...@@ -31699,7 +31729,7 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde...@@ -31699,7 +31729,7 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
31699 const ty, const alignment, const @"addrspace", const is_const = switch (nav_status) {31729 const ty, const alignment, const @"addrspace", const is_const = switch (nav_status) {
31700 .unresolved => unreachable,31730 .unresolved => unreachable,
31701 .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },31731 .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 },
31703 };31733 };
31704 const ptr_ty = try pt.ptrTypeSema(.{31734 const ptr_ty = try pt.ptrTypeSema(.{
31705 .child = ty,31735 .child = ty,
...@@ -31710,10 +31740,10 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde...@@ -31710,10 +31740,10 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
31710 },31740 },
31711 });31741 });
3171231742
31713 if (is_tlv_or_dllimport) {31743 if (is_runtime) {
31714 // This pointer is runtime-known; we need to emit an AIR instruction to create it.31744 // This pointer is runtime-known; we need to emit an AIR instruction to create it.
31715 return block.addInst(.{31745 return block.addInst(.{
31716 .tag = .tlv_dllimport_ptr,31746 .tag = .runtime_nav_ptr,
31717 .data = .{ .ty_nav = .{31747 .data = .{ .ty_nav = .{
31718 .ty = ptr_ty.toIntern(),31748 .ty = ptr_ty.toIntern(),
31719 .nav = nav_index,31749 .nav = nav_index,
...@@ -32508,11 +32538,11 @@ fn analyzeSlice(...@@ -32508,11 +32538,11 @@ fn analyzeSlice(
32508 const actual_len = if (array_ty.zigTypeTag(zcu) == .array)32538 const actual_len = if (array_ty.zigTypeTag(zcu) == .array)
32509 try pt.intRef(.usize, array_ty.arrayLenIncludingSentinel(zcu))32539 try pt.intRef(.usize, array_ty.arrayLenIncludingSentinel(zcu))
32510 else if (slice_ty.isSlice(zcu)) l: {32540 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);
32512 break :l if (slice_ty.sentinel(zcu) == null)32542 break :l if (slice_ty.sentinel(zcu) == null)
32513 slice_len_inst32543 slice_len
32514 else32544 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);
32516 } else break :bounds_check;32546 } else break :bounds_check;
3251732547
32518 const actual_end = if (slice_sentinel != null)32548 const actual_end = if (slice_sentinel != null)
...@@ -36432,6 +36462,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -36432,6 +36462,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
36432 .float_c_longdouble_f128,36462 .float_c_longdouble_f128,
36433 .float_comptime_float,36463 .float_comptime_float,
36434 .variable,36464 .variable,
36465 .threadlocal_variable,
36435 .@"extern",36466 .@"extern",
36436 .func_decl,36467 .func_decl,
36437 .func_instance,36468 .func_instance,
src/Zcu.zig+3-9
...@@ -2047,6 +2047,7 @@ pub const SrcLoc = struct {...@@ -2047,6 +2047,7 @@ pub const SrcLoc = struct {
2047 .init_field_library,2047 .init_field_library,
2048 .init_field_thread_local,2048 .init_field_thread_local,
2049 .init_field_dll_import,2049 .init_field_dll_import,
2050 .init_field_relocation,
2050 => |builtin_call_node| {2051 => |builtin_call_node| {
2051 const wanted = switch (src_loc.lazy) {2052 const wanted = switch (src_loc.lazy) {
2052 .init_field_name => "name",2053 .init_field_name => "name",
...@@ -2059,6 +2060,7 @@ pub const SrcLoc = struct {...@@ -2059,6 +2060,7 @@ pub const SrcLoc = struct {
2059 .init_field_library => "library",2060 .init_field_library => "library",
2060 .init_field_thread_local => "thread_local",2061 .init_field_thread_local => "thread_local",
2061 .init_field_dll_import => "dll_import",2062 .init_field_dll_import => "dll_import",
2063 .init_field_relocation => "relocation",
2062 else => unreachable,2064 else => unreachable,
2063 };2065 };
2064 const tree = try src_loc.file_scope.getTree(zcu);2066 const tree = try src_loc.file_scope.getTree(zcu);
...@@ -2506,6 +2508,7 @@ pub const LazySrcLoc = struct {...@@ -2506,6 +2508,7 @@ pub const LazySrcLoc = struct {
2506 init_field_library: Ast.Node.Offset,2508 init_field_library: Ast.Node.Offset,
2507 init_field_thread_local: Ast.Node.Offset,2509 init_field_thread_local: Ast.Node.Offset,
2508 init_field_dll_import: Ast.Node.Offset,2510 init_field_dll_import: Ast.Node.Offset,
2511 init_field_relocation: Ast.Node.Offset,
2509 /// The source location points to the value of an item in a specific2512 /// The source location points to the value of an item in a specific
2510 /// case of a `switch`.2513 /// case of a `switch`.
2511 switch_case_item: SwitchItem,2514 switch_case_item: SwitchItem,
...@@ -4562,15 +4565,6 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu...@@ -4562,15 +4565,6 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu
4562 return .ok;4565 return .ok;
4563}4566}
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
4574pub const CodegenFailError = error{4568pub const CodegenFailError = error{
4575 /// Indicates the error message has been already stored at `Zcu.failed_codegen`.4569 /// Indicates the error message has been already stored at `Zcu.failed_codegen`.
4576 CodegenFail,4570 CodegenFail,
src/Zcu/PerThread.zig+29-21
...@@ -1153,18 +1153,23 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1153,18 +1153,23 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1153 // First, we must resolve the declaration's type. To do this, we analyze the type body if available,1153 // First, we must resolve the declaration's type. To do this, we analyze the type body if available,
1154 // or otherwise, we analyze the value body, populating `early_val` in the process.1154 // 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) {
1157 .@"comptime" => unreachable, // this is not a Nav1157 .@"comptime" => unreachable, // this is not a Nav
1158 .unnamed_test, .@"test", .decltest => assert(nav_ty.zigTypeTag(zcu) == .@"fn"),1158 .unnamed_test, .@"test", .decltest => {
1159 .@"usingnamespace" => {},1159 assert(nav_ty.zigTypeTag(zcu) == .@"fn");
1160 .@"const" => {},1160 break :is_const true;
1161 .@"var" => try sema.validateVarType(1161 },
1162 &block,1162 .@"usingnamespace", .@"const" => true,
1163 if (zir_decl.type_body != null) ty_src else init_src,1163 .@"var" => {
1164 nav_ty,1164 try sema.validateVarType(
1165 zir_decl.linkage == .@"extern",1165 &block,
1166 ),1166 if (zir_decl.type_body != null) ty_src else init_src,
1167 }1167 nav_ty,
1168 zir_decl.linkage == .@"extern",
1169 );
1170 break :is_const false;
1171 },
1172 };
11681173
1169 // Now that we know the type, we can evaluate the alignment, linksection, and addrspace, to determine1174 // Now that we know the type, we can evaluate the alignment, linksection, and addrspace, to determine
1170 // the full pointer type of this declaration.1175 // the full pointer type of this declaration.
...@@ -1195,7 +1200,6 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1195,7 +1200,6 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1195 .init = final_val.?.toIntern(),1200 .init = final_val.?.toIntern(),
1196 .owner_nav = nav_id,1201 .owner_nav = nav_id,
1197 .is_threadlocal = zir_decl.is_threadlocal,1202 .is_threadlocal = zir_decl.is_threadlocal,
1198 .is_weak_linkage = false,
1199 } })),1203 } })),
1200 else => final_val.?,1204 else => final_val.?,
1201 },1205 },
...@@ -1212,10 +1216,12 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1212,10 +1216,12 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1212 .name = old_nav.name,1216 .name = old_nav.name,
1213 .ty = nav_ty.toIntern(),1217 .ty = nav_ty.toIntern(),
1214 .lib_name = try ip.getOrPutStringOpt(gpa, pt.tid, lib_name, .no_embedded_nulls),1218 .lib_name = try ip.getOrPutStringOpt(gpa, pt.tid, lib_name, .no_embedded_nulls),
1215 .is_const = zir_decl.kind == .@"const",
1216 .is_threadlocal = zir_decl.is_threadlocal,1219 .is_threadlocal = zir_decl.is_threadlocal,
1217 .is_weak_linkage = false,1220 .linkage = .strong,
1221 .visibility = .default,
1218 .is_dll_import = false,1222 .is_dll_import = false,
1223 .relocation = .any,
1224 .is_const = is_const,
1219 .alignment = modifiers.alignment,1225 .alignment = modifiers.alignment,
1220 .@"addrspace" = modifiers.@"addrspace",1226 .@"addrspace" = modifiers.@"addrspace",
1221 .zir_index = old_nav.analysis.?.zir_index, // `declaration` instruction1227 .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...@@ -1243,6 +1249,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1243 }1249 }
1244 ip.resolveNavValue(nav_id, .{1250 ip.resolveNavValue(nav_id, .{
1245 .val = nav_val.toIntern(),1251 .val = nav_val.toIntern(),
1252 .is_const = is_const,
1246 .alignment = .none,1253 .alignment = .none,
1247 .@"linksection" = .none,1254 .@"linksection" = .none,
1248 .@"addrspace" = .generic,1255 .@"addrspace" = .generic,
...@@ -1286,6 +1293,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1286,6 +1293,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
12861293
1287 ip.resolveNavValue(nav_id, .{1294 ip.resolveNavValue(nav_id, .{
1288 .val = nav_val.toIntern(),1295 .val = nav_val.toIntern(),
1296 .is_const = is_const,
1289 .alignment = modifiers.alignment,1297 .alignment = modifiers.alignment,
1290 .@"linksection" = modifiers.@"linksection",1298 .@"linksection" = modifiers.@"linksection",
1291 .@"addrspace" = modifiers.@"addrspace",1299 .@"addrspace" = modifiers.@"addrspace",
...@@ -1515,8 +1523,6 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr...@@ -1515,8 +1523,6 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
1515 // the pointer modifiers, i.e. alignment, linksection, addrspace.1523 // the pointer modifiers, i.e. alignment, linksection, addrspace.
1516 const modifiers = try sema.resolveNavPtrModifiers(&block, zir_decl, inst_resolved.inst, resolved_ty);1524 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.
1520 const is_const = switch (zir_decl.kind) {1526 const is_const = switch (zir_decl.kind) {
1521 .@"comptime" => unreachable,1527 .@"comptime" => unreachable,
1522 .unnamed_test, .@"test", .decltest, .@"usingnamespace", .@"const" => true,1528 .unnamed_test, .@"test", .decltest, .@"usingnamespace", .@"const" => true,
...@@ -1542,7 +1548,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr...@@ -1542,7 +1548,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
1542 r.alignment != modifiers.alignment or1548 r.alignment != modifiers.alignment or
1543 r.@"linksection" != modifiers.@"linksection" or1549 r.@"linksection" != modifiers.@"linksection" or
1544 r.@"addrspace" != modifiers.@"addrspace" or1550 r.@"addrspace" != modifiers.@"addrspace" or
1545 zcu.navValIsConst(r.val) != is_const or1551 r.is_const != is_const or
1546 (old_nav.getExtern(ip) != null) != is_extern_decl,1552 (old_nav.getExtern(ip) != null) != is_extern_decl,
1547 };1553 };
15481554
...@@ -1550,10 +1556,10 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr...@@ -1550,10 +1556,10 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
15501556
1551 ip.resolveNavType(nav_id, .{1557 ip.resolveNavType(nav_id, .{
1552 .type = resolved_ty.toIntern(),1558 .type = resolved_ty.toIntern(),
1559 .is_const = is_const,
1553 .alignment = modifiers.alignment,1560 .alignment = modifiers.alignment,
1554 .@"linksection" = modifiers.@"linksection",1561 .@"linksection" = modifiers.@"linksection",
1555 .@"addrspace" = modifiers.@"addrspace",1562 .@"addrspace" = modifiers.@"addrspace",
1556 .is_const = is_const,
1557 .is_threadlocal = zir_decl.is_threadlocal,1563 .is_threadlocal = zir_decl.is_threadlocal,
1558 .is_extern_decl = is_extern_decl,1564 .is_extern_decl = is_extern_decl,
1559 });1565 });
...@@ -1750,7 +1756,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: *A...@@ -1750,7 +1756,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: *A
17501756
1751 if (build_options.enable_debug_extensions and comp.verbose_air) {1757 if (build_options.enable_debug_extensions and comp.verbose_air) {
1752 std.debug.print("# Begin Function AIR: {}:\n", .{nav.fqn.fmt(ip)});1758 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);
1754 std.debug.print("# End Function AIR: {}\n\n", .{nav.fqn.fmt(ip)});1760 std.debug.print("# End Function AIR: {}\n\n", .{nav.fqn.fmt(ip)});
1755 }1761 }
17561762
...@@ -3577,8 +3583,10 @@ pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!V...@@ -3577,8 +3583,10 @@ pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!V
3577 .lib_name = e.lib_name,3583 .lib_name = e.lib_name,
3578 .is_const = e.is_const,3584 .is_const = e.is_const,
3579 .is_threadlocal = e.is_threadlocal,3585 .is_threadlocal = e.is_threadlocal,
3580 .is_weak_linkage = e.is_weak_linkage,3586 .linkage = e.linkage,
3587 .visibility = e.visibility,
3581 .is_dll_import = e.is_dll_import,3588 .is_dll_import = e.is_dll_import,
3589 .relocation = e.relocation,
3582 .alignment = e.alignment,3590 .alignment = e.alignment,
3583 .@"addrspace" = e.@"addrspace",3591 .@"addrspace" = e.@"addrspace",
3584 .zir_index = e.zir_index,3592 .zir_index = e.zir_index,
...@@ -3954,7 +3962,7 @@ pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Err...@@ -3954,7 +3962,7 @@ pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Err
3954 const ty, const alignment, const @"addrspace", const is_const = switch (ip.getNav(nav_id).status) {3962 const ty, const alignment, const @"addrspace", const is_const = switch (ip.getNav(nav_id).status) {
3955 .unresolved => unreachable,3963 .unresolved => unreachable,
3956 .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },3964 .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 },
3958 };3966 };
3959 return pt.ptrType(.{3967 return pt.ptrType(.{
3960 .child = ty,3968 .child = ty,
src/arch/aarch64/CodeGen.zig+1-1
...@@ -880,7 +880,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -880,7 +880,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
880 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),880 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
881 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),881 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
882 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),882 .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
885 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),885 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
886 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),886 .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 {...@@ -869,7 +869,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
869 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),869 .is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
870 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),870 .error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
871 .vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),871 .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
874 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),874 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
875 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),875 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
src/arch/riscv64/CodeGen.zig+4-9
...@@ -1041,12 +1041,7 @@ fn formatAir(...@@ -1041,12 +1041,7 @@ fn formatAir(
1041 _: std.fmt.FormatOptions,1041 _: std.fmt.FormatOptions,
1042 writer: anytype,1042 writer: anytype,
1043) @TypeOf(writer).Error!void {1043) @TypeOf(writer).Error!void {
1044 @import("../../print_air.zig").dumpInst(1044 data.func.air.dumpInst(data.inst, data.func.pt, data.func.liveness);
1045 data.inst,
1046 data.func.pt,
1047 data.func.air,
1048 data.func.liveness,
1049 );
1050}1045}
1051fn fmtAir(func: *Func, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {1046fn fmtAir(func: *Func, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {
1052 return .{ .data = .{ .func = func, .inst = inst } };1047 return .{ .data = .{ .func = func, .inst = inst } };
...@@ -1656,7 +1651,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {...@@ -1656,7 +1651,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
1656 .wrap_errunion_payload => try func.airWrapErrUnionPayload(inst),1651 .wrap_errunion_payload => try func.airWrapErrUnionPayload(inst),
1657 .wrap_errunion_err => try func.airWrapErrUnionErr(inst),1652 .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
1661 .add_optimized,1656 .add_optimized,
1662 .sub_optimized,1657 .sub_optimized,
...@@ -3626,7 +3621,7 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void {...@@ -3626,7 +3621,7 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void {
3626 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });3621 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
3627}3622}
36283623
3629fn airTlvDllimportPtr(func: *Func, inst: Air.Inst.Index) !void {3624fn airRuntimeNavPtr(func: *Func, inst: Air.Inst.Index) !void {
3630 const zcu = func.pt.zcu;3625 const zcu = func.pt.zcu;
3631 const ip = &zcu.intern_pool;3626 const ip = &zcu.intern_pool;
3632 const ty_nav = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;3627 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 {...@@ -3641,7 +3636,7 @@ fn airTlvDllimportPtr(func: *Func, inst: Air.Inst.Index) !void {
3641 break :sym sym;3636 break :sym sym;
3642 }3637 }
3643 break :sym try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav);3638 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
3646 const dest_mcv = try func.allocRegOrMem(ptr_ty, inst, true);3641 const dest_mcv = try func.allocRegOrMem(ptr_ty, inst, true);
3647 if (dest_mcv.isRegister()) {3642 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 {...@@ -723,7 +723,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
723 .is_named_enum_value => @panic("TODO implement is_named_enum_value"),723 .is_named_enum_value => @panic("TODO implement is_named_enum_value"),
724 .error_set_has_value => @panic("TODO implement error_set_has_value"),724 .error_set_has_value => @panic("TODO implement error_set_has_value"),
725 .vector_store_elem => @panic("TODO implement vector_store_elem"),725 .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
728 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),728 .c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
729 .c_va_copy => return self.fail("TODO implement c_va_copy", .{}),729 .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 {...@@ -2057,7 +2057,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
2057 .error_set_has_value => cg.airErrorSetHasValue(inst),2057 .error_set_has_value => cg.airErrorSetHasValue(inst),
2058 .frame_addr => cg.airFrameAddress(inst),2058 .frame_addr => cg.airFrameAddress(inst),
20592059
2060 .tlv_dllimport_ptr => cg.airTlvDllimportPtr(inst),2060 .runtime_nav_ptr => cg.airRuntimeNavPtr(inst),
20612061
2062 .assembly,2062 .assembly,
2063 .is_err_ptr,2063 .is_err_ptr,
...@@ -7616,7 +7616,7 @@ fn airFrameAddress(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {...@@ -7616,7 +7616,7 @@ fn airFrameAddress(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7616 return cg.finishAir(inst, .stack, &.{});7616 return cg.finishAir(inst, .stack, &.{});
7617}7617}
76187618
7619fn airTlvDllimportPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {7619fn airRuntimeNavPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
7620 const ty_nav = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;7620 const ty_nav = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
7621 const mod = cg.pt.zcu.navFileScope(cg.owner_nav).mod.?;7621 const mod = cg.pt.zcu.navFileScope(cg.owner_nav).mod.?;
7622 if (mod.single_threaded) {7622 if (mod.single_threaded) {
src/arch/x86_64/CodeGen.zig+187-56
...@@ -274,6 +274,12 @@ pub const MCValue = union(enum) {...@@ -274,6 +274,12 @@ pub const MCValue = union(enum) {
274 load_symbol: bits.SymbolOffset,274 load_symbol: bits.SymbolOffset,
275 /// The address of the memory location not-yet-allocated by the linker.275 /// The address of the memory location not-yet-allocated by the linker.
276 lea_symbol: bits.SymbolOffset,276 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,
277 /// The value is in memory at a constant offset from the address in a register.283 /// The value is in memory at a constant offset from the address in a register.
278 indirect: bits.RegisterOffset,284 indirect: bits.RegisterOffset,
279 /// The value is in memory.285 /// The value is in memory.
...@@ -314,6 +320,7 @@ pub const MCValue = union(enum) {...@@ -314,6 +320,7 @@ pub const MCValue = union(enum) {
314 .eflags,320 .eflags,
315 .register_overflow,321 .register_overflow,
316 .lea_symbol,322 .lea_symbol,
323 .lea_pcrel,
317 .lea_direct,324 .lea_direct,
318 .lea_got,325 .lea_got,
319 .lea_frame,326 .lea_frame,
...@@ -327,6 +334,7 @@ pub const MCValue = union(enum) {...@@ -327,6 +334,7 @@ pub const MCValue = union(enum) {
327 .register_quadruple,334 .register_quadruple,
328 .memory,335 .memory,
329 .load_symbol,336 .load_symbol,
337 .load_pcrel,
330 .load_got,338 .load_got,
331 .load_direct,339 .load_direct,
332 .indirect,340 .indirect,
...@@ -429,6 +437,7 @@ pub const MCValue = union(enum) {...@@ -429,6 +437,7 @@ pub const MCValue = union(enum) {
429 .register_overflow,437 .register_overflow,
430 .register_mask,438 .register_mask,
431 .lea_symbol,439 .lea_symbol,
440 .lea_pcrel,
432 .lea_direct,441 .lea_direct,
433 .lea_got,442 .lea_got,
434 .lea_frame,443 .lea_frame,
...@@ -445,6 +454,7 @@ pub const MCValue = union(enum) {...@@ -445,6 +454,7 @@ pub const MCValue = union(enum) {
445 .load_got => |sym_index| .{ .lea_got = sym_index },454 .load_got => |sym_index| .{ .lea_got = sym_index },
446 .load_frame => |frame_addr| .{ .lea_frame = frame_addr },455 .load_frame => |frame_addr| .{ .lea_frame = frame_addr },
447 .load_symbol => |sym_off| .{ .lea_symbol = sym_off },456 .load_symbol => |sym_off| .{ .lea_symbol = sym_off },
457 .load_pcrel => |sym_off| .{ .lea_pcrel = sym_off },
448 };458 };
449 }459 }
450460
...@@ -466,6 +476,7 @@ pub const MCValue = union(enum) {...@@ -466,6 +476,7 @@ pub const MCValue = union(enum) {
466 .load_got,476 .load_got,
467 .load_frame,477 .load_frame,
468 .load_symbol,478 .load_symbol,
479 .load_pcrel,
469 .elementwise_args,480 .elementwise_args,
470 .reserved_frame,481 .reserved_frame,
471 .air_ref,482 .air_ref,
...@@ -477,6 +488,7 @@ pub const MCValue = union(enum) {...@@ -477,6 +488,7 @@ pub const MCValue = union(enum) {
477 .lea_got => |sym_index| .{ .load_got = sym_index },488 .lea_got => |sym_index| .{ .load_got = sym_index },
478 .lea_frame => |frame_addr| .{ .load_frame = frame_addr },489 .lea_frame => |frame_addr| .{ .load_frame = frame_addr },
479 .lea_symbol => |sym_index| .{ .load_symbol = sym_index },490 .lea_symbol => |sym_index| .{ .load_symbol = sym_index },
491 .lea_pcrel => |sym_index| .{ .load_pcrel = sym_index },
480 };492 };
481 }493 }
482494
...@@ -505,6 +517,8 @@ pub const MCValue = union(enum) {...@@ -505,6 +517,8 @@ pub const MCValue = union(enum) {
505 .load_frame,517 .load_frame,
506 .load_symbol,518 .load_symbol,
507 .lea_symbol,519 .lea_symbol,
520 .load_pcrel,
521 .lea_pcrel,
508 => switch (off) {522 => switch (off) {
509 0 => mcv,523 0 => mcv,
510 else => unreachable, // not offsettable524 else => unreachable, // not offsettable
...@@ -543,6 +557,7 @@ pub const MCValue = union(enum) {...@@ -543,6 +557,7 @@ pub const MCValue = union(enum) {
543 .elementwise_args,557 .elementwise_args,
544 .reserved_frame,558 .reserved_frame,
545 .lea_symbol,559 .lea_symbol,
560 .lea_pcrel,
546 => unreachable,561 => unreachable,
547 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| .{562 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| .{
548 .base = .{ .reg = .ds },563 .base = .{ .reg = .ds },
...@@ -583,6 +598,18 @@ pub const MCValue = union(enum) {...@@ -583,6 +598,18 @@ pub const MCValue = union(enum) {
583 } },598 } },
584 };599 };
585 },600 },
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 },
586 .air_ref => |ref| (try function.resolveInst(ref)).mem(function, mod_rm),613 .air_ref => |ref| (try function.resolveInst(ref)).mem(function, mod_rm),
587 };614 };
588 }615 }
...@@ -618,6 +645,8 @@ pub const MCValue = union(enum) {...@@ -618,6 +645,8 @@ pub const MCValue = union(enum) {
618 }),645 }),
619 .load_symbol => |pl| try writer.print("[sym:{} + 0x{x}]", .{ pl.sym_index, pl.off }),646 .load_symbol => |pl| try writer.print("[sym:{} + 0x{x}]", .{ pl.sym_index, pl.off }),
620 .lea_symbol => |pl| try writer.print("sym:{} + 0x{x}", .{ pl.sym_index, pl.off }),647 .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 }),
621 .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),650 .indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),
622 .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}),651 .load_direct => |pl| try writer.print("[direct:{d}]", .{pl}),
623 .lea_direct => |pl| try writer.print("direct:{d}", .{pl}),652 .lea_direct => |pl| try writer.print("direct:{d}", .{pl}),
...@@ -655,6 +684,8 @@ const InstTracking = struct {...@@ -655,6 +684,8 @@ const InstTracking = struct {
655 .lea_frame,684 .lea_frame,
656 .load_symbol,685 .load_symbol,
657 .lea_symbol,686 .lea_symbol,
687 .load_pcrel,
688 .lea_pcrel,
658 => result,689 => result,
659 .dead,690 .dead,
660 .elementwise_args,691 .elementwise_args,
...@@ -755,6 +786,8 @@ const InstTracking = struct {...@@ -755,6 +786,8 @@ const InstTracking = struct {
755 .lea_frame,786 .lea_frame,
756 .load_symbol,787 .load_symbol,
757 .lea_symbol,788 .lea_symbol,
789 .load_pcrel,
790 .lea_pcrel,
758 => assert(std.meta.eql(self.long, target.long)),791 => assert(std.meta.eql(self.long, target.long)),
759 .dead,792 .dead,
760 .eflags,793 .eflags,
...@@ -1228,12 +1261,7 @@ fn formatAir(...@@ -1228,12 +1261,7 @@ fn formatAir(
1228 _: std.fmt.FormatOptions,1261 _: std.fmt.FormatOptions,
1229 writer: anytype,1262 writer: anytype,
1230) @TypeOf(writer).Error!void {1263) @TypeOf(writer).Error!void {
1231 @import("../../print_air.zig").dumpInst(1264 data.self.air.dumpInst(data.inst, data.self.pt, data.self.liveness);
1232 data.inst,
1233 data.self.pt,
1234 data.self.air,
1235 data.self.liveness,
1236 );
1237}1265}
1238fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {1266fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {
1239 return .{ .data = .{ .self = self, .inst = inst } };1267 return .{ .data = .{ .self = self, .inst = inst } };
...@@ -161477,10 +161505,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -161477,10 +161505,12 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
161477 for (elems, 0..) |elem_ref, field_index| {161505 for (elems, 0..) |elem_ref, field_index| {
161478 const elem_dies = bt.feed();161506 const elem_dies = bt.feed();
161479 if (loaded_struct.fieldIsComptime(ip, field_index)) continue;161507 if (loaded_struct.fieldIsComptime(ip, field_index)) continue;
161480 var elem = try cg.tempFromOperand(elem_ref, elem_dies);161508 if (!hack_around_sema_opv_bugs or Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]).hasRuntimeBitsIgnoreComptime(zcu)) {
161481 try res.write(&elem, .{ .disp = @intCast(loaded_struct.offsets.get(ip)[field_index]) }, cg);161509 var elem = try cg.tempFromOperand(elem_ref, elem_dies);
161482 try elem.die(cg);161510 try res.write(&elem, .{ .disp = @intCast(loaded_struct.offsets.get(ip)[field_index]) }, cg);
161483 try cg.resetTemps(reset_index);161511 try elem.die(cg);
161512 try cg.resetTemps(reset_index);
161513 }
161484 }161514 }
161485 },161515 },
161486 .@"packed" => return cg.fail("failed to select {s} {}", .{161516 .@"packed" => return cg.fail("failed to select {s} {}", .{
...@@ -163487,31 +163517,49 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -163487,31 +163517,49 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
163487 };163517 };
163488 for (ops) |op| try op.die(cg);163518 for (ops) |op| try op.die(cg);
163489 },163519 },
163490 .tlv_dllimport_ptr => switch (cg.bin_file.tag) {163520 .runtime_nav_ptr => switch (cg.bin_file.tag) {
163491 .elf, .macho => {163521 .elf, .macho => {
163492 const ty_nav = air_datas[@intFromEnum(inst)].ty_nav;163522 const ty_nav = air_datas[@intFromEnum(inst)].ty_nav;
163493163523
163494 const nav = ip.getNav(ty_nav.nav);163524 const nav = ip.getNav(ty_nav.nav);
163495 const tlv_sym_index = sym: {163525 const sym_index, const relocation = sym: {
163496 if (cg.bin_file.cast(.elf)) |elf_file| {163526 if (cg.bin_file.cast(.elf)) |elf_file| {
163497 const zo = elf_file.zigObjectPtr().?;163527 const zo = elf_file.zigObjectPtr().?;
163498 if (nav.getExtern(ip)) |e| {163528 if (nav.getExtern(ip)) |e| {
163499 const sym = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip));163529 const sym = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip));
163500 zo.symbol(sym).flags.is_extern_ptr = true;163530 linkage: switch (e.linkage) {
163501 break :sym sym;163531 .internal => {},
163502 }163532 .strong => switch (e.visibility) {
163503 break :sym try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav);163533 .default => zo.symbol(sym).flags.is_extern_ptr = true,
163504 }163534 .hidden, .protected => {},
163505 if (cg.bin_file.cast(.macho)) |macho_file| {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| {
163506 const zo = macho_file.getZigObject().?;163545 const zo = macho_file.getZigObject().?;
163507 if (nav.getExtern(ip)) |e| {163546 if (nav.getExtern(ip)) |e| {
163508 const sym = try macho_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip));163547 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;163548 linkage: switch (e.linkage) {
163510 break :sym sym;163549 .internal => {},
163511 }163550 .strong => switch (e.visibility) {
163512 break :sym try zo.getOrCreateMetadataForNav(macho_file, ty_nav.nav);163551 .default => zo.symbols.items[sym].flags.is_extern_ptr = true,
163513 }163552 .hidden, .protected => {},
163514 unreachable;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;
163515 };163563 };
163516163564
163517 if (cg.mod.pic) {163565 if (cg.mod.pic) {
...@@ -163520,13 +163568,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -163520,13 +163568,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
163520 try cg.spillRegisters(&.{.rax});163568 try cg.spillRegisters(&.{.rax});
163521 }163569 }
163522163570
163523 var slot = try cg.tempInit(.usize, .{ .lea_symbol = .{163571 var slot = try cg.tempInit(.usize, switch (relocation) {
163524 .sym_index = tlv_sym_index,163572 .any => .{ .lea_symbol = .{ .sym_index = sym_index } },
163525 } });163573 .pcrel => .{ .lea_pcrel = .{ .sym_index = sym_index } },
163574 });
163526 while (try slot.toRegClass(true, .general_purpose, cg)) {}163575 while (try slot.toRegClass(true, .general_purpose, cg)) {}
163527 try slot.finish(inst, &.{}, &.{}, cg);163576 try slot.finish(inst, &.{}, &.{}, cg);
163528 },163577 },
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}),
163530 },163579 },
163531 .c_va_arg => try cg.airVaArg(inst),163580 .c_va_arg => try cg.airVaArg(inst),
163532 .c_va_copy => try cg.airVaCopy(inst),163581 .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...@@ -169189,6 +169238,7 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE
169189 .register,169238 .register,
169190 .register_offset,169239 .register_offset,
169191 .lea_symbol,169240 .lea_symbol,
169241 .lea_pcrel,
169192 .lea_direct,169242 .lea_direct,
169193 .lea_got,169243 .lea_got,
169194 .lea_frame,169244 .lea_frame,
...@@ -169196,6 +169246,7 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE...@@ -169196,6 +169246,7 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE
169196 .memory,169246 .memory,
169197 .indirect,169247 .indirect,
169198 .load_symbol,169248 .load_symbol,
169249 .load_pcrel,
169199 .load_direct,169250 .load_direct,
169200 .load_got,169251 .load_got,
169201 .load_frame,169252 .load_frame,
...@@ -169407,6 +169458,7 @@ fn store(...@@ -169407,6 +169458,7 @@ fn store(
169407 .register,169458 .register,
169408 .register_offset,169459 .register_offset,
169409 .lea_symbol,169460 .lea_symbol,
169461 .lea_pcrel,
169410 .lea_direct,169462 .lea_direct,
169411 .lea_got,169463 .lea_got,
169412 .lea_frame,169464 .lea_frame,
...@@ -169414,6 +169466,7 @@ fn store(...@@ -169414,6 +169466,7 @@ fn store(
169414 .memory,169466 .memory,
169415 .indirect,169467 .indirect,
169416 .load_symbol,169468 .load_symbol,
169469 .load_pcrel,
169417 .load_direct,169470 .load_direct,
169418 .load_got,169471 .load_got,
169419 .load_frame,169472 .load_frame,
...@@ -169883,6 +169936,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:...@@ -169883,6 +169936,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
169883 .register_overflow,169936 .register_overflow,
169884 .register_mask,169937 .register_mask,
169885 .lea_symbol,169938 .lea_symbol,
169939 .lea_pcrel,
169886 .lea_direct,169940 .lea_direct,
169887 .lea_got,169941 .lea_got,
169888 .lea_frame,169942 .lea_frame,
...@@ -169892,7 +169946,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:...@@ -169892,7 +169946,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
169892 => unreachable, // unmodifiable destination169946 => unreachable, // unmodifiable destination
169893 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),169947 .register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
169894 .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented169948 .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 => {
169896 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);169950 const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
169897 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);169951 const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
169898 defer self.register_manager.unlockReg(addr_reg_lock);169952 defer self.register_manager.unlockReg(addr_reg_lock);
...@@ -171552,6 +171606,8 @@ fn genBinOp(...@@ -171552,6 +171606,8 @@ fn genBinOp(
171552 .register_mask,171606 .register_mask,
171553 .load_symbol,171607 .load_symbol,
171554 .lea_symbol,171608 .lea_symbol,
171609 .load_pcrel,
171610 .lea_pcrel,
171555 .load_direct,171611 .load_direct,
171556 .lea_direct,171612 .lea_direct,
171557 .load_got,171613 .load_got,
...@@ -172740,6 +172796,7 @@ fn genBinOpMir(...@@ -172740,6 +172796,7 @@ fn genBinOpMir(
172740 .lea_got,172796 .lea_got,
172741 .lea_frame,172797 .lea_frame,
172742 .lea_symbol,172798 .lea_symbol,
172799 .lea_pcrel,
172743 .elementwise_args,172800 .elementwise_args,
172744 .reserved_frame,172801 .reserved_frame,
172745 .air_ref,172802 .air_ref,
...@@ -172831,6 +172888,8 @@ fn genBinOpMir(...@@ -172831,6 +172888,8 @@ fn genBinOpMir(
172831 .indirect,172888 .indirect,
172832 .load_symbol,172889 .load_symbol,
172833 .lea_symbol,172890 .lea_symbol,
172891 .load_pcrel,
172892 .lea_pcrel,
172834 .load_direct,172893 .load_direct,
172835 .lea_direct,172894 .lea_direct,
172836 .load_got,172895 .load_got,
...@@ -172906,7 +172965,7 @@ fn genBinOpMir(...@@ -172906,7 +172965,7 @@ fn genBinOpMir(
172906 }172965 }
172907 }172966 }
172908 },172967 },
172909 .memory, .indirect, .load_symbol, .load_got, .load_direct, .load_frame => {172968 .memory, .indirect, .load_symbol, .load_pcrel, .load_got, .load_direct, .load_frame => {
172910 const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock };172969 const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock };
172911 const limb_abi_size: u32 = @min(abi_size, 8);172970 const limb_abi_size: u32 = @min(abi_size, 8);
172912172971
...@@ -172953,8 +173012,9 @@ fn genBinOpMir(...@@ -172953,8 +173012,9 @@ fn genBinOpMir(
172953 .load_frame,173012 .load_frame,
172954 .lea_frame,173013 .lea_frame,
172955 .lea_symbol,173014 .lea_symbol,
173015 .lea_pcrel,
172956 => null,173016 => null,
172957 .memory, .load_symbol, .load_got, .load_direct => src: {173017 .memory, .load_symbol, .load_pcrel, .load_got, .load_direct => src: {
172958 switch (resolved_src_mcv) {173018 switch (resolved_src_mcv) {
172959 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr))) != null and173019 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr))) != null and
172960 std.math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null)173020 std.math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null)
...@@ -173093,6 +173153,8 @@ fn genBinOpMir(...@@ -173093,6 +173153,8 @@ fn genBinOpMir(
173093 .indirect,173153 .indirect,
173094 .load_symbol,173154 .load_symbol,
173095 .lea_symbol,173155 .lea_symbol,
173156 .load_pcrel,
173157 .lea_pcrel,
173096 .load_direct,173158 .load_direct,
173097 .lea_direct,173159 .lea_direct,
173098 .load_got,173160 .load_got,
...@@ -173160,6 +173222,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv...@@ -173160,6 +173222,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
173160 .register_overflow,173222 .register_overflow,
173161 .register_mask,173223 .register_mask,
173162 .lea_symbol,173224 .lea_symbol,
173225 .lea_pcrel,
173163 .lea_direct,173226 .lea_direct,
173164 .lea_got,173227 .lea_got,
173165 .lea_frame,173228 .lea_frame,
...@@ -173222,6 +173285,8 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv...@@ -173222,6 +173285,8 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
173222 .eflags,173285 .eflags,
173223 .load_symbol,173286 .load_symbol,
173224 .lea_symbol,173287 .lea_symbol,
173288 .load_pcrel,
173289 .lea_pcrel,
173225 .load_direct,173290 .load_direct,
173226 .lea_direct,173291 .lea_direct,
173227 .load_got,173292 .load_got,
...@@ -173281,7 +173346,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv...@@ -173281,7 +173346,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
173281 }173346 }
173282 },173347 },
173283 .register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented173348 .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 => {
173285 const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);173350 const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
173286 const tmp_mcv = MCValue{ .register = tmp_reg };173351 const tmp_mcv = MCValue{ .register = tmp_reg };
173287 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);173352 const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
...@@ -173450,7 +173515,8 @@ fn genLocalDebugInfo(...@@ -173450,7 +173515,8 @@ fn genLocalDebugInfo(
173450 .disp = frame_addr.off,173515 .disp = frame_addr.off,
173451 } },173516 } },
173452 }),173517 }),
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, .{
173454 .base = .{ .reloc = sym_off.sym_index },173520 .base = .{ .reloc = sym_off.sym_index },
173455 .mod = .{ .rm = .{173521 .mod = .{ .rm = .{
173456 .size = .qword,173522 .size = .qword,
...@@ -174108,12 +174174,13 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -174108,12 +174174,13 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174108 .lea_got,174174 .lea_got,
174109 .lea_frame,174175 .lea_frame,
174110 .lea_symbol,174176 .lea_symbol,
174177 .lea_pcrel,
174111 .elementwise_args,174178 .elementwise_args,
174112 .reserved_frame,174179 .reserved_frame,
174113 .air_ref,174180 .air_ref,
174114 => unreachable,174181 => unreachable,
174115 .register, .register_pair, .register_triple, .register_quadruple, .load_frame => null,174182 .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: {
174117 switch (resolved_dst_mcv) {174184 switch (resolved_dst_mcv) {
174118 .memory => |addr| if (std.math.cast(174185 .memory => |addr| if (std.math.cast(
174119 i32,174186 i32,
...@@ -174122,7 +174189,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -174122,7 +174189,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174122 i32,174189 i32,
174123 @as(i64, @bitCast(addr)) + abi_size - 8,174190 @as(i64, @bitCast(addr)) + abi_size - 8,
174124 ) != null) break :dst null,174191 ) != null) break :dst null,
174125 .load_symbol, .load_got, .load_direct => {},174192 .load_symbol, .load_pcrel, .load_got, .load_direct => {},
174126 else => unreachable,174193 else => unreachable,
174127 }174194 }
174128174195
...@@ -174160,6 +174227,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -174160,6 +174227,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174160 .register_mask,174227 .register_mask,
174161 .indirect,174228 .indirect,
174162 .lea_symbol,174229 .lea_symbol,
174230 .lea_pcrel,
174163 .lea_direct,174231 .lea_direct,
174164 .lea_got,174232 .lea_got,
174165 .lea_frame,174233 .lea_frame,
...@@ -174168,7 +174236,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -174168,7 +174236,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174168 .air_ref,174236 .air_ref,
174169 => unreachable,174237 => unreachable,
174170 .register_pair, .register_triple, .register_quadruple, .load_frame => null,174238 .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: {
174172 switch (resolved_src_mcv) {174240 switch (resolved_src_mcv) {
174173 .memory => |addr| if (std.math.cast(174241 .memory => |addr| if (std.math.cast(
174174 i32,174242 i32,
...@@ -174177,7 +174245,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v...@@ -174177,7 +174245,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
174177 i32,174245 i32,
174178 @as(i64, @bitCast(addr)) + abi_size - 8,174246 @as(i64, @bitCast(addr)) + abi_size - 8,
174179 ) != null) break :src null,174247 ) != null) break :src null,
174180 .load_symbol, .load_got, .load_direct => {},174248 .load_symbol, .load_pcrel, .load_got, .load_direct => {},
174181 else => unreachable,174249 else => unreachable,
174182 }174250 }
174183174251
...@@ -174568,6 +174636,7 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)...@@ -174568,6 +174636,7 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)
174568 .lea_direct,174636 .lea_direct,
174569 .lea_got,174637 .lea_got,
174570 .lea_symbol,174638 .lea_symbol,
174639 .lea_pcrel,
174571 .elementwise_args,174640 .elementwise_args,
174572 .reserved_frame,174641 .reserved_frame,
174573 .air_ref,174642 .air_ref,
...@@ -174616,6 +174685,7 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)...@@ -174616,6 +174685,7 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)
174616174685
174617 .memory,174686 .memory,
174618 .load_symbol,174687 .load_symbol,
174688 .load_pcrel,
174619 .load_got,174689 .load_got,
174620 .load_direct,174690 .load_direct,
174621 => {174691 => {
...@@ -174947,8 +175017,7 @@ fn lowerSwitchBr(...@@ -174947,8 +175017,7 @@ fn lowerSwitchBr(
174947) !void {175017) !void {
174948 const zcu = cg.pt.zcu;175018 const zcu = cg.pt.zcu;
174949 const condition_ty = cg.typeOf(switch_br.operand);175019 const condition_ty = cg.typeOf(switch_br.operand);
174950 const condition_int_info = cg.intInfo(condition_ty).?;175020 const unsigned_condition_ty = try cg.pt.intType(.unsigned, cg.intInfo(condition_ty).?.bits);
174951 const condition_int_ty = try cg.pt.intType(condition_int_info.signedness, condition_int_info.bits);
174952175021
174953 const ExpectedContents = extern struct {175022 const ExpectedContents = extern struct {
174954 liveness_deaths: [1 << 8 | 1]Air.Inst.Index,175023 liveness_deaths: [1 << 8 | 1]Air.Inst.Index,
...@@ -175019,8 +175088,8 @@ fn lowerSwitchBr(...@@ -175019,8 +175088,8 @@ fn lowerSwitchBr(
175019 .{ .air_ref = Air.internedToRef(min.?.toIntern()) },175088 .{ .air_ref = Air.internedToRef(min.?.toIntern()) },
175020 );175089 );
175021 const else_reloc = if (switch_br.else_body_len > 0) else_reloc: {175090 const else_reloc = if (switch_br.else_body_len > 0) else_reloc: {
175022 var cond_temp = try cg.tempInit(condition_ty, condition_index);175091 var cond_temp = try cg.tempInit(unsigned_condition_ty, condition_index);
175023 var table_max_temp = try cg.tempFromValue(try cg.pt.intValue(condition_int_ty, table_len - 1));175092 var table_max_temp = try cg.tempFromValue(try cg.pt.intValue(unsigned_condition_ty, table_len - 1));
175024 const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, cg) catch |err| switch (err) {175093 const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, cg) catch |err| switch (err) {
175025 error.SelectFailed => unreachable,175094 error.SelectFailed => unreachable,
175026 else => |e| return e,175095 else => |e| return e,
...@@ -175348,8 +175417,7 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -175348,8 +175417,7 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void {
175348175417
175349 if (self.loop_switches.getPtr(br.block_inst)) |table| {175418 if (self.loop_switches.getPtr(br.block_inst)) |table| {
175350 const condition_ty = self.typeOf(br.operand);175419 const condition_ty = self.typeOf(br.operand);
175351 const condition_int_info = self.intInfo(condition_ty).?;175420 const unsigned_condition_ty = try self.pt.intType(.unsigned, self.intInfo(condition_ty).?.bits);
175352 const condition_int_ty = try self.pt.intType(condition_int_info.signedness, condition_int_info.bits);
175353 const condition_mcv = block_tracking.short;175421 const condition_mcv = block_tracking.short;
175354 try self.spillEflagsIfOccupied();175422 try self.spillEflagsIfOccupied();
175355 if (table.min.orderAgainstZero(self.pt.zcu).compare(.neq)) try self.genBinOpMir(175423 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 {...@@ -175361,8 +175429,8 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void {
175361 switch (table.else_relocs) {175429 switch (table.else_relocs) {
175362 .@"unreachable" => {},175430 .@"unreachable" => {},
175363 .forward => |*else_relocs| {175431 .forward => |*else_relocs| {
175364 var cond_temp = try self.tempInit(condition_ty, condition_mcv);175432 var cond_temp = try self.tempInit(unsigned_condition_ty, condition_mcv);
175365 var table_max_temp = try self.tempFromValue(try self.pt.intValue(condition_int_ty, table.len - 1));175433 var table_max_temp = try self.tempFromValue(try self.pt.intValue(unsigned_condition_ty, table.len - 1));
175366 const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, self) catch |err| switch (err) {175434 const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, self) catch |err| switch (err) {
175367 error.SelectFailed => unreachable,175435 error.SelectFailed => unreachable,
175368 else => |e| return e,175436 else => |e| return e,
...@@ -175373,8 +175441,8 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -175373,8 +175441,8 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void {
175373 try cc_temp.die(self);175441 try cc_temp.die(self);
175374 },175442 },
175375 .backward => |else_reloc| {175443 .backward => |else_reloc| {
175376 var cond_temp = try self.tempInit(condition_ty, condition_mcv);175444 var cond_temp = try self.tempInit(unsigned_condition_ty, condition_mcv);
175377 var table_max_temp = try self.tempFromValue(try self.pt.intValue(condition_int_ty, table.len - 1));175445 var table_max_temp = try self.tempFromValue(try self.pt.intValue(unsigned_condition_ty, table.len - 1));
175378 const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, self) catch |err| switch (err) {175446 const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, self) catch |err| switch (err) {
175379 error.SelectFailed => unreachable,175447 error.SelectFailed => unreachable,
175380 else => |e| return e,175448 else => |e| return e,
...@@ -176625,6 +176693,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C...@@ -176625,6 +176693,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
176625 .lea_got,176693 .lea_got,
176626 .lea_frame,176694 .lea_frame,
176627 .lea_symbol,176695 .lea_symbol,
176696 .lea_pcrel,
176628 .elementwise_args,176697 .elementwise_args,
176629 .reserved_frame,176698 .reserved_frame,
176630 .air_ref,176699 .air_ref,
...@@ -176719,7 +176788,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C...@@ -176719,7 +176788,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
176719 }176788 }
176720 return;176789 return;
176721 },176790 },
176722 .load_symbol, .load_direct, .load_got => {176791 .load_symbol, .load_pcrel, .load_direct, .load_got => {
176723 const src_addr_reg =176792 const src_addr_reg =
176724 (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();176793 (try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
176725 const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);176794 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...@@ -176752,7 +176821,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
176752 .undef => if (opts.safety and part_i > 0) .{ .register = dst_regs[0] } else .undef,176821 .undef => if (opts.safety and part_i > 0) .{ .register = dst_regs[0] } else .undef,
176753 dst_tag => |src_regs| .{ .register = src_regs[part_i] },176822 dst_tag => |src_regs| .{ .register = src_regs[part_i] },
176754 .memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(),176823 .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 = .{
176756 .reg = src_info.?.addr_reg,176825 .reg = src_info.?.addr_reg,
176757 .off = part_disp,176826 .off = part_disp,
176758 } },176827 } },
...@@ -176773,11 +176842,11 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C...@@ -176773,11 +176842,11 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
176773 src_mcv,176842 src_mcv,
176774 opts,176843 opts,
176775 ),176844 ),
176776 .memory, .load_symbol, .load_direct, .load_got => {176845 .memory, .load_symbol, .load_pcrel, .load_direct, .load_got => {
176777 switch (dst_mcv) {176846 switch (dst_mcv) {
176778 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|176847 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
176779 return self.genSetMem(.{ .reg = .ds }, small_addr, ty, src_mcv, opts),176848 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 => {},
176781 else => unreachable,176850 else => unreachable,
176782 }176851 }
176783176852
...@@ -177234,7 +177303,7 @@ fn genSetReg(...@@ -177234,7 +177303,7 @@ fn genSetReg(
177234 if (src_reg_mask.info.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size));177303 if (src_reg_mask.info.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size));
177235 try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{});177304 try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{});
177236 },177305 },
177237 .memory, .load_symbol, .load_direct, .load_got => {177306 .memory, .load_symbol, .load_pcrel, .load_direct, .load_got => {
177238 switch (src_mcv) {177307 switch (src_mcv) {
177239 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|177308 .memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
177240 return (try self.moveStrategy(177309 return (try self.moveStrategy(
...@@ -177263,6 +177332,21 @@ fn genSetReg(...@@ -177263,6 +177332,21 @@ fn genSetReg(
177263 .segment, .mmx, .ip, .cr, .dr => unreachable,177332 .segment, .mmx, .ip, .cr, .dr => unreachable,
177264 .x87, .sse => {},177333 .x87, .sse => {},
177265 },177334 },
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 },
177266 .load_direct => |sym_index| switch (dst_reg.class()) {177350 .load_direct => |sym_index| switch (dst_reg.class()) {
177267 .general_purpose, .gphi => {177351 .general_purpose, .gphi => {
177268 _ = try self.addInst(.{177352 _ = try self.addInst(.{
...@@ -177313,6 +177397,28 @@ fn genSetReg(...@@ -177313,6 +177397,28 @@ fn genSetReg(
177313 @tagName(self.bin_file.tag),177397 @tagName(self.bin_file.tag),
177314 }),177398 }),
177315 },177399 },
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 },
177316 .lea_direct, .lea_got => |sym_index| _ = try self.addInst(.{177422 .lea_direct, .lea_got => |sym_index| _ = try self.addInst(.{
177317 .tag = switch (src_mcv) {177423 .tag = switch (src_mcv) {
177318 .lea_direct => .lea,177424 .lea_direct => .lea,
...@@ -177350,6 +177456,7 @@ fn genSetMem(...@@ -177350,6 +177456,7 @@ fn genSetMem(
177350 .frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } },177456 .frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } },
177351 .table, .rip_inst => unreachable,177457 .table, .rip_inst => unreachable,
177352 .reloc => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index, .off = disp } },177458 .reloc => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index, .off = disp } },
177459 .pcrel => |sym_index| .{ .lea_pcrel = .{ .sym_index = sym_index, .off = disp } },
177353 };177460 };
177354 switch (src_mcv) {177461 switch (src_mcv) {
177355 .none,177462 .none,
...@@ -177466,7 +177573,7 @@ fn genSetMem(...@@ -177466,7 +177573,7 @@ fn genSetMem(
177466 .off = disp,177573 .off = disp,
177467 }).compare(.gte, src_align),177574 }).compare(.gte, src_align),
177468 .table, .rip_inst => unreachable,177575 .table, .rip_inst => unreachable,
177469 .reloc => false,177576 .reloc, .pcrel => false,
177470 })).write(177577 })).write(
177471 self,177578 self,
177472 .{ .base = base, .mod = .{ .rm = .{177579 .{ .base = base, .mod = .{ .rm = .{
...@@ -177557,6 +177664,8 @@ fn genSetMem(...@@ -177557,6 +177664,8 @@ fn genSetMem(
177557 .lea_frame,177664 .lea_frame,
177558 .load_symbol,177665 .load_symbol,
177559 .lea_symbol,177666 .lea_symbol,
177667 .load_pcrel,
177668 .lea_pcrel,
177560 => switch (abi_size) {177669 => switch (abi_size) {
177561 0 => {},177670 0 => {},
177562 1, 2, 4, 8 => {177671 1, 2, 4, 8 => {
...@@ -178110,7 +178219,7 @@ fn airCmpxchg(self: *CodeGen, inst: Air.Inst.Index) !void {...@@ -178110,7 +178219,7 @@ fn airCmpxchg(self: *CodeGen, inst: Air.Inst.Index) !void {
178110 .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),178219 .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
178111 }178220 }
178112 const ptr_lock = switch (ptr_mem.base) {178221 const ptr_lock = switch (ptr_mem.base) {
178113 .none, .frame, .reloc => null,178222 .none, .frame, .reloc, .pcrel => null,
178114 .reg => |reg| self.register_manager.lockReg(reg),178223 .reg => |reg| self.register_manager.lockReg(reg),
178115 .table, .rip_inst => unreachable,178224 .table, .rip_inst => unreachable,
178116 };178225 };
...@@ -178193,7 +178302,7 @@ fn atomicOp(...@@ -178193,7 +178302,7 @@ fn atomicOp(
178193 .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),178302 .off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
178194 }178303 }
178195 const mem_lock = switch (ptr_mem.base) {178304 const mem_lock = switch (ptr_mem.base) {
178196 .none, .frame, .reloc => null,178305 .none, .frame, .reloc, .pcrel => null,
178197 .reg => |reg| self.register_manager.lockReg(reg),178306 .reg => |reg| self.register_manager.lockReg(reg),
178198 .table, .rip_inst => unreachable,178307 .table, .rip_inst => unreachable,
178199 };178308 };
...@@ -182266,6 +182375,8 @@ const Temp = struct {...@@ -182266,6 +182375,8 @@ const Temp = struct {
182266 .memory,182375 .memory,
182267 .load_symbol,182376 .load_symbol,
182268 .lea_symbol,182377 .lea_symbol,
182378 .load_pcrel,
182379 .lea_pcrel,
182269 .indirect,182380 .indirect,
182270 .load_direct,182381 .load_direct,
182271 .lea_direct,182382 .lea_direct,
...@@ -182427,6 +182538,22 @@ const Temp = struct {...@@ -182427,6 +182538,22 @@ const Temp = struct {
182427 assert(limb_index == 0);182538 assert(limb_index == 0);
182428 new_temp_index.tracking(cg).* = .init(.{ .lea_symbol = sym_off });182539 new_temp_index.tracking(cg).* = .init(.{ .lea_symbol = sym_off });
182429 },182540 },
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 },
182430 .load_frame => |frame_addr| {182557 .load_frame => |frame_addr| {
182431 const new_reg =182558 const new_reg =
182432 try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);182559 try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
...@@ -182721,11 +182848,12 @@ const Temp = struct {...@@ -182721,11 +182848,12 @@ const Temp = struct {
182721 .memory,182848 .memory,
182722 .indirect,182849 .indirect,
182723 .load_symbol,182850 .load_symbol,
182851 .load_pcrel,
182724 .load_direct,182852 .load_direct,
182725 .load_got,182853 .load_got,
182726 .load_frame,182854 .load_frame,
182727 => return temp.toRegClass(true, .general_purpose, cg),182855 => return temp.toRegClass(true, .general_purpose, cg),
182728 .lea_symbol => |sym_off| {182856 .lea_symbol, .lea_pcrel => |sym_off| {
182729 const off = sym_off.off;182857 const off = sym_off.off;
182730 // hack around linker relocation bugs182858 // hack around linker relocation bugs
182731 if (false and off == 0) return false;182859 if (false and off == 0) return false;
...@@ -187464,6 +187592,8 @@ const Temp = struct {...@@ -187464,6 +187592,8 @@ const Temp = struct {
187464 .memory,187592 .memory,
187465 .load_symbol,187593 .load_symbol,
187466 .lea_symbol,187594 .lea_symbol,
187595 .load_pcrel,
187596 .lea_pcrel,
187467 .indirect,187597 .indirect,
187468 .load_direct,187598 .load_direct,
187469 .lea_direct,187599 .lea_direct,
...@@ -190044,6 +190174,7 @@ const Select = struct {...@@ -190044,6 +190174,7 @@ const Select = struct {
190044 .register => |base_reg| .{ .reg = base_reg.toSize(.ptr, s.cg.target) },190174 .register => |base_reg| .{ .reg = base_reg.toSize(.ptr, s.cg.target) },
190045 .register_offset => |base_reg_off| .{ .reg = base_reg_off.reg.toSize(.ptr, s.cg.target) },190175 .register_offset => |base_reg_off| .{ .reg = base_reg_off.reg.toSize(.ptr, s.cg.target) },
190046 .lea_symbol => |base_sym_off| .{ .reloc = base_sym_off.sym_index },190176 .lea_symbol => |base_sym_off| .{ .reloc = base_sym_off.sym_index },
190177 .lea_pcrel => |base_sym_off| .{ .pcrel = base_sym_off.sym_index },
190047 },190178 },
190048 .mod = .{ .rm = .{190179 .mod = .{ .rm = .{
190049 .size = op.flags.base.size,190180 .size = op.flags.base.size,
src/arch/x86_64/Emit.zig+9-8
...@@ -189,12 +189,12 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -189,12 +189,12 @@ pub fn emitMir(emit: *Emit) Error!void {
189 .r_addend = lowered_relocs[0].off,189 .r_addend = lowered_relocs[0].off,
190 }, zo);190 }, zo);
191 },191 },
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| {
193 const zo = elf_file.zigObjectPtr().?;193 const zo = elf_file.zigObjectPtr().?;
194 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;194 const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
195 const sym = zo.symbol(sym_index);195 const sym = zo.symbol(sym_index);
196 if (emit.lower.pic) {196 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)
198 @intFromEnum(std.elf.R_X86_64.GOTPCREL)198 @intFromEnum(std.elf.R_X86_64.GOTPCREL)
199 else199 else
200 @intFromEnum(std.elf.R_X86_64.PC32);200 @intFromEnum(std.elf.R_X86_64.PC32);
...@@ -218,7 +218,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -218,7 +218,7 @@ pub fn emitMir(emit: *Emit) Error!void {
218 const zo = macho_file.getZigObject().?;218 const zo = macho_file.getZigObject().?;
219 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;219 const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;
220 const sym = &zo.symbols.items[sym_index];220 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)
222 .got_load222 .got_load
223 else if (sym.flags.tlv)223 else if (sym.flags.tlv)
224 .tlv224 .tlv
...@@ -378,9 +378,9 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -378,9 +378,9 @@ pub fn emitMir(emit: *Emit) Error!void {
378 };378 };
379 break :stack_value &loc_buf[0];379 break :stack_value &loc_buf[0];
380 } } },380 } } },
381 .pseudo_dbg_local_as => .{ mir_inst.data.as.air_inst, .{ .addr = .{381 .pseudo_dbg_local_as => .{ mir_inst.data.as.air_inst, .{
382 .sym = mir_inst.data.as.sym_index,382 .addr_reloc = mir_inst.data.as.sym_index,
383 } } },383 } },
384 .pseudo_dbg_local_aso => loc: {384 .pseudo_dbg_local_aso => loc: {
385 const sym_off = emit.lower.mir.extraData(385 const sym_off = emit.lower.mir.extraData(
386 bits.SymbolOffset,386 bits.SymbolOffset,
...@@ -388,7 +388,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -388,7 +388,7 @@ pub fn emitMir(emit: *Emit) Error!void {
388 ).data;388 ).data;
389 break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{389 break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{
390 sym: {390 sym: {
391 loc_buf[0] = .{ .addr = .{ .sym = sym_off.sym_index } };391 loc_buf[0] = .{ .addr_reloc = sym_off.sym_index };
392 break :sym &loc_buf[0];392 break :sym &loc_buf[0];
393 },393 },
394 off: {394 off: {
...@@ -437,7 +437,8 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -437,7 +437,8 @@ pub fn emitMir(emit: *Emit) Error!void {
437 .none => .{ .constu = 0 },437 .none => .{ .constu = 0 },
438 .reg => |reg| .{ .breg = reg.dwarfNum() },438 .reg => |reg| .{ .breg = reg.dwarfNum() },
439 .frame, .table, .rip_inst => unreachable,439 .frame, .table, .rip_inst => unreachable,
440 .reloc => |sym_index| .{ .addr = .{ .sym = sym_index } },440 .reloc => |sym_index| .{ .addr_reloc = sym_index },
441 .pcrel => unreachable,
441 };442 };
442 break :base &loc_buf[0];443 break :base &loc_buf[0];
443 },444 },
src/arch/x86_64/Lower.zig+19-2
...@@ -66,6 +66,7 @@ pub const Reloc = struct {...@@ -66,6 +66,7 @@ pub const Reloc = struct {
66 inst: Mir.Inst.Index,66 inst: Mir.Inst.Index,
67 table,67 table,
68 linker_reloc: u32,68 linker_reloc: u32,
69 linker_pcrel: u32,
69 linker_tlsld: u32,70 linker_tlsld: u32,
70 linker_dtpoff: u32,71 linker_dtpoff: u32,
71 linker_extern_fn: u32,72 linker_extern_fn: u32,
...@@ -421,9 +422,9 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)...@@ -421,9 +422,9 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
421 for (emit_ops, ops, 0..) |*emit_op, op, op_index| {422 for (emit_ops, ops, 0..) |*emit_op, op, op_index| {
422 emit_op.* = switch (op) {423 emit_op.* = switch (op) {
423 else => op,424 else => op,
424 .mem => |mem_op| switch (mem_op.base()) {425 .mem => |mem_op| op: switch (mem_op.base()) {
425 else => op,426 else => op,
426 .reloc => |sym_index| op: {427 .reloc => |sym_index| {
427 assert(prefix == .none);428 assert(prefix == .none);
428 assert(mem_op.sib.disp == 0);429 assert(mem_op.sib.disp == 0);
429 assert(mem_op.sib.scale_index.scale == 0);430 assert(mem_op.sib.scale_index.scale == 0);
...@@ -559,6 +560,22 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)...@@ -559,6 +560,22 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
559 return lower.fail("TODO: bin format '{s}'", .{@tagName(lower.bin_file.tag)});560 return lower.fail("TODO: bin format '{s}'", .{@tagName(lower.bin_file.tag)});
560 }561 }
561 },562 },
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 },
562 },579 },
563 };580 };
564 }581 }
src/arch/x86_64/Mir.zig+3-2
...@@ -1866,7 +1866,7 @@ pub const Memory = struct {...@@ -1866,7 +1866,7 @@ pub const Memory = struct {
1866 .none, .table => undefined,1866 .none, .table => undefined,
1867 .reg => |reg| @intFromEnum(reg),1867 .reg => |reg| @intFromEnum(reg),
1868 .frame => |frame_index| @intFromEnum(frame_index),1868 .frame => |frame_index| @intFromEnum(frame_index),
1869 .reloc => |sym_index| sym_index,1869 .reloc, .pcrel => |sym_index| sym_index,
1870 .rip_inst => |inst_index| inst_index,1870 .rip_inst => |inst_index| inst_index,
1871 },1871 },
1872 .off = switch (mem.mod) {1872 .off = switch (mem.mod) {
...@@ -1895,6 +1895,7 @@ pub const Memory = struct {...@@ -1895,6 +1895,7 @@ pub const Memory = struct {
1895 .frame => .{ .frame = @enumFromInt(mem.base) },1895 .frame => .{ .frame = @enumFromInt(mem.base) },
1896 .table => .table,1896 .table => .table,
1897 .reloc => .{ .reloc = mem.base },1897 .reloc => .{ .reloc = mem.base },
1898 .pcrel => .{ .pcrel = mem.base },
1898 .rip_inst => .{ .rip_inst = mem.base },1899 .rip_inst => .{ .rip_inst = mem.base },
1899 },1900 },
1900 .scale_index = switch (mem.info.index) {1901 .scale_index = switch (mem.info.index) {
...@@ -1959,7 +1960,7 @@ pub fn resolveFrameAddr(mir: Mir, frame_addr: bits.FrameAddr) bits.RegisterOffse...@@ -1959,7 +1960,7 @@ pub fn resolveFrameAddr(mir: Mir, frame_addr: bits.FrameAddr) bits.RegisterOffse
19591960
1960pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory {1961pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory {
1961 return switch (mem.info.base) {1962 return switch (mem.info.base) {
1962 .none, .reg, .table, .reloc, .rip_inst => mem,1963 .none, .reg, .table, .reloc, .pcrel, .rip_inst => mem,
1963 .frame => if (mir.frame_locs.len > 0) .{1964 .frame => if (mir.frame_locs.len > 0) .{
1964 .info = .{1965 .info = .{
1965 .base = .reg,1966 .base = .reg,
src/arch/x86_64/bits.zig+1
...@@ -762,6 +762,7 @@ pub const Memory = struct {...@@ -762,6 +762,7 @@ pub const Memory = struct {
762 frame: FrameIndex,762 frame: FrameIndex,
763 table,763 table,
764 reloc: u32,764 reloc: u32,
765 pcrel: u32,
765 rip_inst: Mir.Inst.Index,766 rip_inst: Mir.Inst.Index,
766767
767 pub const Tag = @typeInfo(Base).@"union".tag_type.?;768 pub const Tag = @typeInfo(Base).@"union".tag_type.?;
src/arch/x86_64/encoder.zig+4-3
...@@ -138,7 +138,7 @@ pub const Instruction = struct {...@@ -138,7 +138,7 @@ pub const Instruction = struct {
138 .moffs => true,138 .moffs => true,
139 .rip => false,139 .rip => false,
140 .sib => |s| switch (s.base) {140 .sib => |s| switch (s.base) {
141 .none, .frame, .table, .reloc, .rip_inst => false,141 .none, .frame, .table, .reloc, .pcrel, .rip_inst => false,
142 .reg => |reg| reg.isClass(.segment),142 .reg => |reg| reg.isClass(.segment),
143 },143 },
144 };144 };
...@@ -211,7 +211,7 @@ pub const Instruction = struct {...@@ -211,7 +211,7 @@ pub const Instruction = struct {
211 .none, .imm => 0b00,211 .none, .imm => 0b00,
212 .reg => |reg| @truncate(reg.enc() >> 3),212 .reg => |reg| @truncate(reg.enc() >> 3),
213 .mem => |mem| switch (mem.base()) {213 .mem => |mem| switch (mem.base()) {
214 .none, .frame, .table, .reloc, .rip_inst => 0b00, // rsp, rbp, and rip are not extended214 .none, .frame, .table, .reloc, .pcrel, .rip_inst => 0b00, // rsp, rbp, and rip are not extended
215 .reg => |reg| @truncate(reg.enc() >> 3),215 .reg => |reg| @truncate(reg.enc() >> 3),
216 },216 },
217 .bytes => unreachable,217 .bytes => unreachable,
...@@ -282,6 +282,7 @@ pub const Instruction = struct {...@@ -282,6 +282,7 @@ pub const Instruction = struct {
282 .frame => |frame_index| try writer.print("{}", .{frame_index}),282 .frame => |frame_index| try writer.print("{}", .{frame_index}),
283 .table => try writer.print("Table", .{}),283 .table => try writer.print("Table", .{}),
284 .reloc => |sym_index| try writer.print("Symbol({d})", .{sym_index}),284 .reloc => |sym_index| try writer.print("Symbol({d})", .{sym_index}),
285 .pcrel => |sym_index| try writer.print("PcRelSymbol({d})", .{sym_index}),
285 .rip_inst => |inst_index| try writer.print("RipInst({d})", .{inst_index}),286 .rip_inst => |inst_index| try writer.print("RipInst({d})", .{inst_index}),
286 }287 }
287 if (mem.scaleIndex()) |si| {288 if (mem.scaleIndex()) |si| {
...@@ -721,7 +722,7 @@ pub const Instruction = struct {...@@ -721,7 +722,7 @@ pub const Instruction = struct {
721 try encoder.modRm_indirectDisp32(operand_enc, 0);722 try encoder.modRm_indirectDisp32(operand_enc, 0);
722 try encoder.disp32(undefined);723 try encoder.disp32(undefined);
723 } else return error.CannotEncode,724 } else return error.CannotEncode,
724 .rip_inst => {725 .pcrel, .rip_inst => {
725 try encoder.modRm_RIPDisp32(operand_enc);726 try encoder.modRm_RIPDisp32(operand_enc);
726 try encoder.disp32(sib.disp);727 try encoder.disp32(sib.disp);
727 },728 },
src/codegen.zig+57-24
...@@ -921,41 +921,74 @@ fn genNavRef(...@@ -921,41 +921,74 @@ fn genNavRef(
921 const nav = ip.getNav(nav_index);921 const nav = ip.getNav(nav_index);
922 assert(!nav.isThreadlocal(ip));922 assert(!nav.isThreadlocal(ip));
923923
924 const is_extern, const lib_name = if (nav.getExtern(ip)) |e|924 const lib_name, const linkage, const visibility = if (nav.getExtern(ip)) |e|
925 .{ true, e.lib_name }925 .{ e.lib_name, e.linkage, e.visibility }
926 else926 else
927 .{ false, .none };927 .{ .none, .internal, .default };
928928
929 const name = nav.name;929 const name = nav.name;
930 if (lf.cast(.elf)) |elf_file| {930 if (lf.cast(.elf)) |elf_file| {
931 const zo = elf_file.zigObjectPtr().?;931 const zo = elf_file.zigObjectPtr().?;
932 if (is_extern) {932 switch (linkage) {
933 const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));933 .internal => {
934 zo.symbol(sym_index).flags.is_extern_ptr = true;934 const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index);
935 return .{ .mcv = .{ .lea_symbol = sym_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,
936 }952 }
937 const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index);
938 return .{ .mcv = .{ .lea_symbol = sym_index } };
939 } else if (lf.cast(.macho)) |macho_file| {953 } else if (lf.cast(.macho)) |macho_file| {
940 const zo = macho_file.getZigObject().?;954 const zo = macho_file.getZigObject().?;
941 if (is_extern) {955 switch (linkage) {
942 const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));956 .internal => {
943 zo.symbols.items[sym_index].flags.is_extern_ptr = true;957 const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);
944 return .{ .mcv = .{ .lea_symbol = sym_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,
945 }976 }
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 } };
949 } else if (lf.cast(.coff)) |coff_file| {977 } else if (lf.cast(.coff)) |coff_file| {
950 if (is_extern) {978 // TODO audit this
951 // TODO audit this979 switch (linkage) {
952 const global_index = try coff_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));980 .internal => {
953 try coff_file.need_got_table.put(gpa, global_index, {}); // needs GOT981 const atom_index = try coff_file.getOrCreateAtomForNav(nav_index);
954 return .{ .mcv = .{ .load_got = link.File.Coff.global_symbol_bit | global_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,
955 }991 }
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 } };
959 } else if (lf.cast(.plan9)) |p9| {992 } else if (lf.cast(.plan9)) |p9| {
960 const atom_index = try p9.seeNav(pt, nav_index);993 const atom_index = try p9.seeNav(pt, nav_index);
961 const atom = p9.getAtom(atom_index);994 const atom = p9.getAtom(atom_index);
src/codegen/c.zig+22-12
...@@ -2255,19 +2255,30 @@ pub const DeclGen = struct {...@@ -2255,19 +2255,30 @@ pub const DeclGen = struct {
2255 fn renderFwdDecl(2255 fn renderFwdDecl(
2256 dg: *DeclGen,2256 dg: *DeclGen,
2257 nav_index: InternPool.Nav.Index,2257 nav_index: InternPool.Nav.Index,
2258 flags: struct {2258 flags: packed struct {
2259 is_extern: bool,
2260 is_const: bool,2259 is_const: bool,
2261 is_threadlocal: bool,2260 is_threadlocal: bool,
2262 is_weak_linkage: bool,2261 linkage: std.builtin.GlobalLinkage,
2262 visibility: std.builtin.SymbolVisibility,
2263 },2263 },
2264 ) !void {2264 ) !void {
2265 const zcu = dg.pt.zcu;2265 const zcu = dg.pt.zcu;
2266 const ip = &zcu.intern_pool;2266 const ip = &zcu.intern_pool;
2267 const nav = ip.getNav(nav_index);2267 const nav = ip.getNav(nav_index);
2268 const fwd = dg.fwdDeclWriter();2268 const fwd = dg.fwdDeclWriter();
2269 try fwd.writeAll(if (flags.is_extern) "zig_extern " else "static ");2269 try fwd.writeAll(switch (flags.linkage) {
2270 if (flags.is_weak_linkage) try fwd.writeAll("zig_weak_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 }
2271 if (flags.is_threadlocal and !dg.mod.single_threaded) try fwd.writeAll("zig_threadlocal ");2282 if (flags.is_threadlocal and !dg.mod.single_threaded) try fwd.writeAll("zig_threadlocal ");
2272 try dg.renderTypeAndName(2283 try dg.renderTypeAndName(
2273 fwd,2284 fwd,
...@@ -2994,10 +3005,10 @@ pub fn genDecl(o: *Object) !void {...@@ -2994,10 +3005,10 @@ pub fn genDecl(o: *Object) !void {
2994 switch (ip.indexToKey(nav.status.fully_resolved.val)) {3005 switch (ip.indexToKey(nav.status.fully_resolved.val)) {
2995 .@"extern" => |@"extern"| {3006 .@"extern" => |@"extern"| {
2996 if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{3007 if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{
2997 .is_extern = true,
2998 .is_const = @"extern".is_const,3008 .is_const = @"extern".is_const,
2999 .is_threadlocal = @"extern".is_threadlocal,3009 .is_threadlocal = @"extern".is_threadlocal,
3000 .is_weak_linkage = @"extern".is_weak_linkage,3010 .linkage = @"extern".linkage,
3011 .visibility = @"extern".visibility,
3001 });3012 });
30023013
3003 const fwd = o.dg.fwdDeclWriter();3014 const fwd = o.dg.fwdDeclWriter();
...@@ -3016,13 +3027,12 @@ pub fn genDecl(o: *Object) !void {...@@ -3016,13 +3027,12 @@ pub fn genDecl(o: *Object) !void {
3016 },3027 },
3017 .variable => |variable| {3028 .variable => |variable| {
3018 try o.dg.renderFwdDecl(o.dg.pass.nav, .{3029 try o.dg.renderFwdDecl(o.dg.pass.nav, .{
3019 .is_extern = false,
3020 .is_const = false,3030 .is_const = false,
3021 .is_threadlocal = variable.is_threadlocal,3031 .is_threadlocal = variable.is_threadlocal,
3022 .is_weak_linkage = variable.is_weak_linkage,3032 .linkage = .internal,
3033 .visibility = .default,
3023 });3034 });
3024 const w = o.writer();3035 const w = o.writer();
3025 if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
3026 if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");3036 if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");
3027 if (nav.status.fully_resolved.@"linksection".toSlice(&zcu.intern_pool)) |s|3037 if (nav.status.fully_resolved.@"linksection".toSlice(&zcu.intern_pool)) |s|
3028 try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});3038 try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
...@@ -3467,7 +3477,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,...@@ -3467,7 +3477,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
3467 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),3477 .error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
3468 .vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),3478 .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
3472 .c_va_start => try airCVaStart(f, inst),3482 .c_va_start => try airCVaStart(f, inst),
3473 .c_va_arg => try airCVaArg(f, inst),3483 .c_va_arg => try airCVaArg(f, inst),
...@@ -7672,7 +7682,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -7672,7 +7682,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
7672 return local;7682 return local;
7673}7683}
76747684
7675fn airTlvDllimportPtr(f: *Function, inst: Air.Inst.Index) !CValue {7685fn airRuntimeNavPtr(f: *Function, inst: Air.Inst.Index) !CValue {
7676 const ty_nav = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;7686 const ty_nav = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
7677 const writer = f.object.writer();7687 const writer = f.object.writer();
7678 const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty));7688 const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty));
src/codegen/llvm.zig+73-50
...@@ -2979,36 +2979,49 @@ pub const Object = struct {...@@ -2979,36 +2979,49 @@ pub const Object = struct {
2979 const zcu = pt.zcu;2979 const zcu = pt.zcu;
2980 const ip = &zcu.intern_pool;2980 const ip = &zcu.intern_pool;
2981 const nav = ip.getNav(nav_index);2981 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) {
2983 .unresolved => unreachable,2983 .unresolved => unreachable,
2984 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {2984 .fully_resolved => |r| switch (ip.indexToKey(r.val)) {
2985 .variable => |variable| .{ false, variable.is_threadlocal, variable.is_weak_linkage, false },2985 .variable => |variable| .{ .internal, .default, variable.is_threadlocal, false },
2986 .@"extern" => |@"extern"| .{ true, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import },2986 .@"extern" => |@"extern"| .{ @"extern".linkage, .fromSymbolVisibility(@"extern".visibility), @"extern".is_threadlocal, @"extern".is_dll_import },
2987 else => .{ false, false, false, false },2987 else => .{ .internal, .default, false, false },
2988 },2988 },
2989 // This means it's a source declaration which is not `extern`!2989 // 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 },
2991 };2991 };
29922992
2993 const variable_index = try o.builder.addVariable(2993 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)),
2995 try o.lowerType(Type.fromInterned(nav.typeOf(ip))),2999 try o.lowerType(Type.fromInterned(nav.typeOf(ip))),
2996 toLlvmGlobalAddressSpace(nav.getAddrspace(), zcu.getTarget()),3000 toLlvmGlobalAddressSpace(nav.getAddrspace(), zcu.getTarget()),
2997 );3001 );
2998 gop.value_ptr.* = variable_index.ptrConst(&o.builder).global;3002 gop.value_ptr.* = variable_index.ptrConst(&o.builder).global;
29993003
3000 // This is needed for declarations created by `@extern`.3004 // This is needed for declarations created by `@extern`.
3001 if (is_extern) {3005 switch (linkage) {
3002 variable_index.setLinkage(.external, &o.builder);3006 .internal => {
3003 variable_index.setUnnamedAddr(.default, &o.builder);3007 variable_index.setLinkage(.internal, &o.builder);
3004 if (is_threadlocal and !zcu.navFileScope(nav_index).mod.?.single_threaded)3008 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
3005 variable_index.setThreadLocal(.generaldynamic, &o.builder);3009 },
3006 if (is_weak_linkage) variable_index.setLinkage(.extern_weak, &o.builder);3010 .strong, .weak => {
3007 if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder);3011 variable_index.setLinkage(switch (linkage) {
3008 } else {3012 .internal => unreachable,
3009 variable_index.setLinkage(.internal, &o.builder);3013 .strong => .external,
3010 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);3014 .weak => .extern_weak,
3011 }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);
3012 return variable_index;3025 return variable_index;
3013 }3026 }
30143027
...@@ -4530,14 +4543,14 @@ pub const NavGen = struct {...@@ -4530,14 +4543,14 @@ pub const NavGen = struct {
4530 const nav = ip.getNav(nav_index);4543 const nav = ip.getNav(nav_index);
4531 const resolved = nav.status.fully_resolved;4544 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)) {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)) {
4534 .variable => |variable| .{ false, .none, variable.is_threadlocal, variable.is_weak_linkage, false, false, variable.init, variable.owner_nav },4547 .variable => |variable| .{ .none, .internal, .default, variable.is_threadlocal, 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 },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 },
4536 else => .{ false, .none, false, false, false, true, resolved.val, nav_index },4549 else => .{ .none, .internal, .default, false, false, true, resolved.val, nav_index },
4537 };4550 };
4538 const ty = Type.fromInterned(nav.typeOf(ip));4551 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())) {
4541 _ = try o.resolveLlvmFunction(owner_nav);4554 _ = try o.resolveLlvmFunction(owner_nav);
4542 } else {4555 } else {
4543 const variable_index = try o.resolveGlobalNav(nav_index);4556 const variable_index = try o.resolveGlobalNav(nav_index);
...@@ -4549,6 +4562,7 @@ pub const NavGen = struct {...@@ -4549,6 +4562,7 @@ pub const NavGen = struct {
4549 .none => .no_init,4562 .none => .no_init,
4550 else => try o.lowerValue(init_val),4563 else => try o.lowerValue(init_val),
4551 }, &o.builder);4564 }, &o.builder);
4565 variable_index.setVisibility(visibility, &o.builder);
45524566
4553 const file_scope = zcu.navFileScopeIndex(nav_index);4567 const file_scope = zcu.navFileScopeIndex(nav_index);
4554 const mod = zcu.fileByIndex(file_scope).mod.?;4568 const mod = zcu.fileByIndex(file_scope).mod.?;
...@@ -4568,7 +4582,7 @@ pub const NavGen = struct {...@@ -4568,7 +4582,7 @@ pub const NavGen = struct {
4568 line_number,4582 line_number,
4569 try o.lowerDebugType(ty),4583 try o.lowerDebugType(ty),
4570 variable_index,4584 variable_index,
4571 .{ .local = !is_extern },4585 .{ .local = linkage == .internal },
4572 );4586 );
45734587
4574 const debug_expression = try o.builder.debugExpression(&.{});4588 const debug_expression = try o.builder.debugExpression(&.{});
...@@ -4583,38 +4597,47 @@ pub const NavGen = struct {...@@ -4583,38 +4597,47 @@ pub const NavGen = struct {
4583 }4597 }
4584 }4598 }
45854599
4586 if (is_extern) {4600 switch (linkage) {
4587 const global_index = o.nav_map.get(nav_index).?;4601 .internal => {},
4602 .strong, .weak => {
4603 const global_index = o.nav_map.get(nav_index).?;
45884604
4589 const decl_name = decl_name: {4605 const decl_name = decl_name: {
4590 if (zcu.getTarget().cpu.arch.isWasm() and ty.zigTypeTag(zcu) == .@"fn") {4606 if (zcu.getTarget().cpu.arch.isWasm() and ty.zigTypeTag(zcu) == .@"fn") {
4591 if (lib_name.toSlice(ip)) |lib_name_slice| {4607 if (lib_name.toSlice(ip)) |lib_name_slice| {
4592 if (!std.mem.eql(u8, lib_name_slice, "c")) {4608 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 });4609 break :decl_name try o.builder.strtabStringFmt("{}|{s}", .{ nav.name.fmt(ip), lib_name_slice });
4610 }
4594 }4611 }
4595 }4612 }
4596 }4613 break :decl_name try o.builder.strtabString(nav.name.toSlice(ip));
4597 break :decl_name try o.builder.strtabString(nav.name.toSlice(ip));4614 };
4598 };
45994615
4600 if (o.builder.getGlobal(decl_name)) |other_global| {4616 if (o.builder.getGlobal(decl_name)) |other_global| {
4601 if (other_global != global_index) {4617 if (other_global != global_index) {
4602 // Another global already has this name; just use it in place of this global.4618 // Another global already has this name; just use it in place of this global.
4603 try global_index.replace(other_global, &o.builder);4619 try global_index.replace(other_global, &o.builder);
4604 return;4620 return;
4621 }
4605 }4622 }
4606 }
46074623
4608 try global_index.rename(decl_name, &o.builder);4624 try global_index.rename(decl_name, &o.builder);
4609 global_index.setLinkage(.external, &o.builder);4625 global_index.setUnnamedAddr(.default, &o.builder);
4610 global_index.setUnnamedAddr(.default, &o.builder);4626 if (is_dll_import) {
4611 if (is_dll_import) {4627 global_index.setDllStorageClass(.dllimport, &o.builder);
4612 global_index.setDllStorageClass(.dllimport, &o.builder);4628 } else if (zcu.comp.config.dll_export_fns) {
4613 } else if (zcu.comp.config.dll_export_fns) {4629 global_index.setDllStorageClass(.default, &o.builder);
4614 global_index.setDllStorageClass(.default, &o.builder);4630 }
4615 }
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,
4618 }4641 }
4619 }4642 }
4620};4643};
...@@ -5023,7 +5046,7 @@ pub const FuncGen = struct {...@@ -5023,7 +5046,7 @@ pub const FuncGen = struct {
50235046
5024 .vector_store_elem => try self.airVectorStoreElem(inst),5047 .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
5028 .inferred_alloc, .inferred_alloc_comptime => unreachable,5051 .inferred_alloc, .inferred_alloc_comptime => unreachable,
50295052
...@@ -8122,7 +8145,7 @@ pub const FuncGen = struct {...@@ -8122,7 +8145,7 @@ pub const FuncGen = struct {
8122 return .none;8145 return .none;
8123 }8146 }
81248147
8125 fn airTlvDllimportPtr(fg: *FuncGen, inst: Air.Inst.Index) !Builder.Value {8148 fn airRuntimeNavPtr(fg: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
8126 const o = fg.ng.object;8149 const o = fg.ng.object;
8127 const ty_nav = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;8150 const ty_nav = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
8128 const llvm_ptr_const = try o.lowerNavRefValue(ty_nav.nav);8151 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!...@@ -308,7 +308,7 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
308 assert(comp.libcxx_static_lib == null);308 assert(comp.libcxx_static_lib == null);
309 const crt_file = try sub_compilation.toCrtFile();309 const crt_file = try sub_compilation.toCrtFile();
310 comp.libcxx_static_lib = crt_file;310 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);
312}312}
313313
314pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void {314pub 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...@@ -504,7 +504,7 @@ pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
504 assert(comp.libcxxabi_static_lib == null);504 assert(comp.libcxxabi_static_lib == null);
505 const crt_file = try sub_compilation.toCrtFile();505 const crt_file = try sub_compilation.toCrtFile();
506 comp.libcxxabi_static_lib = crt_file;506 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);
508}508}
509509
510pub fn addCxxArgs(510pub fn addCxxArgs(
src/libs/libtsan.zig+1-1
...@@ -325,7 +325,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo...@@ -325,7 +325,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
325 };325 };
326326
327 const crt_file = try sub_compilation.toCrtFile();327 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);
329 assert(comp.tsan_lib == null);329 assert(comp.tsan_lib == null);
330 comp.tsan_lib = crt_file;330 comp.tsan_lib = crt_file;
331}331}
src/libs/libunwind.zig+1-1
...@@ -195,7 +195,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr...@@ -195,7 +195,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
195 };195 };
196196
197 const crt_file = try sub_compilation.toCrtFile();197 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);
199 assert(comp.libunwind_static_lib == null);199 assert(comp.libunwind_static_lib == null);
200 comp.libunwind_static_lib = crt_file;200 comp.libunwind_static_lib = crt_file;
201}201}
src/libs/musl.zig+1-1
...@@ -278,7 +278,7 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro...@@ -278,7 +278,7 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
278 errdefer comp.gpa.free(basename);278 errdefer comp.gpa.free(basename);
279279
280 const crt_file = try sub_compilation.toCrtFile();280 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);
282 {282 {
283 comp.mutex.lock();283 comp.mutex.lock();
284 defer comp.mutex.unlock();284 defer comp.mutex.unlock();
src/link/Dwarf.zig+34-20
...@@ -1051,7 +1051,7 @@ const Entry = struct {...@@ -1051,7 +1051,7 @@ const Entry = struct {
1051 const ref = zo.getSymbolRef(reloc.target_sym, macho_file);1051 const ref = zo.getSymbolRef(reloc.target_sym, macho_file);
1052 try dwarf.resolveReloc(1052 try dwarf.resolveReloc(
1053 entry_off + reloc.source_off,1053 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)),
1055 @intFromEnum(dwarf.address_size),1055 @intFromEnum(dwarf.address_size),
1056 );1056 );
1057 }1057 }
...@@ -1085,13 +1085,19 @@ const ExternalReloc = struct {...@@ -1085,13 +1085,19 @@ const ExternalReloc = struct {
10851085
1086pub const Loc = union(enum) {1086pub const Loc = union(enum) {
1087 empty,1087 empty,
1088 addr: union(enum) { sym: u32 },1088 addr_reloc: u32,
1089 deref: *const Loc,
1089 constu: u64,1090 constu: u64,
1090 consts: i64,1091 consts: i64,
1091 plus: Bin,1092 plus: Bin,
1092 reg: u32,1093 reg: u32,
1093 breg: u32,1094 breg: u32,
1094 push_object_address,1095 push_object_address,
1096 call: struct {
1097 args: []const Loc = &.{},
1098 unit: Unit.Index,
1099 entry: Entry.Index,
1100 },
1095 form_tls_address: *const Loc,1101 form_tls_address: *const Loc,
1096 implicit_value: []const u8,1102 implicit_value: []const u8,
1097 stack_value: *const Loc,1103 stack_value: *const Loc,
...@@ -1136,11 +1142,13 @@ pub const Loc = union(enum) {...@@ -1136,11 +1142,13 @@ pub const Loc = union(enum) {
1136 const writer = adapter.writer();1142 const writer = adapter.writer();
1137 switch (loc) {1143 switch (loc) {
1138 .empty => {},1144 .empty => {},
1139 .addr => |addr| {1145 .addr_reloc => |sym_index| {
1140 try writer.writeByte(DW.OP.addr);1146 try writer.writeByte(DW.OP.addr);
1141 switch (addr) {1147 try adapter.addrSym(sym_index);
1142 .sym => |sym_index| try adapter.addrSym(sym_index),1148 },
1143 }1149 .deref => |addr| {
1150 try addr.write(adapter);
1151 try writer.writeByte(DW.OP.deref);
1144 },1152 },
1145 .constu => |constu| if (std.math.cast(u5, constu)) |lit| {1153 .constu => |constu| if (std.math.cast(u5, constu)) |lit| {
1146 try writer.writeByte(@as(u8, DW.OP.lit0) + lit);1154 try writer.writeByte(@as(u8, DW.OP.lit0) + lit);
...@@ -1225,6 +1233,11 @@ pub const Loc = union(enum) {...@@ -1225,6 +1233,11 @@ pub const Loc = union(enum) {
1225 try sleb128(writer, 0);1233 try sleb128(writer, 0);
1226 },1234 },
1227 .push_object_address => try writer.writeByte(DW.OP.push_object_address),1235 .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 },
1228 .form_tls_address => |addr| {1241 .form_tls_address => |addr| {
1229 try addr.write(adapter);1242 try addr.write(adapter);
1230 try writer.writeByte(DW.OP.form_tls_address);1243 try writer.writeByte(DW.OP.form_tls_address);
...@@ -1385,12 +1398,12 @@ pub const Cfa = union(enum) {...@@ -1385,12 +1398,12 @@ pub const Cfa = union(enum) {
1385 },1398 },
1386 .def_cfa_expression => |expr| {1399 .def_cfa_expression => |expr| {
1387 try writer.writeByte(DW.CFA.def_cfa_expression);1400 try writer.writeByte(DW.CFA.def_cfa_expression);
1388 try wip_nav.frameExprloc(expr);1401 try wip_nav.frameExprLoc(expr);
1389 },1402 },
1390 .expression => |reg_expr| {1403 .expression => |reg_expr| {
1391 try writer.writeByte(DW.CFA.expression);1404 try writer.writeByte(DW.CFA.expression);
1392 try uleb128(writer, reg_expr.reg);1405 try uleb128(writer, reg_expr.reg);
1393 try wip_nav.frameExprloc(reg_expr.expr);1406 try wip_nav.frameExprLoc(reg_expr.expr);
1394 },1407 },
1395 .val_offset => |reg_off| {1408 .val_offset => |reg_off| {
1396 const factored_off = @divExact(reg_off.off, wip_nav.dwarf.debug_frame.header.data_alignment_factor);1409 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) {...@@ -1407,7 +1420,7 @@ pub const Cfa = union(enum) {
1407 .val_expression => |reg_expr| {1420 .val_expression => |reg_expr| {
1408 try writer.writeByte(DW.CFA.val_expression);1421 try writer.writeByte(DW.CFA.val_expression);
1409 try uleb128(writer, reg_expr.reg);1422 try uleb128(writer, reg_expr.reg);
1410 try wip_nav.frameExprloc(reg_expr.expr);1423 try wip_nav.frameExprLoc(reg_expr.expr);
1411 },1424 },
1412 .escape => |bytes| try writer.writeAll(bytes),1425 .escape => |bytes| try writer.writeAll(bytes),
1413 }1426 }
...@@ -1471,7 +1484,7 @@ pub const WipNav = struct {...@@ -1471,7 +1484,7 @@ pub const WipNav = struct {
1471 });1484 });
1472 try wip_nav.strp(name);1485 try wip_nav.strp(name);
1473 try wip_nav.refType(ty);1486 try wip_nav.refType(ty);
1474 try wip_nav.infoExprloc(loc);1487 try wip_nav.infoExprLoc(loc);
1475 wip_nav.any_children = true;1488 wip_nav.any_children = true;
1476 }1489 }
14771490
...@@ -1741,7 +1754,7 @@ pub const WipNav = struct {...@@ -1741,7 +1754,7 @@ pub const WipNav = struct {
1741 }1754 }
1742 };1755 };
17431756
1744 fn infoExprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void {1757 fn infoExprLoc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
1745 var counter: ExprLocCounter = .init(wip_nav.dwarf);1758 var counter: ExprLocCounter = .init(wip_nav.dwarf);
1746 try loc.write(&counter);1759 try loc.write(&counter);
17471760
...@@ -1773,7 +1786,7 @@ pub const WipNav = struct {...@@ -1773,7 +1786,7 @@ pub const WipNav = struct {
1773 try wip_nav.debug_info.appendNTimes(wip_nav.dwarf.gpa, 0, @intFromEnum(wip_nav.dwarf.address_size));1786 try wip_nav.debug_info.appendNTimes(wip_nav.dwarf.gpa, 0, @intFromEnum(wip_nav.dwarf.address_size));
1774 }1787 }
17751788
1776 fn frameExprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void {1789 fn frameExprLoc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
1777 var counter: ExprLocCounter = .init(wip_nav.dwarf);1790 var counter: ExprLocCounter = .init(wip_nav.dwarf);
1778 try loc.write(&counter);1791 try loc.write(&counter);
17791792
...@@ -2384,7 +2397,8 @@ fn initWipNavInner(...@@ -2384,7 +2397,8 @@ fn initWipNavInner(
2384 else => {},2397 else => {},
2385 }2398 }
23862399
2387 const unit = try dwarf.getUnit(file.mod.?);2400 const mod = file.mod.?;
2401 const unit = try dwarf.getUnit(mod);
2388 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);2402 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
2389 errdefer _ = if (!nav_gop.found_existing) dwarf.navs.pop();2403 errdefer _ = if (!nav_gop.found_existing) dwarf.navs.pop();
2390 if (nav_gop.found_existing) {2404 if (nav_gop.found_existing) {
...@@ -2425,13 +2439,13 @@ fn initWipNavInner(...@@ -2425,13 +2439,13 @@ fn initWipNavInner(
2425 }, &nav, inst_info.file, &decl);2439 }, &nav, inst_info.file, &decl);
2426 try wip_nav.strp(nav.fqn.toSlice(ip));2440 try wip_nav.strp(nav.fqn.toSlice(ip));
2427 const ty: Type = nav_val.typeOf(zcu);2441 const ty: Type = nav_val.typeOf(zcu);
2428 const addr: Loc = .{ .addr = .{ .sym = sym_index } };2442 const addr: Loc = .{ .addr_reloc = sym_index };
2429 const loc: Loc = if (decl.is_threadlocal) .{ .form_tls_address = &addr } else addr;2443 const loc: Loc = if (decl.is_threadlocal) .{ .form_tls_address = &addr } else addr;
2430 switch (decl.kind) {2444 switch (decl.kind) {
2431 .unnamed_test, .@"test", .decltest, .@"comptime", .@"usingnamespace" => unreachable,2445 .unnamed_test, .@"test", .decltest, .@"comptime", .@"usingnamespace" => unreachable,
2432 .@"const" => {2446 .@"const" => {
2433 const const_ty_reloc_index = try wip_nav.refForward();2447 const const_ty_reloc_index = try wip_nav.refForward();
2434 try wip_nav.infoExprloc(loc);2448 try wip_nav.infoExprLoc(loc);
2435 try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse2449 try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
2436 ty.abiAlignment(zcu).toByteUnits().?);2450 ty.abiAlignment(zcu).toByteUnits().?);
2437 try diw.writeByte(@intFromBool(decl.linkage != .normal));2451 try diw.writeByte(@intFromBool(decl.linkage != .normal));
...@@ -2441,7 +2455,7 @@ fn initWipNavInner(...@@ -2441,7 +2455,7 @@ fn initWipNavInner(
2441 },2455 },
2442 .@"var" => {2456 .@"var" => {
2443 try wip_nav.refType(ty);2457 try wip_nav.refType(ty);
2444 try wip_nav.infoExprloc(loc);2458 try wip_nav.infoExprLoc(loc);
2445 try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse2459 try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
2446 ty.abiAlignment(zcu).toByteUnits().?);2460 ty.abiAlignment(zcu).toByteUnits().?);
2447 try diw.writeByte(@intFromBool(decl.linkage != .normal));2461 try diw.writeByte(@intFromBool(decl.linkage != .normal));
...@@ -2512,7 +2526,7 @@ fn initWipNavInner(...@@ -2512,7 +2526,7 @@ fn initWipNavInner(
2512 try wip_nav.infoAddrSym(sym_index, 0);2526 try wip_nav.infoAddrSym(sym_index, 0);
2513 wip_nav.func_high_pc = @intCast(wip_nav.debug_info.items.len);2527 wip_nav.func_high_pc = @intCast(wip_nav.debug_info.items.len);
2514 try diw.writeInt(u32, 0, dwarf.endian);2528 try diw.writeInt(u32, 0, dwarf.endian);
2515 const target = file.mod.?.resolved_target.result;2529 const target = mod.resolved_target.result;
2516 try uleb128(diw, switch (nav.status.fully_resolved.alignment) {2530 try uleb128(diw, switch (nav.status.fully_resolved.alignment) {
2517 .none => target_info.defaultFunctionAlignment(target),2531 .none => target_info.defaultFunctionAlignment(target),
2518 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),2532 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
...@@ -3838,7 +3852,7 @@ fn updateLazyValue(...@@ -3838,7 +3852,7 @@ fn updateLazyValue(
3838 byte_offset += base_ptr.byte_offset;3852 byte_offset += base_ptr.byte_offset;
3839 };3853 };
3840 try wip_nav.abbrevCode(.location_comptime_value);3854 try wip_nav.abbrevCode(.location_comptime_value);
3841 try wip_nav.infoExprloc(.{ .implicit_pointer = .{3855 try wip_nav.infoExprLoc(.{ .implicit_pointer = .{
3842 .unit = base_unit,3856 .unit = base_unit,
3843 .entry = base_entry,3857 .entry = base_entry,
3844 .offset = byte_offset,3858 .offset = byte_offset,
...@@ -4360,7 +4374,7 @@ fn refAbbrevCode(dwarf: *Dwarf, abbrev_code: AbbrevCode) UpdateError!@typeInfo(A...@@ -4360,7 +4374,7 @@ fn refAbbrevCode(dwarf: *Dwarf, abbrev_code: AbbrevCode) UpdateError!@typeInfo(A
4360 assert(abbrev_code != .null);4374 assert(abbrev_code != .null);
4361 const entry: Entry.Index = @enumFromInt(@intFromEnum(abbrev_code));4375 const entry: Entry.Index = @enumFromInt(@intFromEnum(abbrev_code));
4362 if (dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).getEntry(entry).len > 0) return @intFromEnum(abbrev_code);4376 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);
4364 defer debug_abbrev.deinit();4378 defer debug_abbrev.deinit();
4365 const daw = debug_abbrev.writer();4379 const daw = debug_abbrev.writer();
4366 const abbrev = AbbrevCode.abbrevs.get(abbrev_code);4380 const abbrev = AbbrevCode.abbrevs.get(abbrev_code);
...@@ -4422,7 +4436,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {...@@ -4422,7 +4436,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
4422 mod_info.root_dir_path = try dwarf.debug_line_str.addString(dwarf, root_dir_path);4436 mod_info.root_dir_path = try dwarf.debug_line_str.addString(dwarf, root_dir_path);
4423 }4437 }
44244438
4425 var header = std.ArrayList(u8).init(dwarf.gpa);4439 var header: std.ArrayList(u8) = .init(dwarf.gpa);
4426 defer header.deinit();4440 defer header.deinit();
4427 if (dwarf.debug_aranges.section.dirty) {4441 if (dwarf.debug_aranges.section.dirty) {
4428 for (dwarf.debug_aranges.section.units.items, 0..) |*unit_ptr, unit_index| {4442 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 {...@@ -959,6 +959,12 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
959 self.rela_plt.clearRetainingCapacity();959 self.rela_plt.clearRetainingCapacity();
960960
961 if (self.zigObjectPtr()) |zo| {961 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
962 var has_reloc_errors = false;968 var has_reloc_errors = false;
963 for (zo.atoms_indexes.items) |atom_index| {969 for (zo.atoms_indexes.items) |atom_index| {
964 const atom_ptr = zo.atom(atom_index) orelse continue;970 const atom_ptr = zo.atom(atom_index) orelse continue;
...@@ -969,7 +975,10 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {...@@ -969,7 +975,10 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
969 const code = try zo.codeAlloc(self, atom_index);975 const code = try zo.codeAlloc(self, atom_index);
970 defer gpa.free(code);976 defer gpa.free(code);
971 const file_offset = atom_ptr.offset(self);977 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) {
973 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,982 error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
974 error.UnsupportedCpuArch => {983 error.UnsupportedCpuArch => {
975 try self.reportUnsupportedCpuArch();984 try self.reportUnsupportedCpuArch();
...@@ -980,6 +989,8 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {...@@ -980,6 +989,8 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
980 try self.pwriteAll(code, file_offset);989 try self.pwriteAll(code, file_offset);
981 }990 }
982991
992 try self.reportUndefinedSymbols(&undefs);
993
983 if (has_reloc_errors) return error.LinkFailure;994 if (has_reloc_errors) return error.LinkFailure;
984 }995 }
985996
...@@ -1392,11 +1403,9 @@ fn scanRelocs(self: *Elf) !void {...@@ -1392,11 +1403,9 @@ fn scanRelocs(self: *Elf) !void {
1392 const gpa = self.base.comp.gpa;1403 const gpa = self.base.comp.gpa;
1393 const shared_objects = self.shared_objects.values();1404 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);
1396 defer {1407 defer {
1397 for (undefs.values()) |*refs| {1408 for (undefs.values()) |*refs| refs.deinit();
1398 refs.deinit();
1399 }
1400 undefs.deinit();1409 undefs.deinit();
1401 }1410 }
14021411
...@@ -2702,15 +2711,16 @@ fn initSyntheticSections(self: *Elf) !void {...@@ -2702,15 +2711,16 @@ fn initSyntheticSections(self: *Elf) !void {
2702 });2711 });
2703 }2712 }
27042713
2705 const needs_interp = blk: {2714 const is_exe_or_dyn_lib = switch (comp.config.output_mode) {
2706 // On Ubuntu with musl-gcc, we get a weird combo of options looking like this:2715 .Exe => true,
2707 // -dynamic-linker=<path> -static2716 .Lib => comp.config.link_mode == .dynamic,
2708 // In this case, if we do generate .interp section and segment, we will get2717 .Obj => false,
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;
2713 };2718 };
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
2714 if (needs_interp and self.section_indexes.interp == null) {2724 if (needs_interp and self.section_indexes.interp == null) {
2715 self.section_indexes.interp = try self.addSection(.{2725 self.section_indexes.interp = try self.addSection(.{
2716 .name = try self.insertShString(".interp"),2726 .name = try self.insertShString(".interp"),
...@@ -3707,11 +3717,9 @@ fn allocateSpecialPhdrs(self: *Elf) void {...@@ -3707,11 +3717,9 @@ fn allocateSpecialPhdrs(self: *Elf) void {
3707fn writeAtoms(self: *Elf) !void {3717fn writeAtoms(self: *Elf) !void {
3708 const gpa = self.base.comp.gpa;3718 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);
3711 defer {3721 defer {
3712 for (undefs.values()) |*refs| {3722 for (undefs.values()) |*refs| refs.deinit();
3713 refs.deinit();
3714 }
3715 undefs.deinit();3723 undefs.deinit();
3716 }3724 }
37173725
src/link/Elf/Atom.zig+3-3
...@@ -497,14 +497,14 @@ fn dynAbsRelocAction(symbol: *const Symbol, elf_file: *Elf) RelocAction {...@@ -497,14 +497,14 @@ fn dynAbsRelocAction(symbol: *const Symbol, elf_file: *Elf) RelocAction {
497}497}
498498
499fn outputType(elf_file: *Elf) u2 {499fn outputType(elf_file: *Elf) u2 {
500 const comp = elf_file.base.comp;
501 assert(!elf_file.base.isRelocatable());500 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) {
503 .Obj => unreachable,503 .Obj => unreachable,
504 .Lib => 0,504 .Lib => 0,
505 .Exe => switch (elf_file.getTarget().os.tag) {505 .Exe => switch (elf_file.getTarget().os.tag) {
506 .haiku => 0,506 .haiku => 0,
507 else => if (comp.config.pie) 1 else 2,507 else => if (config.pie) 1 else 2,
508 },508 },
509 };509 };
510}510}
src/link/Elf/ZigObject.zig+1
...@@ -657,6 +657,7 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {...@@ -657,6 +657,7 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
657 const atom_ptr = self.atom(atom_index) orelse continue;657 const atom_ptr = self.atom(atom_index) orelse continue;
658 if (!atom_ptr.alive) continue;658 if (!atom_ptr.alive) continue;
659 const shdr = atom_ptr.inputShdr(elf_file);659 const shdr = atom_ptr.inputShdr(elf_file);
660 if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
660 if (shdr.sh_type == elf.SHT_NOBITS) continue;661 if (shdr.sh_type == elf.SHT_NOBITS) continue;
661 if (atom_ptr.scanRelocsRequiresCode(elf_file)) {662 if (atom_ptr.scanRelocsRequiresCode(elf_file)) {
662 // TODO ideally we don't have to fetch the code here.663 // 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) {...@@ -2376,7 +2376,7 @@ pub const FunctionImportId = enum(u32) {
2376 const zcu = wasm.base.comp.zcu.?;2376 const zcu = wasm.base.comp.zcu.?;
2377 const ip = &zcu.intern_pool;2377 const ip = &zcu.intern_pool;
2378 const ext = ip.getNav(i.ptr(wasm).*).getResolvedExtern(ip).?;2378 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;
2380 },2380 },
2381 };2381 };
2382 }2382 }
src/main.zig+2-2
...@@ -39,7 +39,7 @@ test {...@@ -39,7 +39,7 @@ test {
39 _ = Package;39 _ = Package;
40}40}
4141
42const thread_stack_size = 50 << 20;42const thread_stack_size = 60 << 20;
4343
44pub const std_options: std.Options = .{44pub const std_options: std.Options = .{
45 .wasiCwd = wasi_cwd,45 .wasiCwd = wasi_cwd,
...@@ -4208,7 +4208,7 @@ fn serve(...@@ -4208,7 +4208,7 @@ fn serve(
4208 const main_progress_node = std.Progress.start(.{});4208 const main_progress_node = std.Progress.start(.{});
4209 const file_system_inputs = comp.file_system_inputs.?;4209 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)
4212 @import("IncrementalDebugServer.zig")4212 @import("IncrementalDebugServer.zig")
4213 else4213 else
4214 void;4214 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 {...@@ -223,6 +223,10 @@ pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool {
223/// than or equal to the number of behavior tests as the respective LLVM backend.223/// than or equal to the number of behavior tests as the respective LLVM backend.
224pub fn selfHostedBackendIsAsRobustAsLlvm(target: std.Target) bool {224pub fn selfHostedBackendIsAsRobustAsLlvm(target: std.Target) bool {
225 if (target.cpu.arch.isSpirV()) return true;225 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 };
226 return false;230 return false;
227}231}
228232
test/behavior/math.zig+1
...@@ -1722,6 +1722,7 @@ test "signed zeros are represented properly" {...@@ -1722,6 +1722,7 @@ test "signed zeros are represented properly" {
1722 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO1722 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1723 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;1723 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
1724 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;1724 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
1726 const S = struct {1727 const S = struct {
1727 fn doTheTest() !void {1728 fn doTheTest() !void {
test/behavior/switch.zig+9
...@@ -1056,3 +1056,12 @@ test "unlabeled break ignores switch" {...@@ -1056,3 +1056,12 @@ test "unlabeled break ignores switch" {
1056 };1056 };
1057 try expect(result == 123);1057 try expect(result == 123);
1058}1058}
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 {...@@ -117,9 +117,9 @@ export fn testMutablePointer() void {
117// tmp.zig:37:38: note: imported here117// tmp.zig:37:38: note: imported here
118// neg_inf.zon:1:1: error: expected type '?u8'118// neg_inf.zon:1:1: error: expected type '?u8'
119// tmp.zig:57:28: note: imported here119// 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'
121// tmp.zig:62:39: note: imported here121// 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'
123// tmp.zig:67:44: note: imported here123// 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'
125// tmp.zig:72:50: note: imported here125// 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 {...@@ -15,6 +15,6 @@ pub export fn entry() void {
15// error15// error
16//16//
17// :7:25: error: unable to resolve comptime value17// :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-known18// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_499.C' must be comptime-known
19// :4:16: note: struct requires comptime because of this field19// :4:16: note: struct requires comptime because of this field
20// :4:16: note: types are not available at runtime20// :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 {...@@ -16,5 +16,5 @@ pub export fn entry2() void {
16//16//
17// :3:6: error: no field or member function named 'copy' in '[]const u8'17// :3:6: error: no field or member function named 'copy' in '[]const u8'
18// :9:8: error: no field or member function named 'bar' in '@TypeOf(.{})'18// :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'
20// :12:6: note: struct declared here20// :12:6: note: struct declared here
test/cases/compile_errors/coerce_anon_struct.zig+1-1
...@@ -6,6 +6,6 @@ export fn foo() void {...@@ -6,6 +6,6 @@ export fn foo() void {
66
7// error7// error
8//8//
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'
10// :3:16: note: struct declared here10// :3:16: note: struct declared here
11// :1:11: note: struct declared here11// :1:11: note: struct declared here
test/cases/compile_errors/redundant_try.zig+2-2
...@@ -44,9 +44,9 @@ comptime {...@@ -44,9 +44,9 @@ comptime {
44//44//
45// :5:23: error: expected error union type, found 'comptime_int'45// :5:23: error: expected error union type, found 'comptime_int'
46// :10:23: error: expected error union type, found '@TypeOf(.{})'46// :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'
48// :15:23: note: struct declared here48// :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'
50// :20:27: note: struct declared here50// :20:27: note: struct declared here
51// :25:23: error: expected error union type, found 'struct { comptime *const [5:0]u8 = "hello" }'51// :25:23: error: expected error union type, found 'struct { comptime *const [5:0]u8 = "hello" }'
52// :31:13: error: expected error union type, found 'u32'52// :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;...@@ -6,8 +6,9 @@ var buffer: [0x1000000]u64 = [1]u64{0} ** 0x1000000;
6pub fn main() anyerror!void {6pub fn main() anyerror!void {
7 buffer[0x10] = 1;7 buffer[0x10] = 1;
8 try std.io.getStdOut().writer().print("{d}, {d}, {d}\n", .{8 try std.io.getStdOut().writer().print("{d}, {d}, {d}\n", .{
9 buffer[0],9 // workaround the dreaded decl_val
10 buffer[0x10],10 (&buffer)[0],
11 buffer[0x1000000 - 1],11 (&buffer)[0x10],
12 (&buffer)[0x1000000 - 1],
12 });13 });
13}14}
test/src/Debugger.zig-1
...@@ -9,7 +9,6 @@ pub const Options = struct {...@@ -9,7 +9,6 @@ pub const Options = struct {
9 lldb: ?[]const u8,9 lldb: ?[]const u8,
10 optimize_modes: []const std.builtin.OptimizeMode,10 optimize_modes: []const std.builtin.OptimizeMode,
11 skip_single_threaded: bool,11 skip_single_threaded: bool,
12 skip_non_native: bool,
13 skip_libc: bool,12 skip_libc: bool,
14};13};
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...@@ -24,6 +24,8 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
24 .optimize = optimize,24 .optimize = optimize,
25 .link_libc = true,25 .link_libc = true,
26 }),26 }),
27 // extern threadlocals are not implemented in the self-hosted linker
28 .use_llvm = true,
27 });29 });
28 exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &[_][]const u8{"-std=c11"} });30 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 {...@@ -52,6 +52,8 @@ pub fn build(b: *std.Build) void {
52 .unwind_tables = .@"async",52 .unwind_tables = .@"async",
53 .omit_frame_pointer = true,53 .omit_frame_pointer = true,
54 }),54 }),
55 // self-hosted lacks omit_frame_pointer support
56 .use_llvm = true,
55 });57 });
5658
57 const run_cmd = b.addRunArtifact(exe);59 const run_cmd = b.addRunArtifact(exe);
...@@ -97,6 +99,8 @@ pub fn build(b: *std.Build) void {...@@ -97,6 +99,8 @@ pub fn build(b: *std.Build) void {
97 .unwind_tables = if (target.result.os.tag.isDarwin()) .@"async" else null,99 .unwind_tables = if (target.result.os.tag.isDarwin()) .@"async" else null,
98 .omit_frame_pointer = true,100 .omit_frame_pointer = true,
99 }),101 }),
102 // zig objcopy doesn't support incremental binaries
103 .use_llvm = true,
100 });104 });
101105
102 exe.linkLibrary(c_shared_lib);106 exe.linkLibrary(c_shared_lib);
...@@ -137,6 +141,8 @@ pub fn build(b: *std.Build) void {...@@ -137,6 +141,8 @@ pub fn build(b: *std.Build) void {
137 .unwind_tables = null,141 .unwind_tables = null,
138 .omit_frame_pointer = false,142 .omit_frame_pointer = false,
139 }),143 }),
144 // self-hosted lacks omit_frame_pointer support
145 .use_llvm = true,
140 });146 });
141147
142 // This "freestanding" binary is runnable because it invokes the148 // This "freestanding" binary is runnable because it invokes the
test/tests.zig+52-15
...@@ -1113,8 +1113,6 @@ const test_targets = blk: {...@@ -1113,8 +1113,6 @@ const test_targets = blk: {
1113 .os_tag = .linux,1113 .os_tag = .linux,
1114 .abi = .none,1114 .abi = .none,
1115 },1115 },
1116 .use_llvm = false,
1117 .use_lld = false,
1118 },1116 },
1119 .{1117 .{
1120 .target = .{1118 .target = .{
...@@ -1123,8 +1121,6 @@ const test_targets = blk: {...@@ -1123,8 +1121,6 @@ const test_targets = blk: {
1123 .os_tag = .linux,1121 .os_tag = .linux,
1124 .abi = .none,1122 .abi = .none,
1125 },1123 },
1126 .use_llvm = false,
1127 .use_lld = false,
1128 .pic = true,1124 .pic = true,
1129 },1125 },
1130 .{1126 .{
...@@ -1134,8 +1130,6 @@ const test_targets = blk: {...@@ -1134,8 +1130,6 @@ const test_targets = blk: {
1134 .os_tag = .linux,1130 .os_tag = .linux,
1135 .abi = .none,1131 .abi = .none,
1136 },1132 },
1137 .use_llvm = false,
1138 .use_lld = false,
1139 .strip = true,1133 .strip = true,
1140 },1134 },
1141 .{1135 .{
...@@ -1144,6 +1138,8 @@ const test_targets = blk: {...@@ -1144,6 +1138,8 @@ const test_targets = blk: {
1144 .os_tag = .linux,1138 .os_tag = .linux,
1145 .abi = .none,1139 .abi = .none,
1146 },1140 },
1141 .use_llvm = true,
1142 .use_lld = true,
1147 },1143 },
1148 .{1144 .{
1149 .target = .{1145 .target = .{
...@@ -1602,7 +1598,9 @@ const c_abi_targets = blk: {...@@ -1602,7 +1598,9 @@ const c_abi_targets = blk: {
1602 break :blk [_]CAbiTarget{1598 break :blk [_]CAbiTarget{
1603 // Native Targets1599 // Native Targets
16041600
1605 .{},1601 .{
1602 .use_llvm = true,
1603 },
16061604
1607 // Linux Targets1605 // Linux Targets
16081606
...@@ -1841,7 +1839,6 @@ const c_abi_targets = blk: {...@@ -1841,7 +1839,6 @@ const c_abi_targets = blk: {
1841 .abi = .musl,1839 .abi = .musl,
1842 },1840 },
1843 .use_llvm = false,1841 .use_llvm = false,
1844 .use_lld = false,
1845 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},1842 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
1846 },1843 },
1847 .{1844 .{
...@@ -1852,7 +1849,6 @@ const c_abi_targets = blk: {...@@ -1852,7 +1849,6 @@ const c_abi_targets = blk: {
1852 .abi = .musl,1849 .abi = .musl,
1853 },1850 },
1854 .use_llvm = false,1851 .use_llvm = false,
1855 .use_lld = false,
1856 .strip = true,1852 .strip = true,
1857 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},1853 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
1858 },1854 },
...@@ -1864,7 +1860,6 @@ const c_abi_targets = blk: {...@@ -1864,7 +1860,6 @@ const c_abi_targets = blk: {
1864 .abi = .musl,1860 .abi = .musl,
1865 },1861 },
1866 .use_llvm = false,1862 .use_llvm = false,
1867 .use_lld = false,
1868 .pic = true,1863 .pic = true,
1869 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},1864 .c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
1870 },1865 },
...@@ -1874,6 +1869,7 @@ const c_abi_targets = blk: {...@@ -1874,6 +1869,7 @@ const c_abi_targets = blk: {
1874 .os_tag = .linux,1869 .os_tag = .linux,
1875 .abi = .musl,1870 .abi = .musl,
1876 },1871 },
1872 .use_llvm = true,
1877 },1873 },
1878 .{1874 .{
1879 .target = .{1875 .target = .{
...@@ -1881,6 +1877,7 @@ const c_abi_targets = blk: {...@@ -1881,6 +1877,7 @@ const c_abi_targets = blk: {
1881 .os_tag = .linux,1877 .os_tag = .linux,
1882 .abi = .muslx32,1878 .abi = .muslx32,
1883 },1879 },
1880 .use_llvm = true,
1884 },1881 },
18851882
1886 // WASI Targets1883 // WASI Targets
...@@ -2276,8 +2273,13 @@ const ModuleTestOptions = struct {...@@ -2276,8 +2273,13 @@ const ModuleTestOptions = struct {
2276 include_paths: []const []const u8,2273 include_paths: []const []const u8,
2277 skip_single_threaded: bool,2274 skip_single_threaded: bool,
2278 skip_non_native: bool,2275 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,
2279 skip_libc: bool,2282 skip_libc: bool,
2280 use_llvm: ?bool = null,
2281 max_rss: usize = 0,2283 max_rss: usize = 0,
2282 no_builtin: bool = false,2284 no_builtin: bool = false,
2283 build_options: ?*std.Build.Step.Options = null,2285 build_options: ?*std.Build.Step.Options = null,
...@@ -2298,6 +2300,15 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {...@@ -2298,6 +2300,15 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
2298 if (options.skip_non_native and !test_target.target.isNative())2300 if (options.skip_non_native and !test_target.target.isNative())
2299 continue;2301 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
2301 const resolved_target = b.resolveTargetQuery(test_target.target);2312 const resolved_target = b.resolveTargetQuery(test_target.target);
2302 const target = resolved_target.result;2313 const target = resolved_target.result;
2303 const triple_txt = target.zigTriple(b.allocator) catch @panic("OOM");2314 const triple_txt = target.zigTriple(b.allocator) catch @panic("OOM");
...@@ -2318,10 +2329,6 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {...@@ -2318,10 +2329,6 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
2318 if (options.skip_single_threaded and test_target.single_threaded == true)2329 if (options.skip_single_threaded and test_target.single_threaded == true)
2319 continue;2330 continue;
23202331
2321 if (options.use_llvm) |use_llvm| {
2322 if (test_target.use_llvm != use_llvm) continue;
2323 }
2324
2325 // TODO get compiler-rt tests passing for self-hosted backends.2332 // TODO get compiler-rt tests passing for self-hosted backends.
2326 if ((target.cpu.arch != .x86_64 or target.ofmt != .elf) and2333 if ((target.cpu.arch != .x86_64 or target.ofmt != .elf) and
2327 test_target.use_llvm == false and mem.eql(u8, options.name, "compiler-rt"))2334 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 {...@@ -2501,9 +2508,31 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
2501 return step;2508 return step;
2502}2509}
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
2504const CAbiTestOptions = struct {2527const CAbiTestOptions = struct {
2505 test_target_filters: []const []const u8,2528 test_target_filters: []const []const u8,
2506 skip_non_native: bool,2529 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,
2507 skip_release: bool,2536 skip_release: bool,
2508};2537};
25092538
...@@ -2517,6 +2546,14 @@ pub fn addCAbiTests(b: *std.Build, options: CAbiTestOptions) *Step {...@@ -2517,6 +2546,14 @@ pub fn addCAbiTests(b: *std.Build, options: CAbiTestOptions) *Step {
25172546
2518 for (c_abi_targets) |c_abi_target| {2547 for (c_abi_targets) |c_abi_target| {
2519 if (options.skip_non_native and !c_abi_target.target.isNative()) continue;2548 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
2521 const resolved_target = b.resolveTargetQuery(c_abi_target.target);2558 const resolved_target = b.resolveTargetQuery(c_abi_target.target);
2522 const target = resolved_target.result;2559 const target = resolved_target.result;
tools/doctest.zig+44-1
...@@ -168,6 +168,15 @@ fn printOutput(...@@ -168,6 +168,15 @@ fn printOutput(
168 try build_args.appendSlice(&[_][]const u8{ "-target", triple });168 try build_args.appendSlice(&[_][]const u8{ "-target", triple });
169 try shell_out.print("-target {s} ", .{triple});169 try shell_out.print("-target {s} ", .{triple});
170 }170 }
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 }
171 if (code.verbose_cimport) {180 if (code.verbose_cimport) {
172 try build_args.append("--verbose-cimport");181 try build_args.append("--verbose-cimport");
173 try shell_out.print("--verbose-cimport ", .{});182 try shell_out.print("--verbose-cimport ", .{});
...@@ -224,7 +233,6 @@ fn printOutput(...@@ -224,7 +233,6 @@ fn printOutput(
224 break :code_block;233 break :code_block;
225 }234 }
226 }235 }
227
228 const target_query = try std.Target.Query.parse(.{236 const target_query = try std.Target.Query.parse(.{
229 .arch_os_abi = code.target_str orelse "native",237 .arch_os_abi = code.target_str orelse "native",
230 });238 });
...@@ -319,6 +327,16 @@ fn printOutput(...@@ -319,6 +327,16 @@ fn printOutput(
319 },327 },
320 }328 }
321 }329 }
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
322 const result = run(arena, &env_map, tmp_dir_path, test_args.items) catch340 const result = run(arena, &env_map, tmp_dir_path, test_args.items) catch
323 fatal("test failed", .{});341 fatal("test failed", .{});
324 const escaped_stderr = try escapeHtml(arena, result.stderr);342 const escaped_stderr = try escapeHtml(arena, result.stderr);
...@@ -469,6 +487,15 @@ fn printOutput(...@@ -469,6 +487,15 @@ fn printOutput(
469 try build_args.appendSlice(&[_][]const u8{ "-target", triple });487 try build_args.appendSlice(&[_][]const u8{ "-target", triple });
470 try shell_out.print("-target {s} ", .{triple});488 try shell_out.print("-target {s} ", .{triple});
471 }489 }
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 }
472 for (code.additional_options) |option| {499 for (code.additional_options) |option| {
473 try build_args.append(option);500 try build_args.append(option);
474 try shell_out.print("{s} ", .{option});501 try shell_out.print("{s} ", .{option});
...@@ -538,6 +565,15 @@ fn printOutput(...@@ -538,6 +565,15 @@ fn printOutput(
538 try test_args.appendSlice(&[_][]const u8{ "-target", triple });565 try test_args.appendSlice(&[_][]const u8{ "-target", triple });
539 try shell_out.print("-target {s} ", .{triple});566 try shell_out.print("-target {s} ", .{triple});
540 }567 }
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 }
541 if (code.link_mode) |link_mode| {577 if (code.link_mode) |link_mode| {
542 switch (link_mode) {578 switch (link_mode) {
543 .static => {579 .static => {
...@@ -827,6 +863,7 @@ const Code = struct {...@@ -827,6 +863,7 @@ const Code = struct {
827 verbose_cimport: bool,863 verbose_cimport: bool,
828 just_check_syntax: bool,864 just_check_syntax: bool,
829 additional_options: []const []const u8,865 additional_options: []const []const u8,
866 use_llvm: ?bool,
830867
831 const Id = union(enum) {868 const Id = union(enum) {
832 @"test",869 @"test",
...@@ -886,6 +923,7 @@ fn parseManifest(arena: Allocator, source_bytes: []const u8) !Code {...@@ -886,6 +923,7 @@ fn parseManifest(arena: Allocator, source_bytes: []const u8) !Code {
886 var link_libc = false;923 var link_libc = false;
887 var disable_cache = false;924 var disable_cache = false;
888 var verbose_cimport = false;925 var verbose_cimport = false;
926 var use_llvm: ?bool = null;
889927
890 while (it.next()) |prefixed_line| {928 while (it.next()) |prefixed_line| {
891 const line = skipPrefix(prefixed_line);929 const line = skipPrefix(prefixed_line);
...@@ -901,6 +939,10 @@ fn parseManifest(arena: Allocator, source_bytes: []const u8) !Code {...@@ -901,6 +939,10 @@ fn parseManifest(arena: Allocator, source_bytes: []const u8) !Code {
901 try additional_options.append(arena, line["additional_option=".len..]);939 try additional_options.append(arena, line["additional_option=".len..]);
902 } else if (mem.startsWith(u8, line, "target=")) {940 } else if (mem.startsWith(u8, line, "target=")) {
903 target_str = line["target=".len..];941 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;
904 } else if (mem.eql(u8, line, "link_libc")) {946 } else if (mem.eql(u8, line, "link_libc")) {
905 link_libc = true;947 link_libc = true;
906 } else if (mem.eql(u8, line, "disable_cache")) {948 } else if (mem.eql(u8, line, "disable_cache")) {
...@@ -923,6 +965,7 @@ fn parseManifest(arena: Allocator, source_bytes: []const u8) !Code {...@@ -923,6 +965,7 @@ fn parseManifest(arena: Allocator, source_bytes: []const u8) !Code {
923 .disable_cache = disable_cache,965 .disable_cache = disable_cache,
924 .verbose_cimport = verbose_cimport,966 .verbose_cimport = verbose_cimport,
925 .just_check_syntax = just_check_syntax,967 .just_check_syntax = just_check_syntax,
968 .use_llvm = use_llvm,
926 };969 };
927}970}
928971