mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
Merge pull request #24072 from jacobly0/x86_64-default
Compilation: enable the x86_64 backend by default for debug builds
This commit is contained in:
commit
8b875b17ad
8
.github/workflows/ci.yaml
vendored
8
.github/workflows/ci.yaml
vendored
@ -20,6 +20,14 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Build and Test
|
- name: Build and Test
|
||||||
run: sh ci/x86_64-linux-debug.sh
|
run: sh ci/x86_64-linux-debug.sh
|
||||||
|
x86_64-linux-debug-llvm:
|
||||||
|
timeout-minutes: 540
|
||||||
|
runs-on: [self-hosted, Linux, x86_64]
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Build and Test
|
||||||
|
run: sh ci/x86_64-linux-debug-llvm.sh
|
||||||
x86_64-linux-release:
|
x86_64-linux-release:
|
||||||
timeout-minutes: 540
|
timeout-minutes: 540
|
||||||
runs-on: [self-hosted, Linux, x86_64]
|
runs-on: [self-hosted, Linux, x86_64]
|
||||||
|
|||||||
@ -519,6 +519,7 @@ set(ZIG_STAGE2_SOURCES
|
|||||||
src/Air/Legalize.zig
|
src/Air/Legalize.zig
|
||||||
src/Air/Liveness.zig
|
src/Air/Liveness.zig
|
||||||
src/Air/Liveness/Verify.zig
|
src/Air/Liveness/Verify.zig
|
||||||
|
src/Air/print.zig
|
||||||
src/Air/types_resolved.zig
|
src/Air/types_resolved.zig
|
||||||
src/Builtin.zig
|
src/Builtin.zig
|
||||||
src/Compilation.zig
|
src/Compilation.zig
|
||||||
@ -675,7 +676,6 @@ set(ZIG_STAGE2_SOURCES
|
|||||||
src/libs/mingw.zig
|
src/libs/mingw.zig
|
||||||
src/libs/musl.zig
|
src/libs/musl.zig
|
||||||
src/mutable_value.zig
|
src/mutable_value.zig
|
||||||
src/print_air.zig
|
|
||||||
src/print_env.zig
|
src/print_env.zig
|
||||||
src/print_targets.zig
|
src/print_targets.zig
|
||||||
src/print_value.zig
|
src/print_value.zig
|
||||||
|
|||||||
52
build.zig
52
build.zig
@ -92,6 +92,12 @@ pub fn build(b: *std.Build) !void {
|
|||||||
const skip_single_threaded = b.option(bool, "skip-single-threaded", "Main test suite skips tests that are single-threaded") orelse false;
|
const skip_single_threaded = b.option(bool, "skip-single-threaded", "Main test suite skips tests that are single-threaded") orelse false;
|
||||||
const skip_translate_c = b.option(bool, "skip-translate-c", "Main test suite skips translate-c tests") orelse false;
|
const skip_translate_c = b.option(bool, "skip-translate-c", "Main test suite skips translate-c tests") orelse false;
|
||||||
const skip_run_translated_c = b.option(bool, "skip-run-translated-c", "Main test suite skips run-translated-c tests") orelse false;
|
const skip_run_translated_c = b.option(bool, "skip-run-translated-c", "Main test suite skips run-translated-c tests") orelse false;
|
||||||
|
const skip_freebsd = b.option(bool, "skip-freebsd", "Main test suite skips targets with freebsd OS") orelse false;
|
||||||
|
const skip_netbsd = b.option(bool, "skip-netbsd", "Main test suite skips targets with netbsd OS") orelse false;
|
||||||
|
const skip_windows = b.option(bool, "skip-windows", "Main test suite skips targets with windows OS") orelse false;
|
||||||
|
const skip_macos = b.option(bool, "skip-macos", "Main test suite skips targets with macos OS") orelse false;
|
||||||
|
const skip_linux = b.option(bool, "skip-linux", "Main test suite skips targets with linux OS") orelse false;
|
||||||
|
const skip_llvm = b.option(bool, "skip-llvm", "Main test suite skips targets that use LLVM backend") orelse false;
|
||||||
|
|
||||||
const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false;
|
const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false;
|
||||||
|
|
||||||
@ -435,10 +441,15 @@ pub fn build(b: *std.Build) !void {
|
|||||||
.include_paths = &.{},
|
.include_paths = &.{},
|
||||||
.skip_single_threaded = skip_single_threaded,
|
.skip_single_threaded = skip_single_threaded,
|
||||||
.skip_non_native = skip_non_native,
|
.skip_non_native = skip_non_native,
|
||||||
|
.skip_freebsd = skip_freebsd,
|
||||||
|
.skip_netbsd = skip_netbsd,
|
||||||
|
.skip_windows = skip_windows,
|
||||||
|
.skip_macos = skip_macos,
|
||||||
|
.skip_linux = skip_linux,
|
||||||
|
.skip_llvm = skip_llvm,
|
||||||
.skip_libc = skip_libc,
|
.skip_libc = skip_libc,
|
||||||
.use_llvm = use_llvm,
|
// 2923515904 was observed on an x86_64-linux-gnu host.
|
||||||
// 2520100864 was observed on an x86_64-linux-gnu host.
|
.max_rss = 3100000000,
|
||||||
.max_rss = 2772110950,
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
test_modules_step.dependOn(tests.addModuleTests(b, .{
|
test_modules_step.dependOn(tests.addModuleTests(b, .{
|
||||||
@ -452,8 +463,13 @@ pub fn build(b: *std.Build) !void {
|
|||||||
.include_paths = &.{"test/c_import"},
|
.include_paths = &.{"test/c_import"},
|
||||||
.skip_single_threaded = true,
|
.skip_single_threaded = true,
|
||||||
.skip_non_native = skip_non_native,
|
.skip_non_native = skip_non_native,
|
||||||
|
.skip_freebsd = skip_freebsd,
|
||||||
|
.skip_netbsd = skip_netbsd,
|
||||||
|
.skip_windows = skip_windows,
|
||||||
|
.skip_macos = skip_macos,
|
||||||
|
.skip_linux = skip_linux,
|
||||||
|
.skip_llvm = skip_llvm,
|
||||||
.skip_libc = skip_libc,
|
.skip_libc = skip_libc,
|
||||||
.use_llvm = use_llvm,
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
test_modules_step.dependOn(tests.addModuleTests(b, .{
|
test_modules_step.dependOn(tests.addModuleTests(b, .{
|
||||||
@ -467,8 +483,13 @@ pub fn build(b: *std.Build) !void {
|
|||||||
.include_paths = &.{},
|
.include_paths = &.{},
|
||||||
.skip_single_threaded = true,
|
.skip_single_threaded = true,
|
||||||
.skip_non_native = skip_non_native,
|
.skip_non_native = skip_non_native,
|
||||||
|
.skip_freebsd = skip_freebsd,
|
||||||
|
.skip_netbsd = skip_netbsd,
|
||||||
|
.skip_windows = skip_windows,
|
||||||
|
.skip_macos = skip_macos,
|
||||||
|
.skip_linux = skip_linux,
|
||||||
|
.skip_llvm = skip_llvm,
|
||||||
.skip_libc = true,
|
.skip_libc = true,
|
||||||
.use_llvm = use_llvm,
|
|
||||||
.no_builtin = true,
|
.no_builtin = true,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -483,8 +504,13 @@ pub fn build(b: *std.Build) !void {
|
|||||||
.include_paths = &.{},
|
.include_paths = &.{},
|
||||||
.skip_single_threaded = true,
|
.skip_single_threaded = true,
|
||||||
.skip_non_native = skip_non_native,
|
.skip_non_native = skip_non_native,
|
||||||
|
.skip_freebsd = skip_freebsd,
|
||||||
|
.skip_netbsd = skip_netbsd,
|
||||||
|
.skip_windows = skip_windows,
|
||||||
|
.skip_macos = skip_macos,
|
||||||
|
.skip_linux = skip_linux,
|
||||||
|
.skip_llvm = skip_llvm,
|
||||||
.skip_libc = true,
|
.skip_libc = true,
|
||||||
.use_llvm = use_llvm,
|
|
||||||
.no_builtin = true,
|
.no_builtin = true,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -499,8 +525,13 @@ pub fn build(b: *std.Build) !void {
|
|||||||
.include_paths = &.{},
|
.include_paths = &.{},
|
||||||
.skip_single_threaded = skip_single_threaded,
|
.skip_single_threaded = skip_single_threaded,
|
||||||
.skip_non_native = skip_non_native,
|
.skip_non_native = skip_non_native,
|
||||||
|
.skip_freebsd = skip_freebsd,
|
||||||
|
.skip_netbsd = skip_netbsd,
|
||||||
|
.skip_windows = skip_windows,
|
||||||
|
.skip_macos = skip_macos,
|
||||||
|
.skip_linux = skip_linux,
|
||||||
|
.skip_llvm = skip_llvm,
|
||||||
.skip_libc = skip_libc,
|
.skip_libc = skip_libc,
|
||||||
.use_llvm = use_llvm,
|
|
||||||
// I observed a value of 5605064704 on the M2 CI.
|
// I observed a value of 5605064704 on the M2 CI.
|
||||||
.max_rss = 6165571174,
|
.max_rss = 6165571174,
|
||||||
}));
|
}));
|
||||||
@ -536,6 +567,12 @@ pub fn build(b: *std.Build) !void {
|
|||||||
test_step.dependOn(tests.addCAbiTests(b, .{
|
test_step.dependOn(tests.addCAbiTests(b, .{
|
||||||
.test_target_filters = test_target_filters,
|
.test_target_filters = test_target_filters,
|
||||||
.skip_non_native = skip_non_native,
|
.skip_non_native = skip_non_native,
|
||||||
|
.skip_freebsd = skip_freebsd,
|
||||||
|
.skip_netbsd = skip_netbsd,
|
||||||
|
.skip_windows = skip_windows,
|
||||||
|
.skip_macos = skip_macos,
|
||||||
|
.skip_linux = skip_linux,
|
||||||
|
.skip_llvm = skip_llvm,
|
||||||
.skip_release = skip_release,
|
.skip_release = skip_release,
|
||||||
}));
|
}));
|
||||||
test_step.dependOn(tests.addLinkTests(b, enable_macos_sdk, enable_ios_sdk, enable_symlinks_windows));
|
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 {
|
|||||||
.lldb = b.option([]const u8, "lldb", "path to lldb binary"),
|
.lldb = b.option([]const u8, "lldb", "path to lldb binary"),
|
||||||
.optimize_modes = optimization_modes,
|
.optimize_modes = optimization_modes,
|
||||||
.skip_single_threaded = skip_single_threaded,
|
.skip_single_threaded = skip_single_threaded,
|
||||||
.skip_non_native = skip_non_native,
|
|
||||||
.skip_libc = skip_libc,
|
.skip_libc = skip_libc,
|
||||||
})) |test_debugger_step| test_step.dependOn(test_debugger_step);
|
})) |test_debugger_step| test_step.dependOn(test_debugger_step);
|
||||||
if (tests.addLlvmIrTests(b, .{
|
if (tests.addLlvmIrTests(b, .{
|
||||||
|
|||||||
70
ci/x86_64-linux-debug-llvm.sh
Normal file
70
ci/x86_64-linux-debug-llvm.sh
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Requires cmake ninja-build
|
||||||
|
|
||||||
|
set -x
|
||||||
|
set -e
|
||||||
|
|
||||||
|
ARCH="$(uname -m)"
|
||||||
|
TARGET="$ARCH-linux-musl"
|
||||||
|
MCPU="baseline"
|
||||||
|
CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.15.0-dev.233+7c85dc460"
|
||||||
|
PREFIX="$HOME/deps/$CACHE_BASENAME"
|
||||||
|
ZIG="$PREFIX/bin/zig"
|
||||||
|
|
||||||
|
export PATH="$HOME/deps/wasmtime-v29.0.0-$ARCH-linux:$HOME/deps/qemu-linux-x86_64-9.2.0-rc1/bin:$HOME/local/bin:$PATH"
|
||||||
|
|
||||||
|
# Make the `zig version` number consistent.
|
||||||
|
# This will affect the cmake command below.
|
||||||
|
git fetch --unshallow || true
|
||||||
|
git fetch --tags
|
||||||
|
|
||||||
|
# Override the cache directories because they won't actually help other CI runs
|
||||||
|
# which will be testing alternate versions of zig, and ultimately would just
|
||||||
|
# fill up space on the hard drive for no reason.
|
||||||
|
export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache"
|
||||||
|
export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
|
||||||
|
|
||||||
|
mkdir build-debug-llvm
|
||||||
|
cd build-debug-llvm
|
||||||
|
|
||||||
|
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
|
||||||
|
export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
|
||||||
|
|
||||||
|
cmake .. \
|
||||||
|
-DCMAKE_INSTALL_PREFIX="stage3-debug" \
|
||||||
|
-DCMAKE_PREFIX_PATH="$PREFIX" \
|
||||||
|
-DCMAKE_BUILD_TYPE=Debug \
|
||||||
|
-DZIG_TARGET_TRIPLE="$TARGET" \
|
||||||
|
-DZIG_TARGET_MCPU="$MCPU" \
|
||||||
|
-DZIG_STATIC=ON \
|
||||||
|
-DZIG_NO_LIB=ON \
|
||||||
|
-DZIG_EXTRA_BUILD_ARGS="-Duse-llvm=true" \
|
||||||
|
-GNinja
|
||||||
|
|
||||||
|
# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
|
||||||
|
# so that installation and testing do not get affected by them.
|
||||||
|
unset CC
|
||||||
|
unset CXX
|
||||||
|
|
||||||
|
ninja install
|
||||||
|
|
||||||
|
# simultaneously test building self-hosted without LLVM and with 32-bit arm
|
||||||
|
stage3-debug/bin/zig build \
|
||||||
|
-Dtarget=arm-linux-musleabihf \
|
||||||
|
-Dno-lib
|
||||||
|
|
||||||
|
stage3-debug/bin/zig build test docs \
|
||||||
|
--maxrss 21000000000 \
|
||||||
|
-Dlldb=$HOME/deps/lldb-zig/Debug-e0a42bb34/bin/lldb \
|
||||||
|
-fqemu \
|
||||||
|
-fwasmtime \
|
||||||
|
-Dstatic-llvm \
|
||||||
|
-Dskip-freebsd \
|
||||||
|
-Dskip-netbsd \
|
||||||
|
-Dskip-windows \
|
||||||
|
-Dskip-macos \
|
||||||
|
-Dtarget=native-native-musl \
|
||||||
|
--search-prefix "$PREFIX" \
|
||||||
|
--zig-lib-dir "$PWD/../lib" \
|
||||||
|
-Denable-superhtml
|
||||||
@ -25,12 +25,6 @@ git fetch --tags
|
|||||||
export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache"
|
export ZIG_GLOBAL_CACHE_DIR="$PWD/zig-global-cache"
|
||||||
export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
|
export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
|
||||||
|
|
||||||
# Test building from source without LLVM.
|
|
||||||
cc -o bootstrap bootstrap.c
|
|
||||||
./bootstrap
|
|
||||||
./zig2 build -Dno-lib
|
|
||||||
./zig-out/bin/zig test test/behavior.zig
|
|
||||||
|
|
||||||
mkdir build-debug
|
mkdir build-debug
|
||||||
cd build-debug
|
cd build-debug
|
||||||
|
|
||||||
@ -65,39 +59,12 @@ stage3-debug/bin/zig build test docs \
|
|||||||
-fqemu \
|
-fqemu \
|
||||||
-fwasmtime \
|
-fwasmtime \
|
||||||
-Dstatic-llvm \
|
-Dstatic-llvm \
|
||||||
|
-Dskip-freebsd \
|
||||||
|
-Dskip-netbsd \
|
||||||
|
-Dskip-windows \
|
||||||
|
-Dskip-macos \
|
||||||
|
-Dskip-llvm \
|
||||||
-Dtarget=native-native-musl \
|
-Dtarget=native-native-musl \
|
||||||
--search-prefix "$PREFIX" \
|
--search-prefix "$PREFIX" \
|
||||||
--zig-lib-dir "$PWD/../lib" \
|
--zig-lib-dir "$PWD/../lib" \
|
||||||
-Denable-superhtml
|
-Denable-superhtml
|
||||||
|
|
||||||
# Ensure that updating the wasm binary from this commit will result in a viable build.
|
|
||||||
stage3-debug/bin/zig build update-zig1
|
|
||||||
|
|
||||||
mkdir ../build-new
|
|
||||||
cd ../build-new
|
|
||||||
|
|
||||||
export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
|
|
||||||
export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
|
|
||||||
|
|
||||||
cmake .. \
|
|
||||||
-DCMAKE_PREFIX_PATH="$PREFIX" \
|
|
||||||
-DCMAKE_BUILD_TYPE=Debug \
|
|
||||||
-DZIG_TARGET_TRIPLE="$TARGET" \
|
|
||||||
-DZIG_TARGET_MCPU="$MCPU" \
|
|
||||||
-DZIG_STATIC=ON \
|
|
||||||
-DZIG_NO_LIB=ON \
|
|
||||||
-GNinja
|
|
||||||
|
|
||||||
unset CC
|
|
||||||
unset CXX
|
|
||||||
|
|
||||||
ninja install
|
|
||||||
|
|
||||||
stage3/bin/zig test ../test/behavior.zig
|
|
||||||
stage3/bin/zig build -p stage4 \
|
|
||||||
-Dstatic-llvm \
|
|
||||||
-Dtarget=native-native-musl \
|
|
||||||
-Dno-lib \
|
|
||||||
--search-prefix "$PREFIX" \
|
|
||||||
--zig-lib-dir "$PWD/../lib"
|
|
||||||
stage4/bin/zig test ../test/behavior.zig
|
|
||||||
|
|||||||
@ -19,3 +19,4 @@ test "global assembly" {
|
|||||||
|
|
||||||
// test
|
// test
|
||||||
// target=x86_64-linux
|
// target=x86_64-linux
|
||||||
|
// llvm=true
|
||||||
|
|||||||
@ -2581,12 +2581,16 @@ pub fn standardDynamicLinkerPath(target: Target) DynamicLinker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn ptrBitWidth_cpu_abi(cpu: Cpu, abi: Abi) u16 {
|
pub fn ptrBitWidth_cpu_abi(cpu: Cpu, abi: Abi) u16 {
|
||||||
|
return ptrBitWidth_arch_abi(cpu.arch, abi);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ptrBitWidth_arch_abi(cpu_arch: Cpu.Arch, abi: Abi) u16 {
|
||||||
switch (abi) {
|
switch (abi) {
|
||||||
.gnux32, .muslx32, .gnuabin32, .muslabin32, .ilp32 => return 32,
|
.gnux32, .muslx32, .gnuabin32, .muslabin32, .ilp32 => return 32,
|
||||||
.gnuabi64, .muslabi64 => return 64,
|
.gnuabi64, .muslabi64 => return 64,
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
return switch (cpu.arch) {
|
return switch (cpu_arch) {
|
||||||
.avr,
|
.avr,
|
||||||
.msp430,
|
.msp430,
|
||||||
=> 16,
|
=> 16,
|
||||||
|
|||||||
@ -61,7 +61,7 @@ pub const StackTrace = struct {
|
|||||||
|
|
||||||
/// This data structure is used by the Zig language code generation and
|
/// This data structure is used by the Zig language code generation and
|
||||||
/// therefore must be kept in sync with the compiler implementation.
|
/// therefore must be kept in sync with the compiler implementation.
|
||||||
pub const GlobalLinkage = enum {
|
pub const GlobalLinkage = enum(u2) {
|
||||||
internal,
|
internal,
|
||||||
strong,
|
strong,
|
||||||
weak,
|
weak,
|
||||||
@ -70,7 +70,7 @@ pub const GlobalLinkage = enum {
|
|||||||
|
|
||||||
/// This data structure is used by the Zig language code generation and
|
/// This data structure is used by the Zig language code generation and
|
||||||
/// therefore must be kept in sync with the compiler implementation.
|
/// therefore must be kept in sync with the compiler implementation.
|
||||||
pub const SymbolVisibility = enum {
|
pub const SymbolVisibility = enum(u2) {
|
||||||
default,
|
default,
|
||||||
hidden,
|
hidden,
|
||||||
protected,
|
protected,
|
||||||
@ -1030,8 +1030,19 @@ pub const ExternOptions = struct {
|
|||||||
name: []const u8,
|
name: []const u8,
|
||||||
library_name: ?[]const u8 = null,
|
library_name: ?[]const u8 = null,
|
||||||
linkage: GlobalLinkage = .strong,
|
linkage: GlobalLinkage = .strong,
|
||||||
|
visibility: SymbolVisibility = .default,
|
||||||
|
/// Setting this to `true` makes the `@extern` a runtime value.
|
||||||
is_thread_local: bool = false,
|
is_thread_local: bool = false,
|
||||||
is_dll_import: bool = false,
|
is_dll_import: bool = false,
|
||||||
|
relocation: Relocation = .any,
|
||||||
|
|
||||||
|
pub const Relocation = enum(u1) {
|
||||||
|
/// Any type of relocation is allowed.
|
||||||
|
any,
|
||||||
|
/// A program-counter-relative relocation is required.
|
||||||
|
/// Using this value makes the `@extern` a runtime value.
|
||||||
|
pcrel,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/// This data structure is used by the Zig language code generation and
|
/// This data structure is used by the Zig language code generation and
|
||||||
|
|||||||
@ -83,13 +83,16 @@ const RDebug = extern struct {
|
|||||||
r_ldbase: usize,
|
r_ldbase: usize,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// TODO make it possible to reference this same external symbol 2x so we don't need this
|
/// TODO fix comparisons of extern symbol pointers so we don't need this helper function.
|
||||||
/// helper function.
|
pub fn get_DYNAMIC() ?[*]const elf.Dyn {
|
||||||
pub fn get_DYNAMIC() ?[*]elf.Dyn {
|
return @extern([*]const elf.Dyn, .{
|
||||||
return @extern([*]elf.Dyn, .{ .name = "_DYNAMIC", .linkage = .weak });
|
.name = "_DYNAMIC",
|
||||||
|
.linkage = .weak,
|
||||||
|
.visibility = .hidden,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn linkmap_iterator(phdrs: []elf.Phdr) error{InvalidExe}!LinkMap.Iterator {
|
pub fn linkmap_iterator(phdrs: []const elf.Phdr) error{InvalidExe}!LinkMap.Iterator {
|
||||||
_ = phdrs;
|
_ = phdrs;
|
||||||
const _DYNAMIC = get_DYNAMIC() orelse {
|
const _DYNAMIC = get_DYNAMIC() orelse {
|
||||||
// No PT_DYNAMIC means this is either a statically-linked program or a
|
// No PT_DYNAMIC means this is either a statically-linked program or a
|
||||||
|
|||||||
@ -39,27 +39,28 @@ const R_RELATIVE = switch (builtin.cpu.arch) {
|
|||||||
// Obtain a pointer to the _DYNAMIC array.
|
// Obtain a pointer to the _DYNAMIC array.
|
||||||
// We have to compute its address as a PC-relative quantity not to require a
|
// We have to compute its address as a PC-relative quantity not to require a
|
||||||
// relocation that, at this point, is not yet applied.
|
// relocation that, at this point, is not yet applied.
|
||||||
inline fn getDynamicSymbol() [*]elf.Dyn {
|
inline fn getDynamicSymbol() [*]const elf.Dyn {
|
||||||
return switch (builtin.cpu.arch) {
|
return switch (builtin.zig_backend) {
|
||||||
|
else => switch (builtin.cpu.arch) {
|
||||||
.x86 => asm volatile (
|
.x86 => asm volatile (
|
||||||
\\ .weak _DYNAMIC
|
\\ .weak _DYNAMIC
|
||||||
\\ .hidden _DYNAMIC
|
\\ .hidden _DYNAMIC
|
||||||
\\ call 1f
|
\\ call 1f
|
||||||
\\ 1: pop %[ret]
|
\\ 1: pop %[ret]
|
||||||
\\ lea _DYNAMIC-1b(%[ret]), %[ret]
|
\\ lea _DYNAMIC-1b(%[ret]), %[ret]
|
||||||
: [ret] "=r" (-> [*]elf.Dyn),
|
: [ret] "=r" (-> [*]const elf.Dyn),
|
||||||
),
|
),
|
||||||
.x86_64 => asm volatile (
|
.x86_64 => asm volatile (
|
||||||
\\ .weak _DYNAMIC
|
\\ .weak _DYNAMIC
|
||||||
\\ .hidden _DYNAMIC
|
\\ .hidden _DYNAMIC
|
||||||
\\ lea _DYNAMIC(%%rip), %[ret]
|
\\ lea _DYNAMIC(%%rip), %[ret]
|
||||||
: [ret] "=r" (-> [*]elf.Dyn),
|
: [ret] "=r" (-> [*]const elf.Dyn),
|
||||||
),
|
),
|
||||||
.arc => asm volatile (
|
.arc => asm volatile (
|
||||||
\\ .weak _DYNAMIC
|
\\ .weak _DYNAMIC
|
||||||
\\ .hidden _DYNAMIC
|
\\ .hidden _DYNAMIC
|
||||||
\\ add %[ret], pcl, _DYNAMIC@pcl
|
\\ add %[ret], pcl, _DYNAMIC@pcl
|
||||||
: [ret] "=r" (-> [*]elf.Dyn),
|
: [ret] "=r" (-> [*]const elf.Dyn),
|
||||||
),
|
),
|
||||||
// Work around the limited offset range of `ldr`
|
// Work around the limited offset range of `ldr`
|
||||||
.arm, .armeb, .thumb, .thumbeb => asm volatile (
|
.arm, .armeb, .thumb, .thumbeb => asm volatile (
|
||||||
@ -70,7 +71,7 @@ inline fn getDynamicSymbol() [*]elf.Dyn {
|
|||||||
\\ b 2f
|
\\ b 2f
|
||||||
\\ 1: .word _DYNAMIC-1b
|
\\ 1: .word _DYNAMIC-1b
|
||||||
\\ 2:
|
\\ 2:
|
||||||
: [ret] "=r" (-> [*]elf.Dyn),
|
: [ret] "=r" (-> [*]const elf.Dyn),
|
||||||
),
|
),
|
||||||
// A simple `adr` is not enough as it has a limited offset range
|
// A simple `adr` is not enough as it has a limited offset range
|
||||||
.aarch64, .aarch64_be => asm volatile (
|
.aarch64, .aarch64_be => asm volatile (
|
||||||
@ -78,14 +79,14 @@ inline fn getDynamicSymbol() [*]elf.Dyn {
|
|||||||
\\ .hidden _DYNAMIC
|
\\ .hidden _DYNAMIC
|
||||||
\\ adrp %[ret], _DYNAMIC
|
\\ adrp %[ret], _DYNAMIC
|
||||||
\\ add %[ret], %[ret], #:lo12:_DYNAMIC
|
\\ add %[ret], %[ret], #:lo12:_DYNAMIC
|
||||||
: [ret] "=r" (-> [*]elf.Dyn),
|
: [ret] "=r" (-> [*]const elf.Dyn),
|
||||||
),
|
),
|
||||||
// The CSKY ABI requires the gb register to point to the GOT. Additionally, the first
|
// The CSKY ABI requires the gb register to point to the GOT. Additionally, the first
|
||||||
// entry in the GOT is defined to hold the address of _DYNAMIC.
|
// entry in the GOT is defined to hold the address of _DYNAMIC.
|
||||||
.csky => asm volatile (
|
.csky => asm volatile (
|
||||||
\\ mov %[ret], gb
|
\\ mov %[ret], gb
|
||||||
\\ ldw %[ret], %[ret]
|
\\ ldw %[ret], %[ret]
|
||||||
: [ret] "=r" (-> [*]elf.Dyn),
|
: [ret] "=r" (-> [*]const elf.Dyn),
|
||||||
),
|
),
|
||||||
.hexagon => asm volatile (
|
.hexagon => asm volatile (
|
||||||
\\ .weak _DYNAMIC
|
\\ .weak _DYNAMIC
|
||||||
@ -97,7 +98,7 @@ inline fn getDynamicSymbol() [*]elf.Dyn {
|
|||||||
\\ r1 = add(r1, #-4)
|
\\ r1 = add(r1, #-4)
|
||||||
\\ %[ret] = memw(r1)
|
\\ %[ret] = memw(r1)
|
||||||
\\ %[ret] = add(r1, %[ret])
|
\\ %[ret] = add(r1, %[ret])
|
||||||
: [ret] "=r" (-> [*]elf.Dyn),
|
: [ret] "=r" (-> [*]const elf.Dyn),
|
||||||
:
|
:
|
||||||
: "r1"
|
: "r1"
|
||||||
),
|
),
|
||||||
@ -105,7 +106,7 @@ inline fn getDynamicSymbol() [*]elf.Dyn {
|
|||||||
\\ .weak _DYNAMIC
|
\\ .weak _DYNAMIC
|
||||||
\\ .hidden _DYNAMIC
|
\\ .hidden _DYNAMIC
|
||||||
\\ la.local %[ret], _DYNAMIC
|
\\ la.local %[ret], _DYNAMIC
|
||||||
: [ret] "=r" (-> [*]elf.Dyn),
|
: [ret] "=r" (-> [*]const elf.Dyn),
|
||||||
),
|
),
|
||||||
// Note that the - 8 is needed because pc in the second lea instruction points into the
|
// Note that the - 8 is needed because pc in the second lea instruction points into the
|
||||||
// middle of that instruction. (The first lea is 6 bytes, the second is 4 bytes.)
|
// middle of that instruction. (The first lea is 6 bytes, the second is 4 bytes.)
|
||||||
@ -114,7 +115,7 @@ inline fn getDynamicSymbol() [*]elf.Dyn {
|
|||||||
\\ .hidden _DYNAMIC
|
\\ .hidden _DYNAMIC
|
||||||
\\ lea _DYNAMIC - . - 8, %[ret]
|
\\ lea _DYNAMIC - . - 8, %[ret]
|
||||||
\\ lea (%[ret], %%pc), %[ret]
|
\\ lea (%[ret], %%pc), %[ret]
|
||||||
: [ret] "=r" (-> [*]elf.Dyn),
|
: [ret] "=r" (-> [*]const elf.Dyn),
|
||||||
),
|
),
|
||||||
.mips, .mipsel => asm volatile (
|
.mips, .mipsel => asm volatile (
|
||||||
\\ .weak _DYNAMIC
|
\\ .weak _DYNAMIC
|
||||||
@ -124,7 +125,7 @@ inline fn getDynamicSymbol() [*]elf.Dyn {
|
|||||||
\\ 1:
|
\\ 1:
|
||||||
\\ lw %[ret], 0($ra)
|
\\ lw %[ret], 0($ra)
|
||||||
\\ addu %[ret], %[ret], $gp
|
\\ addu %[ret], %[ret], $gp
|
||||||
: [ret] "=r" (-> [*]elf.Dyn),
|
: [ret] "=r" (-> [*]const elf.Dyn),
|
||||||
:
|
:
|
||||||
: "lr"
|
: "lr"
|
||||||
),
|
),
|
||||||
@ -137,7 +138,7 @@ inline fn getDynamicSymbol() [*]elf.Dyn {
|
|||||||
\\ 1:
|
\\ 1:
|
||||||
\\ ld %[ret], 0($ra)
|
\\ ld %[ret], 0($ra)
|
||||||
\\ daddu %[ret], %[ret], $gp
|
\\ daddu %[ret], %[ret], $gp
|
||||||
: [ret] "=r" (-> [*]elf.Dyn),
|
: [ret] "=r" (-> [*]const elf.Dyn),
|
||||||
:
|
:
|
||||||
: "lr"
|
: "lr"
|
||||||
),
|
),
|
||||||
@ -150,7 +151,7 @@ inline fn getDynamicSymbol() [*]elf.Dyn {
|
|||||||
\\ mflr %[ret]
|
\\ mflr %[ret]
|
||||||
\\ lwz 4, 0(%[ret])
|
\\ lwz 4, 0(%[ret])
|
||||||
\\ add %[ret], 4, %[ret]
|
\\ add %[ret], 4, %[ret]
|
||||||
: [ret] "=r" (-> [*]elf.Dyn),
|
: [ret] "=r" (-> [*]const elf.Dyn),
|
||||||
:
|
:
|
||||||
: "lr", "r4"
|
: "lr", "r4"
|
||||||
),
|
),
|
||||||
@ -163,7 +164,7 @@ inline fn getDynamicSymbol() [*]elf.Dyn {
|
|||||||
\\ mflr %[ret]
|
\\ mflr %[ret]
|
||||||
\\ ld 4, 0(%[ret])
|
\\ ld 4, 0(%[ret])
|
||||||
\\ add %[ret], 4, %[ret]
|
\\ add %[ret], 4, %[ret]
|
||||||
: [ret] "=r" (-> [*]elf.Dyn),
|
: [ret] "=r" (-> [*]const elf.Dyn),
|
||||||
:
|
:
|
||||||
: "lr", "r4"
|
: "lr", "r4"
|
||||||
),
|
),
|
||||||
@ -171,7 +172,7 @@ inline fn getDynamicSymbol() [*]elf.Dyn {
|
|||||||
\\ .weak _DYNAMIC
|
\\ .weak _DYNAMIC
|
||||||
\\ .hidden _DYNAMIC
|
\\ .hidden _DYNAMIC
|
||||||
\\ lla %[ret], _DYNAMIC
|
\\ lla %[ret], _DYNAMIC
|
||||||
: [ret] "=r" (-> [*]elf.Dyn),
|
: [ret] "=r" (-> [*]const elf.Dyn),
|
||||||
),
|
),
|
||||||
.s390x => asm volatile (
|
.s390x => asm volatile (
|
||||||
\\ .weak _DYNAMIC
|
\\ .weak _DYNAMIC
|
||||||
@ -181,7 +182,7 @@ inline fn getDynamicSymbol() [*]elf.Dyn {
|
|||||||
\\ jg 2f
|
\\ jg 2f
|
||||||
\\ 1: .quad _DYNAMIC - .
|
\\ 1: .quad _DYNAMIC - .
|
||||||
\\ 2:
|
\\ 2:
|
||||||
: [ret] "=r" (-> [*]elf.Dyn),
|
: [ret] "=r" (-> [*]const elf.Dyn),
|
||||||
),
|
),
|
||||||
// The compiler does not necessarily have any obligation to load the `l7` register (pointing
|
// The compiler does not necessarily have any obligation to load the `l7` register (pointing
|
||||||
// to the GOT), so do it ourselves just in case.
|
// to the GOT), so do it ourselves just in case.
|
||||||
@ -191,15 +192,22 @@ inline fn getDynamicSymbol() [*]elf.Dyn {
|
|||||||
\\ add %%l7, %%lo(_GLOBAL_OFFSET_TABLE_ + 4), %%l7
|
\\ add %%l7, %%lo(_GLOBAL_OFFSET_TABLE_ + 4), %%l7
|
||||||
\\ 1:
|
\\ 1:
|
||||||
\\ add %%l7, %%o7, %[ret]
|
\\ add %%l7, %%o7, %[ret]
|
||||||
: [ret] "=r" (-> [*]elf.Dyn),
|
: [ret] "=r" (-> [*]const elf.Dyn),
|
||||||
),
|
),
|
||||||
else => {
|
else => {
|
||||||
@compileError("PIE startup is not yet supported for this target!");
|
@compileError("PIE startup is not yet supported for this target!");
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
.stage2_x86_64 => @extern([*]const elf.Dyn, .{
|
||||||
|
.name = "_DYNAMIC",
|
||||||
|
.linkage = .weak,
|
||||||
|
.visibility = .hidden,
|
||||||
|
.relocation = .pcrel,
|
||||||
|
}).?,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn relocate(phdrs: []elf.Phdr) void {
|
pub fn relocate(phdrs: []const elf.Phdr) void {
|
||||||
@setRuntimeSafety(false);
|
@setRuntimeSafety(false);
|
||||||
@disableInstrumentation();
|
@disableInstrumentation();
|
||||||
|
|
||||||
@ -256,10 +264,9 @@ pub fn relocate(phdrs: []elf.Phdr) void {
|
|||||||
|
|
||||||
const rel = sorted_dynv[elf.DT_REL];
|
const rel = sorted_dynv[elf.DT_REL];
|
||||||
if (rel != 0) {
|
if (rel != 0) {
|
||||||
const rels = @call(.always_inline, std.mem.bytesAsSlice, .{
|
const rels: []const elf.Rel = @alignCast(@ptrCast(
|
||||||
elf.Rel,
|
@as([*]align(@alignOf(elf.Rel)) const u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]],
|
||||||
@as([*]u8, @ptrFromInt(base_addr + rel))[0..sorted_dynv[elf.DT_RELSZ]],
|
));
|
||||||
});
|
|
||||||
for (rels) |r| {
|
for (rels) |r| {
|
||||||
if (r.r_type() != R_RELATIVE) continue;
|
if (r.r_type() != R_RELATIVE) continue;
|
||||||
@as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr;
|
@as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr;
|
||||||
@ -268,10 +275,9 @@ pub fn relocate(phdrs: []elf.Phdr) void {
|
|||||||
|
|
||||||
const rela = sorted_dynv[elf.DT_RELA];
|
const rela = sorted_dynv[elf.DT_RELA];
|
||||||
if (rela != 0) {
|
if (rela != 0) {
|
||||||
const relas = @call(.always_inline, std.mem.bytesAsSlice, .{
|
const relas: []const elf.Rela = @alignCast(@ptrCast(
|
||||||
elf.Rela,
|
@as([*]align(@alignOf(elf.Rela)) const u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]],
|
||||||
@as([*]u8, @ptrFromInt(base_addr + rela))[0..sorted_dynv[elf.DT_RELASZ]],
|
));
|
||||||
});
|
|
||||||
for (relas) |r| {
|
for (relas) |r| {
|
||||||
if (r.r_type() != R_RELATIVE) continue;
|
if (r.r_type() != R_RELATIVE) continue;
|
||||||
@as(*usize, @ptrFromInt(base_addr + r.r_offset)).* = base_addr + @as(usize, @bitCast(r.r_addend));
|
@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 {
|
|||||||
|
|
||||||
const relr = sorted_dynv[elf.DT_RELR];
|
const relr = sorted_dynv[elf.DT_RELR];
|
||||||
if (relr != 0) {
|
if (relr != 0) {
|
||||||
const relrs = @call(.always_inline, std.mem.bytesAsSlice, .{
|
const relrs: []const elf.Relr = @ptrCast(
|
||||||
elf.Relr,
|
@as([*]align(@alignOf(elf.Relr)) const u8, @ptrFromInt(base_addr + relr))[0..sorted_dynv[elf.DT_RELRSZ]],
|
||||||
@as([*]u8, @ptrFromInt(base_addr + relr))[0..sorted_dynv[elf.DT_RELRSZ]],
|
);
|
||||||
});
|
|
||||||
var current: [*]usize = undefined;
|
var current: [*]usize = undefined;
|
||||||
for (relrs) |r| {
|
for (relrs) |r| {
|
||||||
if ((r & 1) == 0) {
|
if ((r & 1) == 0) {
|
||||||
|
|||||||
@ -163,7 +163,7 @@ fn exit2(code: usize) noreturn {
|
|||||||
// exits(0)
|
// exits(0)
|
||||||
.plan9 => std.os.plan9.exits(null),
|
.plan9 => std.os.plan9.exits(null),
|
||||||
.windows => {
|
.windows => {
|
||||||
std.os.windows.ntdll.RtlExitUserProcess(@as(u32, @truncate(code)));
|
std.os.windows.ntdll.RtlExitUserProcess(@truncate(code));
|
||||||
},
|
},
|
||||||
else => @compileError("TODO"),
|
else => @compileError("TODO"),
|
||||||
}
|
}
|
||||||
@ -511,7 +511,7 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
|
|||||||
// Code coverage instrumentation might try to use thread local variables.
|
// Code coverage instrumentation might try to use thread local variables.
|
||||||
@disableInstrumentation();
|
@disableInstrumentation();
|
||||||
const argc = argc_argv_ptr[0];
|
const argc = argc_argv_ptr[0];
|
||||||
const argv = @as([*][*:0]u8, @ptrCast(argc_argv_ptr + 1));
|
const argv: [*][*:0]u8 = @ptrCast(argc_argv_ptr + 1);
|
||||||
|
|
||||||
const envp_optional: [*:null]?[*:0]u8 = @ptrCast(@alignCast(argv + argc + 1));
|
const envp_optional: [*:null]?[*:0]u8 = @ptrCast(@alignCast(argv + argc + 1));
|
||||||
var envp_count: usize = 0;
|
var envp_count: usize = 0;
|
||||||
@ -573,11 +573,11 @@ fn posixCallMainAndExit(argc_argv_ptr: [*]usize) callconv(.c) noreturn {
|
|||||||
expandStackSize(phdrs);
|
expandStackSize(phdrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
const opt_init_array_start = @extern([*]*const fn () callconv(.c) void, .{
|
const opt_init_array_start = @extern([*]const *const fn () callconv(.c) void, .{
|
||||||
.name = "__init_array_start",
|
.name = "__init_array_start",
|
||||||
.linkage = .weak,
|
.linkage = .weak,
|
||||||
});
|
});
|
||||||
const opt_init_array_end = @extern([*]*const fn () callconv(.c) void, .{
|
const opt_init_array_end = @extern([*]const *const fn () callconv(.c) void, .{
|
||||||
.name = "__init_array_end",
|
.name = "__init_array_end",
|
||||||
.linkage = .weak,
|
.linkage = .weak,
|
||||||
});
|
});
|
||||||
@ -651,7 +651,7 @@ fn main(c_argc: c_int, c_argv: [*][*:0]c_char, c_envp: [*:null]?[*:0]c_char) cal
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn mainWithoutEnv(c_argc: c_int, c_argv: [*][*:0]c_char) callconv(.c) c_int {
|
fn mainWithoutEnv(c_argc: c_int, c_argv: [*][*:0]c_char) callconv(.c) c_int {
|
||||||
std.os.argv = @as([*][*:0]u8, @ptrCast(c_argv))[0..@as(usize, @intCast(c_argc))];
|
std.os.argv = @as([*][*:0]u8, @ptrCast(c_argv))[0..@intCast(c_argc)];
|
||||||
return callMain();
|
return callMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -701,7 +701,7 @@ pub inline fn callMain() u8 {
|
|||||||
pub fn call_wWinMain() std.os.windows.INT {
|
pub fn call_wWinMain() std.os.windows.INT {
|
||||||
const peb = std.os.windows.peb();
|
const peb = std.os.windows.peb();
|
||||||
const MAIN_HINSTANCE = @typeInfo(@TypeOf(root.wWinMain)).@"fn".params[0].type.?;
|
const MAIN_HINSTANCE = @typeInfo(@TypeOf(root.wWinMain)).@"fn".params[0].type.?;
|
||||||
const hInstance = @as(MAIN_HINSTANCE, @ptrCast(peb.ImageBaseAddress));
|
const hInstance: MAIN_HINSTANCE = @ptrCast(peb.ImageBaseAddress);
|
||||||
const lpCmdLine: [*:0]u16 = @ptrCast(peb.ProcessParameters.CommandLine.Buffer);
|
const lpCmdLine: [*:0]u16 = @ptrCast(peb.ProcessParameters.CommandLine.Buffer);
|
||||||
|
|
||||||
// There are various types used for the 'show window' variable through the Win32 APIs:
|
// There are various types used for the 'show window' variable through the Win32 APIs:
|
||||||
|
|||||||
@ -1823,6 +1823,14 @@ pub const Visibility = enum(u2) {
|
|||||||
hidden = 1,
|
hidden = 1,
|
||||||
protected = 2,
|
protected = 2,
|
||||||
|
|
||||||
|
pub fn fromSymbolVisibility(sv: std.builtin.SymbolVisibility) Visibility {
|
||||||
|
return switch (sv) {
|
||||||
|
.default => .default,
|
||||||
|
.hidden => .hidden,
|
||||||
|
.protected => .protected,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub fn format(
|
pub fn format(
|
||||||
self: Visibility,
|
self: Visibility,
|
||||||
comptime _: []const u8,
|
comptime _: []const u8,
|
||||||
@ -2555,6 +2563,10 @@ pub const Variable = struct {
|
|||||||
return self.ptrConst(builder).global.setLinkage(linkage, builder);
|
return self.ptrConst(builder).global.setLinkage(linkage, builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn setVisibility(self: Index, visibility: Visibility, builder: *Builder) void {
|
||||||
|
return self.ptrConst(builder).global.setVisibility(visibility, builder);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn setDllStorageClass(self: Index, class: DllStorageClass, builder: *Builder) void {
|
pub fn setDllStorageClass(self: Index, class: DllStorageClass, builder: *Builder) void {
|
||||||
return self.ptrConst(builder).global.setDllStorageClass(class, builder);
|
return self.ptrConst(builder).global.setDllStorageClass(class, builder);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -272,6 +272,15 @@
|
|||||||
#define zig_linksection_fn zig_linksection
|
#define zig_linksection_fn zig_linksection
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if zig_has_attribute(visibility)
|
||||||
|
#define zig_visibility(name) __attribute__((visibility(#name)))
|
||||||
|
#else
|
||||||
|
#define zig_visibility(name) zig_visibility_##name
|
||||||
|
#define zig_visibility_default
|
||||||
|
#define zig_visibility_hidden zig_visibility_hidden_unavailable
|
||||||
|
#define zig_visibility_protected zig_visibility_protected_unavailable
|
||||||
|
#endif
|
||||||
|
|
||||||
#if zig_has_builtin(unreachable) || defined(zig_gcc) || defined(zig_tinyc)
|
#if zig_has_builtin(unreachable) || defined(zig_gcc) || defined(zig_tinyc)
|
||||||
#define zig_unreachable() __builtin_unreachable()
|
#define zig_unreachable() __builtin_unreachable()
|
||||||
#elif defined(zig_msvc)
|
#elif defined(zig_msvc)
|
||||||
|
|||||||
14
src/Air.zig
14
src/Air.zig
@ -13,6 +13,7 @@ const InternPool = @import("InternPool.zig");
|
|||||||
const Type = @import("Type.zig");
|
const Type = @import("Type.zig");
|
||||||
const Value = @import("Value.zig");
|
const Value = @import("Value.zig");
|
||||||
const Zcu = @import("Zcu.zig");
|
const Zcu = @import("Zcu.zig");
|
||||||
|
const print = @import("Air/print.zig");
|
||||||
const types_resolved = @import("Air/types_resolved.zig");
|
const types_resolved = @import("Air/types_resolved.zig");
|
||||||
|
|
||||||
pub const Legalize = @import("Air/Legalize.zig");
|
pub const Legalize = @import("Air/Legalize.zig");
|
||||||
@ -863,16 +864,17 @@ pub const Inst = struct {
|
|||||||
/// Uses the `vector_store_elem` field.
|
/// Uses the `vector_store_elem` field.
|
||||||
vector_store_elem,
|
vector_store_elem,
|
||||||
|
|
||||||
/// Compute a pointer to a threadlocal or dllimport `Nav`, meaning one of:
|
/// Compute a pointer to a `Nav` at runtime, always one of:
|
||||||
///
|
///
|
||||||
/// * `threadlocal var`
|
/// * `threadlocal var`
|
||||||
/// * `extern threadlocal var` (or corresponding `@extern`)
|
/// * `extern threadlocal var` (or corresponding `@extern`)
|
||||||
/// * `@extern` with `.is_dll_import = true`
|
/// * `@extern` with `.is_dll_import = true`
|
||||||
|
/// * `@extern` with `.relocation = .pcrel`
|
||||||
///
|
///
|
||||||
/// Such pointers are runtime values, so cannot be represented with an InternPool index.
|
/// Such pointers are runtime values, so cannot be represented with an InternPool index.
|
||||||
///
|
///
|
||||||
/// Uses the `ty_nav` field.
|
/// Uses the `ty_nav` field.
|
||||||
tlv_dllimport_ptr,
|
runtime_nav_ptr,
|
||||||
|
|
||||||
/// Implements @cVaArg builtin.
|
/// Implements @cVaArg builtin.
|
||||||
/// Uses the `ty_op` field.
|
/// Uses the `ty_op` field.
|
||||||
@ -1708,7 +1710,7 @@ pub fn typeOfIndex(air: *const Air, inst: Air.Inst.Index, ip: *const InternPool)
|
|||||||
return .fromInterned(ip.indexToKey(err_union_ty.ip_index).error_union_type.payload_type);
|
return .fromInterned(ip.indexToKey(err_union_ty.ip_index).error_union_type.payload_type);
|
||||||
},
|
},
|
||||||
|
|
||||||
.tlv_dllimport_ptr => return .fromInterned(datas[@intFromEnum(inst)].ty_nav.ty),
|
.runtime_nav_ptr => return .fromInterned(datas[@intFromEnum(inst)].ty_nav.ty),
|
||||||
|
|
||||||
.work_item_id,
|
.work_item_id,
|
||||||
.work_group_size,
|
.work_group_size,
|
||||||
@ -1983,7 +1985,7 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
|
|||||||
.err_return_trace,
|
.err_return_trace,
|
||||||
.addrspace_cast,
|
.addrspace_cast,
|
||||||
.save_err_return_trace_index,
|
.save_err_return_trace_index,
|
||||||
.tlv_dllimport_ptr,
|
.runtime_nav_ptr,
|
||||||
.work_item_id,
|
.work_item_id,
|
||||||
.work_group_size,
|
.work_group_size,
|
||||||
.work_group_id,
|
.work_group_id,
|
||||||
@ -2141,6 +2143,10 @@ pub const typesFullyResolved = types_resolved.typesFullyResolved;
|
|||||||
pub const typeFullyResolved = types_resolved.checkType;
|
pub const typeFullyResolved = types_resolved.checkType;
|
||||||
pub const valFullyResolved = types_resolved.checkVal;
|
pub const valFullyResolved = types_resolved.checkVal;
|
||||||
pub const legalize = Legalize.legalize;
|
pub const legalize = Legalize.legalize;
|
||||||
|
pub const write = print.write;
|
||||||
|
pub const writeInst = print.writeInst;
|
||||||
|
pub const dump = print.dump;
|
||||||
|
pub const dumpInst = print.dumpInst;
|
||||||
|
|
||||||
pub const CoveragePoint = enum(u1) {
|
pub const CoveragePoint = enum(u1) {
|
||||||
/// Indicates the block is not a place of interest corresponding to
|
/// Indicates the block is not a place of interest corresponding to
|
||||||
|
|||||||
@ -622,7 +622,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
|
|||||||
.addrspace_cast,
|
.addrspace_cast,
|
||||||
.save_err_return_trace_index,
|
.save_err_return_trace_index,
|
||||||
.vector_store_elem,
|
.vector_store_elem,
|
||||||
.tlv_dllimport_ptr,
|
.runtime_nav_ptr,
|
||||||
.c_va_arg,
|
.c_va_arg,
|
||||||
.c_va_copy,
|
.c_va_copy,
|
||||||
.c_va_end,
|
.c_va_end,
|
||||||
|
|||||||
@ -339,7 +339,7 @@ pub fn categorizeOperand(
|
|||||||
.wasm_memory_size,
|
.wasm_memory_size,
|
||||||
.err_return_trace,
|
.err_return_trace,
|
||||||
.save_err_return_trace_index,
|
.save_err_return_trace_index,
|
||||||
.tlv_dllimport_ptr,
|
.runtime_nav_ptr,
|
||||||
.c_va_start,
|
.c_va_start,
|
||||||
.work_item_id,
|
.work_item_id,
|
||||||
.work_group_size,
|
.work_group_size,
|
||||||
@ -972,7 +972,7 @@ fn analyzeInst(
|
|||||||
.wasm_memory_size,
|
.wasm_memory_size,
|
||||||
.err_return_trace,
|
.err_return_trace,
|
||||||
.save_err_return_trace_index,
|
.save_err_return_trace_index,
|
||||||
.tlv_dllimport_ptr,
|
.runtime_nav_ptr,
|
||||||
.c_va_start,
|
.c_va_start,
|
||||||
.work_item_id,
|
.work_item_id,
|
||||||
.work_group_size,
|
.work_group_size,
|
||||||
|
|||||||
@ -63,7 +63,7 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
|
|||||||
.wasm_memory_size,
|
.wasm_memory_size,
|
||||||
.err_return_trace,
|
.err_return_trace,
|
||||||
.save_err_return_trace_index,
|
.save_err_return_trace_index,
|
||||||
.tlv_dllimport_ptr,
|
.runtime_nav_ptr,
|
||||||
.c_va_start,
|
.c_va_start,
|
||||||
.work_item_id,
|
.work_item_id,
|
||||||
.work_group_size,
|
.work_group_size,
|
||||||
|
|||||||
@ -2,13 +2,15 @@ const std = @import("std");
|
|||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
|
const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
|
||||||
|
|
||||||
const Zcu = @import("Zcu.zig");
|
const build_options = @import("build_options");
|
||||||
const Value = @import("Value.zig");
|
const Zcu = @import("../Zcu.zig");
|
||||||
const Type = @import("Type.zig");
|
const Value = @import("../Value.zig");
|
||||||
const Air = @import("Air.zig");
|
const Type = @import("../Type.zig");
|
||||||
const InternPool = @import("InternPool.zig");
|
const Air = @import("../Air.zig");
|
||||||
|
const InternPool = @import("../InternPool.zig");
|
||||||
|
|
||||||
pub fn write(stream: anytype, pt: Zcu.PerThread, air: Air, liveness: ?Air.Liveness) void {
|
pub fn write(air: Air, stream: anytype, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
|
||||||
|
comptime std.debug.assert(build_options.enable_debug_extensions);
|
||||||
const instruction_bytes = air.instructions.len *
|
const instruction_bytes = air.instructions.len *
|
||||||
// Here we don't use @sizeOf(Air.Inst.Data) because it would include
|
// Here we don't use @sizeOf(Air.Inst.Data) because it would include
|
||||||
// the debug safety tag but we want to measure release size.
|
// the debug safety tag but we want to measure release size.
|
||||||
@ -52,12 +54,13 @@ pub fn write(stream: anytype, pt: Zcu.PerThread, air: Air, liveness: ?Air.Livene
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn writeInst(
|
pub fn writeInst(
|
||||||
|
air: Air,
|
||||||
stream: anytype,
|
stream: anytype,
|
||||||
inst: Air.Inst.Index,
|
inst: Air.Inst.Index,
|
||||||
pt: Zcu.PerThread,
|
pt: Zcu.PerThread,
|
||||||
air: Air,
|
|
||||||
liveness: ?Air.Liveness,
|
liveness: ?Air.Liveness,
|
||||||
) void {
|
) void {
|
||||||
|
comptime std.debug.assert(build_options.enable_debug_extensions);
|
||||||
var writer: Writer = .{
|
var writer: Writer = .{
|
||||||
.pt = pt,
|
.pt = pt,
|
||||||
.gpa = pt.zcu.gpa,
|
.gpa = pt.zcu.gpa,
|
||||||
@ -69,12 +72,12 @@ pub fn writeInst(
|
|||||||
writer.writeInst(stream, inst) catch return;
|
writer.writeInst(stream, inst) catch return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump(pt: Zcu.PerThread, air: Air, liveness: ?Air.Liveness) void {
|
pub fn dump(air: Air, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
|
||||||
write(std.io.getStdErr().writer(), pt, air, liveness);
|
air.write(std.io.getStdErr().writer(), pt, liveness);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dumpInst(inst: Air.Inst.Index, pt: Zcu.PerThread, air: Air, liveness: ?Air.Liveness) void {
|
pub fn dumpInst(air: Air, inst: Air.Inst.Index, pt: Zcu.PerThread, liveness: ?Air.Liveness) void {
|
||||||
writeInst(std.io.getStdErr().writer(), inst, pt, air, liveness);
|
air.writeInst(std.io.getStdErr().writer(), inst, pt, liveness);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Writer = struct {
|
const Writer = struct {
|
||||||
@ -320,7 +323,7 @@ const Writer = struct {
|
|||||||
.reduce, .reduce_optimized => try w.writeReduce(s, inst),
|
.reduce, .reduce_optimized => try w.writeReduce(s, inst),
|
||||||
.cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
|
.cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
|
||||||
.vector_store_elem => try w.writeVectorStoreElem(s, inst),
|
.vector_store_elem => try w.writeVectorStoreElem(s, inst),
|
||||||
.tlv_dllimport_ptr => try w.writeTlvDllimportPtr(s, inst),
|
.runtime_nav_ptr => try w.writeRuntimeNavPtr(s, inst),
|
||||||
|
|
||||||
.work_item_id,
|
.work_item_id,
|
||||||
.work_group_size,
|
.work_group_size,
|
||||||
@ -578,7 +581,7 @@ const Writer = struct {
|
|||||||
try w.writeOperand(s, inst, 2, extra.rhs);
|
try w.writeOperand(s, inst, 2, extra.rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn writeTlvDllimportPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
|
fn writeRuntimeNavPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
|
||||||
const ip = &w.pt.zcu.intern_pool;
|
const ip = &w.pt.zcu.intern_pool;
|
||||||
const ty_nav = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
|
const ty_nav = w.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
|
||||||
try w.writeType(s, .fromInterned(ty_nav.ty));
|
try w.writeType(s, .fromInterned(ty_nav.ty));
|
||||||
@ -321,7 +321,7 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
|
|||||||
if (!checkRef(bin.rhs, zcu)) return false;
|
if (!checkRef(bin.rhs, zcu)) return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
.tlv_dllimport_ptr => {
|
.runtime_nav_ptr => {
|
||||||
if (!checkType(.fromInterned(data.ty_nav.ty), zcu)) return false;
|
if (!checkType(.fromInterned(data.ty_nav.ty), zcu)) return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -774,7 +774,7 @@ pub const Directories = struct {
|
|||||||
/// `comp.debug_incremental`. It is inline so that comptime-known `false` propagates to the caller,
|
/// `comp.debug_incremental`. It is inline so that comptime-known `false` propagates to the caller,
|
||||||
/// preventing debugging features from making it into release builds of the compiler.
|
/// preventing debugging features from making it into release builds of the compiler.
|
||||||
pub inline fn debugIncremental(comp: *const Compilation) bool {
|
pub inline fn debugIncremental(comp: *const Compilation) bool {
|
||||||
if (!build_options.enable_debug_extensions) return false;
|
if (!build_options.enable_debug_extensions or builtin.single_threaded) return false;
|
||||||
return comp.debug_incremental;
|
return comp.debug_incremental;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7225,7 +7225,7 @@ fn buildOutputFromZig(
|
|||||||
assert(out.* == null);
|
assert(out.* == null);
|
||||||
out.* = crt_file;
|
out.* = crt_file;
|
||||||
|
|
||||||
comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
|
comp.queueLinkTaskMode(crt_file.full_object_path, &config);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const CrtFileOptions = struct {
|
pub const CrtFileOptions = struct {
|
||||||
@ -7349,7 +7349,7 @@ pub fn build_crt_file(
|
|||||||
try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node);
|
try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node);
|
||||||
|
|
||||||
const crt_file = try sub_compilation.toCrtFile();
|
const crt_file = try sub_compilation.toCrtFile();
|
||||||
comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
|
comp.queueLinkTaskMode(crt_file.full_object_path, &config);
|
||||||
|
|
||||||
{
|
{
|
||||||
comp.mutex.lock();
|
comp.mutex.lock();
|
||||||
@ -7359,11 +7359,14 @@ pub fn build_crt_file(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn queueLinkTaskMode(comp: *Compilation, path: Cache.Path, output_mode: std.builtin.OutputMode) void {
|
pub fn queueLinkTaskMode(comp: *Compilation, path: Cache.Path, config: *const Compilation.Config) void {
|
||||||
comp.queueLinkTasks(switch (output_mode) {
|
comp.queueLinkTasks(switch (config.output_mode) {
|
||||||
.Exe => unreachable,
|
.Exe => unreachable,
|
||||||
.Obj => &.{.{ .load_object = path }},
|
.Obj => &.{.{ .load_object = path }},
|
||||||
.Lib => &.{.{ .load_archive = path }},
|
.Lib => &.{switch (config.link_mode) {
|
||||||
|
.static => .{ .load_archive = path },
|
||||||
|
.dynamic => .{ .load_dso = path },
|
||||||
|
}},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -191,91 +191,6 @@ pub fn resolve(options: Options) ResolveError!Config {
|
|||||||
|
|
||||||
const root_optimize_mode = options.root_optimize_mode orelse .Debug;
|
const root_optimize_mode = options.root_optimize_mode orelse .Debug;
|
||||||
|
|
||||||
// Make a decision on whether to use LLVM backend for machine code generation.
|
|
||||||
// Note that using the LLVM backend does not necessarily mean using LLVM libraries.
|
|
||||||
// For example, Zig can emit .bc and .ll files directly, and this is still considered
|
|
||||||
// using "the LLVM backend".
|
|
||||||
const use_llvm = b: {
|
|
||||||
// If we have no zig code to compile, no need for LLVM.
|
|
||||||
if (!options.have_zcu) break :b false;
|
|
||||||
|
|
||||||
// If emitting to LLVM bitcode object format, must use LLVM backend.
|
|
||||||
if (options.emit_llvm_ir or options.emit_llvm_bc) {
|
|
||||||
if (options.use_llvm == false)
|
|
||||||
return error.EmittingLlvmModuleRequiresLlvmBackend;
|
|
||||||
if (!target_util.hasLlvmSupport(target, target.ofmt))
|
|
||||||
return error.LlvmLacksTargetSupport;
|
|
||||||
|
|
||||||
break :b true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If LLVM does not support the target, then we can't use it.
|
|
||||||
if (!target_util.hasLlvmSupport(target, target.ofmt)) {
|
|
||||||
if (options.use_llvm == true) return error.LlvmLacksTargetSupport;
|
|
||||||
break :b false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If Zig does not support the target, then we can't use it.
|
|
||||||
if (target_util.zigBackend(target, false) == .other) {
|
|
||||||
if (options.use_llvm == false) return error.ZigLacksTargetSupport;
|
|
||||||
break :b true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.use_llvm) |x| break :b x;
|
|
||||||
|
|
||||||
// If we cannot use LLVM libraries, then our own backends will be a
|
|
||||||
// better default since the LLVM backend can only produce bitcode
|
|
||||||
// and not an object file or executable.
|
|
||||||
if (!use_lib_llvm and options.emit_bin) break :b false;
|
|
||||||
|
|
||||||
// Prefer LLVM for release builds.
|
|
||||||
if (root_optimize_mode != .Debug) break :b true;
|
|
||||||
|
|
||||||
// At this point we would prefer to use our own self-hosted backend,
|
|
||||||
// because the compilation speed is better than LLVM. But only do it if
|
|
||||||
// we are confident in the robustness of the backend.
|
|
||||||
break :b !target_util.selfHostedBackendIsAsRobustAsLlvm(target);
|
|
||||||
};
|
|
||||||
|
|
||||||
if (options.emit_bin and options.have_zcu) {
|
|
||||||
if (!use_lib_llvm and use_llvm) {
|
|
||||||
// Explicit request to use LLVM to produce an object file, but without
|
|
||||||
// using LLVM libraries. Impossible.
|
|
||||||
return error.EmittingBinaryRequiresLlvmLibrary;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (target_util.zigBackend(target, use_llvm) == .other) {
|
|
||||||
// There is no compiler backend available for this target.
|
|
||||||
return error.ZigLacksTargetSupport;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make a decision on whether to use LLD or our own linker.
|
|
||||||
const use_lld = b: {
|
|
||||||
if (!target_util.hasLldSupport(target.ofmt)) {
|
|
||||||
if (options.use_lld == true) return error.LldIncompatibleObjectFormat;
|
|
||||||
break :b false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!build_options.have_llvm) {
|
|
||||||
if (options.use_lld == true) return error.LldUnavailable;
|
|
||||||
break :b false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.lto != null and options.lto != .none) {
|
|
||||||
if (options.use_lld == false) return error.LtoRequiresLld;
|
|
||||||
break :b true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.use_llvm == false) {
|
|
||||||
if (options.use_lld == true) return error.LldCannotIncrementallyLink;
|
|
||||||
break :b false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.use_lld) |x| break :b x;
|
|
||||||
break :b true;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Make a decision on whether to use Clang or Aro for translate-c and compiling C files.
|
// Make a decision on whether to use Clang or Aro for translate-c and compiling C files.
|
||||||
const c_frontend: CFrontend = b: {
|
const c_frontend: CFrontend = b: {
|
||||||
if (!build_options.have_llvm) {
|
if (!build_options.have_llvm) {
|
||||||
@ -288,19 +203,6 @@ pub fn resolve(options: Options) ResolveError!Config {
|
|||||||
break :b .clang;
|
break :b .clang;
|
||||||
};
|
};
|
||||||
|
|
||||||
const lto: std.zig.LtoMode = b: {
|
|
||||||
if (!use_lld) {
|
|
||||||
// zig ld LTO support is tracked by
|
|
||||||
// https://github.com/ziglang/zig/issues/8680
|
|
||||||
if (options.lto != null and options.lto != .none) return error.LtoRequiresLld;
|
|
||||||
break :b .none;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.lto) |x| break :b x;
|
|
||||||
|
|
||||||
break :b .none;
|
|
||||||
};
|
|
||||||
|
|
||||||
const link_libcpp = b: {
|
const link_libcpp = b: {
|
||||||
if (options.link_libcpp == true) break :b true;
|
if (options.link_libcpp == true) break :b true;
|
||||||
if (options.any_sanitize_thread) {
|
if (options.any_sanitize_thread) {
|
||||||
@ -314,14 +216,6 @@ pub fn resolve(options: Options) ResolveError!Config {
|
|||||||
break :b false;
|
break :b false;
|
||||||
};
|
};
|
||||||
|
|
||||||
var link_libunwind = b: {
|
|
||||||
if (link_libcpp and target_util.libCxxNeedsLibUnwind(target)) {
|
|
||||||
if (options.link_libunwind == false) return error.LibCppRequiresLibUnwind;
|
|
||||||
break :b true;
|
|
||||||
}
|
|
||||||
break :b options.link_libunwind orelse false;
|
|
||||||
};
|
|
||||||
|
|
||||||
const link_libc = b: {
|
const link_libc = b: {
|
||||||
if (target_util.osRequiresLibC(target)) {
|
if (target_util.osRequiresLibC(target)) {
|
||||||
if (options.link_libc == false) return error.OsRequiresLibC;
|
if (options.link_libc == false) return error.OsRequiresLibC;
|
||||||
@ -331,7 +225,7 @@ pub fn resolve(options: Options) ResolveError!Config {
|
|||||||
if (options.link_libc == false) return error.LibCppRequiresLibC;
|
if (options.link_libc == false) return error.LibCppRequiresLibC;
|
||||||
break :b true;
|
break :b true;
|
||||||
}
|
}
|
||||||
if (link_libunwind) {
|
if (options.link_libunwind == true) {
|
||||||
if (options.link_libc == false) return error.LibUnwindRequiresLibC;
|
if (options.link_libc == false) return error.LibUnwindRequiresLibC;
|
||||||
break :b true;
|
break :b true;
|
||||||
}
|
}
|
||||||
@ -402,12 +296,17 @@ pub fn resolve(options: Options) ResolveError!Config {
|
|||||||
break :b .static;
|
break :b .static;
|
||||||
};
|
};
|
||||||
|
|
||||||
// This is done here to avoid excessive duplicated logic due to the complex dependencies between these options.
|
const link_libunwind = b: {
|
||||||
if (options.output_mode == .Exe and link_libc and target_util.libCNeedsLibUnwind(target, link_mode)) {
|
if (options.output_mode == .Exe and link_libc and target_util.libCNeedsLibUnwind(target, link_mode)) {
|
||||||
if (options.link_libunwind == false) return error.LibCRequiresLibUnwind;
|
if (options.link_libunwind == false) return error.LibCRequiresLibUnwind;
|
||||||
|
break :b true;
|
||||||
link_libunwind = true;
|
|
||||||
}
|
}
|
||||||
|
if (link_libcpp and target_util.libCxxNeedsLibUnwind(target)) {
|
||||||
|
if (options.link_libunwind == false) return error.LibCppRequiresLibUnwind;
|
||||||
|
break :b true;
|
||||||
|
}
|
||||||
|
break :b options.link_libunwind orelse false;
|
||||||
|
};
|
||||||
|
|
||||||
const import_memory = options.import_memory orelse (options.output_mode == .Obj);
|
const import_memory = options.import_memory orelse (options.output_mode == .Obj);
|
||||||
const export_memory = b: {
|
const export_memory = b: {
|
||||||
@ -446,6 +345,119 @@ pub fn resolve(options: Options) ResolveError!Config {
|
|||||||
} else false;
|
} else false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const is_dyn_lib = switch (options.output_mode) {
|
||||||
|
.Obj, .Exe => false,
|
||||||
|
.Lib => link_mode == .dynamic,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make a decision on whether to use LLVM backend for machine code generation.
|
||||||
|
// Note that using the LLVM backend does not necessarily mean using LLVM libraries.
|
||||||
|
// For example, Zig can emit .bc and .ll files directly, and this is still considered
|
||||||
|
// using "the LLVM backend".
|
||||||
|
const use_llvm = b: {
|
||||||
|
// If we have no zig code to compile, no need for LLVM.
|
||||||
|
if (!options.have_zcu) break :b false;
|
||||||
|
|
||||||
|
// If emitting to LLVM bitcode object format, must use LLVM backend.
|
||||||
|
if (options.emit_llvm_ir or options.emit_llvm_bc) {
|
||||||
|
if (options.use_llvm == false)
|
||||||
|
return error.EmittingLlvmModuleRequiresLlvmBackend;
|
||||||
|
if (!target_util.hasLlvmSupport(target, target.ofmt))
|
||||||
|
return error.LlvmLacksTargetSupport;
|
||||||
|
|
||||||
|
break :b true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If LLVM does not support the target, then we can't use it.
|
||||||
|
if (!target_util.hasLlvmSupport(target, target.ofmt)) {
|
||||||
|
if (options.use_llvm == true) return error.LlvmLacksTargetSupport;
|
||||||
|
break :b false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If Zig does not support the target, then we can't use it.
|
||||||
|
if (target_util.zigBackend(target, false) == .other) {
|
||||||
|
if (options.use_llvm == false) return error.ZigLacksTargetSupport;
|
||||||
|
break :b true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.use_llvm) |x| break :b x;
|
||||||
|
|
||||||
|
// If we cannot use LLVM libraries, then our own backends will be a
|
||||||
|
// better default since the LLVM backend can only produce bitcode
|
||||||
|
// and not an object file or executable.
|
||||||
|
if (!use_lib_llvm and options.emit_bin) break :b false;
|
||||||
|
|
||||||
|
// Prefer LLVM for release builds.
|
||||||
|
if (root_optimize_mode != .Debug) break :b true;
|
||||||
|
|
||||||
|
// load_dynamic_library standalone test not passing on this combination
|
||||||
|
// https://github.com/ziglang/zig/issues/24080
|
||||||
|
if (target.os.tag == .macos and is_dyn_lib) break :b true;
|
||||||
|
|
||||||
|
// At this point we would prefer to use our own self-hosted backend,
|
||||||
|
// because the compilation speed is better than LLVM. But only do it if
|
||||||
|
// we are confident in the robustness of the backend.
|
||||||
|
break :b !target_util.selfHostedBackendIsAsRobustAsLlvm(target);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (options.emit_bin and options.have_zcu) {
|
||||||
|
if (!use_lib_llvm and use_llvm) {
|
||||||
|
// Explicit request to use LLVM to produce an object file, but without
|
||||||
|
// using LLVM libraries. Impossible.
|
||||||
|
return error.EmittingBinaryRequiresLlvmLibrary;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target_util.zigBackend(target, use_llvm) == .other) {
|
||||||
|
// There is no compiler backend available for this target.
|
||||||
|
return error.ZigLacksTargetSupport;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a decision on whether to use LLD or our own linker.
|
||||||
|
const use_lld = b: {
|
||||||
|
if (!target_util.hasLldSupport(target.ofmt)) {
|
||||||
|
if (options.use_lld == true) return error.LldIncompatibleObjectFormat;
|
||||||
|
break :b false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!build_options.have_llvm) {
|
||||||
|
if (options.use_lld == true) return error.LldUnavailable;
|
||||||
|
break :b false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.lto != null and options.lto != .none) {
|
||||||
|
if (options.use_lld == false) return error.LtoRequiresLld;
|
||||||
|
break :b true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.use_llvm == false) {
|
||||||
|
if (options.use_lld == true) return error.LldCannotIncrementallyLink;
|
||||||
|
break :b false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.use_lld) |x| break :b x;
|
||||||
|
|
||||||
|
// If we have no zig code to compile, no need for the self-hosted linker.
|
||||||
|
if (!options.have_zcu) break :b true;
|
||||||
|
|
||||||
|
// If we do have zig code, match the decision for whether to use the llvm backend,
|
||||||
|
// so that the llvm backend defaults to lld and the self-hosted backends do not.
|
||||||
|
break :b use_llvm;
|
||||||
|
};
|
||||||
|
|
||||||
|
const lto: std.zig.LtoMode = b: {
|
||||||
|
if (!use_lld) {
|
||||||
|
// zig ld LTO support is tracked by
|
||||||
|
// https://github.com/ziglang/zig/issues/8680
|
||||||
|
if (options.lto != null and options.lto != .none) return error.LtoRequiresLld;
|
||||||
|
break :b .none;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.lto) |x| break :b x;
|
||||||
|
|
||||||
|
break :b .none;
|
||||||
|
};
|
||||||
|
|
||||||
const root_strip = b: {
|
const root_strip = b: {
|
||||||
if (options.root_strip) |x| break :b x;
|
if (options.root_strip) |x| break :b x;
|
||||||
if (root_optimize_mode == .ReleaseSmall) break :b true;
|
if (root_optimize_mode == .ReleaseSmall) break :b true;
|
||||||
|
|||||||
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
comptime {
|
comptime {
|
||||||
// This file should only be referenced when debug extensions are enabled.
|
// This file should only be referenced when debug extensions are enabled.
|
||||||
std.debug.assert(@import("build_options").enable_debug_extensions);
|
std.debug.assert(@import("build_options").enable_debug_extensions and !@import("builtin").single_threaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
zcu: *Zcu,
|
zcu: *Zcu,
|
||||||
|
|||||||
@ -526,10 +526,10 @@ pub const Nav = struct {
|
|||||||
/// The type of this `Nav` is resolved; the value is queued for resolution.
|
/// The type of this `Nav` is resolved; the value is queued for resolution.
|
||||||
type_resolved: struct {
|
type_resolved: struct {
|
||||||
type: InternPool.Index,
|
type: InternPool.Index,
|
||||||
|
is_const: bool,
|
||||||
alignment: Alignment,
|
alignment: Alignment,
|
||||||
@"linksection": OptionalNullTerminatedString,
|
@"linksection": OptionalNullTerminatedString,
|
||||||
@"addrspace": std.builtin.AddressSpace,
|
@"addrspace": std.builtin.AddressSpace,
|
||||||
is_const: bool,
|
|
||||||
is_threadlocal: bool,
|
is_threadlocal: bool,
|
||||||
/// This field is whether this `Nav` is a literal `extern` definition.
|
/// This field is whether this `Nav` is a literal `extern` definition.
|
||||||
/// It does *not* tell you whether this might alias an extern fn (see #21027).
|
/// It does *not* tell you whether this might alias an extern fn (see #21027).
|
||||||
@ -538,6 +538,7 @@ pub const Nav = struct {
|
|||||||
/// The value of this `Nav` is resolved.
|
/// The value of this `Nav` is resolved.
|
||||||
fully_resolved: struct {
|
fully_resolved: struct {
|
||||||
val: InternPool.Index,
|
val: InternPool.Index,
|
||||||
|
is_const: bool,
|
||||||
alignment: Alignment,
|
alignment: Alignment,
|
||||||
@"linksection": OptionalNullTerminatedString,
|
@"linksection": OptionalNullTerminatedString,
|
||||||
@"addrspace": std.builtin.AddressSpace,
|
@"addrspace": std.builtin.AddressSpace,
|
||||||
@ -727,12 +728,12 @@ pub const Nav = struct {
|
|||||||
const Bits = packed struct(u16) {
|
const Bits = packed struct(u16) {
|
||||||
status: enum(u2) { unresolved, type_resolved, fully_resolved, type_resolved_extern_decl },
|
status: enum(u2) { unresolved, type_resolved, fully_resolved, type_resolved_extern_decl },
|
||||||
/// Populated only if `bits.status != .unresolved`.
|
/// Populated only if `bits.status != .unresolved`.
|
||||||
|
is_const: bool,
|
||||||
|
/// Populated only if `bits.status != .unresolved`.
|
||||||
alignment: Alignment,
|
alignment: Alignment,
|
||||||
/// Populated only if `bits.status != .unresolved`.
|
/// Populated only if `bits.status != .unresolved`.
|
||||||
@"addrspace": std.builtin.AddressSpace,
|
@"addrspace": std.builtin.AddressSpace,
|
||||||
/// Populated only if `bits.status == .type_resolved`.
|
/// Populated only if `bits.status == .type_resolved`.
|
||||||
is_const: bool,
|
|
||||||
/// Populated only if `bits.status == .type_resolved`.
|
|
||||||
is_threadlocal: bool,
|
is_threadlocal: bool,
|
||||||
is_usingnamespace: bool,
|
is_usingnamespace: bool,
|
||||||
};
|
};
|
||||||
@ -753,15 +754,16 @@ pub const Nav = struct {
|
|||||||
.unresolved => .unresolved,
|
.unresolved => .unresolved,
|
||||||
.type_resolved, .type_resolved_extern_decl => .{ .type_resolved = .{
|
.type_resolved, .type_resolved_extern_decl => .{ .type_resolved = .{
|
||||||
.type = repr.type_or_val,
|
.type = repr.type_or_val,
|
||||||
|
.is_const = repr.bits.is_const,
|
||||||
.alignment = repr.bits.alignment,
|
.alignment = repr.bits.alignment,
|
||||||
.@"linksection" = repr.@"linksection",
|
.@"linksection" = repr.@"linksection",
|
||||||
.@"addrspace" = repr.bits.@"addrspace",
|
.@"addrspace" = repr.bits.@"addrspace",
|
||||||
.is_const = repr.bits.is_const,
|
|
||||||
.is_threadlocal = repr.bits.is_threadlocal,
|
.is_threadlocal = repr.bits.is_threadlocal,
|
||||||
.is_extern_decl = repr.bits.status == .type_resolved_extern_decl,
|
.is_extern_decl = repr.bits.status == .type_resolved_extern_decl,
|
||||||
} },
|
} },
|
||||||
.fully_resolved => .{ .fully_resolved = .{
|
.fully_resolved => .{ .fully_resolved = .{
|
||||||
.val = repr.type_or_val,
|
.val = repr.type_or_val,
|
||||||
|
.is_const = repr.bits.is_const,
|
||||||
.alignment = repr.bits.alignment,
|
.alignment = repr.bits.alignment,
|
||||||
.@"linksection" = repr.@"linksection",
|
.@"linksection" = repr.@"linksection",
|
||||||
.@"addrspace" = repr.bits.@"addrspace",
|
.@"addrspace" = repr.bits.@"addrspace",
|
||||||
@ -792,26 +794,26 @@ pub const Nav = struct {
|
|||||||
.bits = switch (nav.status) {
|
.bits = switch (nav.status) {
|
||||||
.unresolved => .{
|
.unresolved => .{
|
||||||
.status = .unresolved,
|
.status = .unresolved,
|
||||||
|
.is_const = false,
|
||||||
.alignment = .none,
|
.alignment = .none,
|
||||||
.@"addrspace" = .generic,
|
.@"addrspace" = .generic,
|
||||||
.is_usingnamespace = nav.is_usingnamespace,
|
.is_usingnamespace = nav.is_usingnamespace,
|
||||||
.is_const = false,
|
|
||||||
.is_threadlocal = false,
|
.is_threadlocal = false,
|
||||||
},
|
},
|
||||||
.type_resolved => |r| .{
|
.type_resolved => |r| .{
|
||||||
.status = if (r.is_extern_decl) .type_resolved_extern_decl else .type_resolved,
|
.status = if (r.is_extern_decl) .type_resolved_extern_decl else .type_resolved,
|
||||||
|
.is_const = r.is_const,
|
||||||
.alignment = r.alignment,
|
.alignment = r.alignment,
|
||||||
.@"addrspace" = r.@"addrspace",
|
.@"addrspace" = r.@"addrspace",
|
||||||
.is_usingnamespace = nav.is_usingnamespace,
|
.is_usingnamespace = nav.is_usingnamespace,
|
||||||
.is_const = r.is_const,
|
|
||||||
.is_threadlocal = r.is_threadlocal,
|
.is_threadlocal = r.is_threadlocal,
|
||||||
},
|
},
|
||||||
.fully_resolved => |r| .{
|
.fully_resolved => |r| .{
|
||||||
.status = .fully_resolved,
|
.status = .fully_resolved,
|
||||||
|
.is_const = r.is_const,
|
||||||
.alignment = r.alignment,
|
.alignment = r.alignment,
|
||||||
.@"addrspace" = r.@"addrspace",
|
.@"addrspace" = r.@"addrspace",
|
||||||
.is_usingnamespace = nav.is_usingnamespace,
|
.is_usingnamespace = nav.is_usingnamespace,
|
||||||
.is_const = false,
|
|
||||||
.is_threadlocal = false,
|
.is_threadlocal = false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -2221,7 +2223,6 @@ pub const Key = union(enum) {
|
|||||||
init: Index,
|
init: Index,
|
||||||
owner_nav: Nav.Index,
|
owner_nav: Nav.Index,
|
||||||
is_threadlocal: bool,
|
is_threadlocal: bool,
|
||||||
is_weak_linkage: bool,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Extern = struct {
|
pub const Extern = struct {
|
||||||
@ -2234,10 +2235,12 @@ pub const Key = union(enum) {
|
|||||||
/// For example `extern "c" fn write(...) usize` would have 'c' as library name.
|
/// For example `extern "c" fn write(...) usize` would have 'c' as library name.
|
||||||
/// Index into the string table bytes.
|
/// Index into the string table bytes.
|
||||||
lib_name: OptionalNullTerminatedString,
|
lib_name: OptionalNullTerminatedString,
|
||||||
is_const: bool,
|
linkage: std.builtin.GlobalLinkage,
|
||||||
|
visibility: std.builtin.SymbolVisibility,
|
||||||
is_threadlocal: bool,
|
is_threadlocal: bool,
|
||||||
is_weak_linkage: bool,
|
|
||||||
is_dll_import: bool,
|
is_dll_import: bool,
|
||||||
|
relocation: std.builtin.ExternOptions.Relocation,
|
||||||
|
is_const: bool,
|
||||||
alignment: Alignment,
|
alignment: Alignment,
|
||||||
@"addrspace": std.builtin.AddressSpace,
|
@"addrspace": std.builtin.AddressSpace,
|
||||||
/// The ZIR instruction which created this extern; used only for source locations.
|
/// The ZIR instruction which created this extern; used only for source locations.
|
||||||
@ -2844,9 +2847,10 @@ pub const Key = union(enum) {
|
|||||||
|
|
||||||
.@"extern" => |e| Hash.hash(seed, asBytes(&e.name) ++
|
.@"extern" => |e| Hash.hash(seed, asBytes(&e.name) ++
|
||||||
asBytes(&e.ty) ++ asBytes(&e.lib_name) ++
|
asBytes(&e.ty) ++ asBytes(&e.lib_name) ++
|
||||||
asBytes(&e.is_const) ++ asBytes(&e.is_threadlocal) ++
|
asBytes(&e.linkage) ++ asBytes(&e.visibility) ++
|
||||||
asBytes(&e.is_weak_linkage) ++ asBytes(&e.alignment) ++
|
asBytes(&e.is_threadlocal) ++ asBytes(&e.is_dll_import) ++
|
||||||
asBytes(&e.is_dll_import) ++ asBytes(&e.@"addrspace") ++
|
asBytes(&e.relocation) ++
|
||||||
|
asBytes(&e.is_const) ++ asBytes(&e.alignment) ++ asBytes(&e.@"addrspace") ++
|
||||||
asBytes(&e.zir_index)),
|
asBytes(&e.zir_index)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -2928,21 +2932,22 @@ pub const Key = union(enum) {
|
|||||||
|
|
||||||
.variable => |a_info| {
|
.variable => |a_info| {
|
||||||
const b_info = b.variable;
|
const b_info = b.variable;
|
||||||
return a_info.owner_nav == b_info.owner_nav and
|
return a_info.ty == b_info.ty and
|
||||||
a_info.ty == b_info.ty and
|
|
||||||
a_info.init == b_info.init and
|
a_info.init == b_info.init and
|
||||||
a_info.is_threadlocal == b_info.is_threadlocal and
|
a_info.owner_nav == b_info.owner_nav and
|
||||||
a_info.is_weak_linkage == b_info.is_weak_linkage;
|
a_info.is_threadlocal == b_info.is_threadlocal;
|
||||||
},
|
},
|
||||||
.@"extern" => |a_info| {
|
.@"extern" => |a_info| {
|
||||||
const b_info = b.@"extern";
|
const b_info = b.@"extern";
|
||||||
return a_info.name == b_info.name and
|
return a_info.name == b_info.name and
|
||||||
a_info.ty == b_info.ty and
|
a_info.ty == b_info.ty and
|
||||||
a_info.lib_name == b_info.lib_name and
|
a_info.lib_name == b_info.lib_name and
|
||||||
a_info.is_const == b_info.is_const and
|
a_info.linkage == b_info.linkage and
|
||||||
|
a_info.visibility == b_info.visibility and
|
||||||
a_info.is_threadlocal == b_info.is_threadlocal and
|
a_info.is_threadlocal == b_info.is_threadlocal and
|
||||||
a_info.is_weak_linkage == b_info.is_weak_linkage and
|
|
||||||
a_info.is_dll_import == b_info.is_dll_import and
|
a_info.is_dll_import == b_info.is_dll_import and
|
||||||
|
a_info.relocation == b_info.relocation and
|
||||||
|
a_info.is_const == b_info.is_const and
|
||||||
a_info.alignment == b_info.alignment and
|
a_info.alignment == b_info.alignment and
|
||||||
a_info.@"addrspace" == b_info.@"addrspace" and
|
a_info.@"addrspace" == b_info.@"addrspace" and
|
||||||
a_info.zir_index == b_info.zir_index;
|
a_info.zir_index == b_info.zir_index;
|
||||||
@ -4889,6 +4894,7 @@ pub const Index = enum(u32) {
|
|||||||
float_c_longdouble_f128: struct { data: *Float128 },
|
float_c_longdouble_f128: struct { data: *Float128 },
|
||||||
float_comptime_float: struct { data: *Float128 },
|
float_comptime_float: struct { data: *Float128 },
|
||||||
variable: struct { data: *Tag.Variable },
|
variable: struct { data: *Tag.Variable },
|
||||||
|
threadlocal_variable: struct { data: *Tag.Variable },
|
||||||
@"extern": struct { data: *Tag.Extern },
|
@"extern": struct { data: *Tag.Extern },
|
||||||
func_decl: struct {
|
func_decl: struct {
|
||||||
const @"data.analysis.inferred_error_set" = opaque {};
|
const @"data.analysis.inferred_error_set" = opaque {};
|
||||||
@ -5548,6 +5554,9 @@ pub const Tag = enum(u8) {
|
|||||||
/// A global variable.
|
/// A global variable.
|
||||||
/// data is extra index to Variable.
|
/// data is extra index to Variable.
|
||||||
variable,
|
variable,
|
||||||
|
/// A global threadlocal variable.
|
||||||
|
/// data is extra index to Variable.
|
||||||
|
threadlocal_variable,
|
||||||
/// An extern function or variable.
|
/// An extern function or variable.
|
||||||
/// data is extra index to Extern.
|
/// data is extra index to Extern.
|
||||||
/// Some parts of the key are stored in `owner_nav`.
|
/// Some parts of the key are stored in `owner_nav`.
|
||||||
@ -5863,6 +5872,7 @@ pub const Tag = enum(u8) {
|
|||||||
.float_c_longdouble_f128 = .{ .summary = .@"@as(c_longdouble, {.payload%value})", .payload = f128 },
|
.float_c_longdouble_f128 = .{ .summary = .@"@as(c_longdouble, {.payload%value})", .payload = f128 },
|
||||||
.float_comptime_float = .{ .summary = .@"{.payload%value}", .payload = f128 },
|
.float_comptime_float = .{ .summary = .@"{.payload%value}", .payload = f128 },
|
||||||
.variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable },
|
.variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable },
|
||||||
|
.threadlocal_variable = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Variable },
|
||||||
.@"extern" = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Extern },
|
.@"extern" = .{ .summary = .@"{.payload.owner_nav.fqn%summary#\"}", .payload = Extern },
|
||||||
.func_decl = .{
|
.func_decl = .{
|
||||||
.summary = .@"{.payload.owner_nav.fqn%summary#\"}",
|
.summary = .@"{.payload.owner_nav.fqn%summary#\"}",
|
||||||
@ -5913,24 +5923,24 @@ pub const Tag = enum(u8) {
|
|||||||
/// May be `none`.
|
/// May be `none`.
|
||||||
init: Index,
|
init: Index,
|
||||||
owner_nav: Nav.Index,
|
owner_nav: Nav.Index,
|
||||||
flags: Flags,
|
|
||||||
|
|
||||||
pub const Flags = packed struct(u32) {
|
|
||||||
is_const: bool,
|
|
||||||
is_threadlocal: bool,
|
|
||||||
is_weak_linkage: bool,
|
|
||||||
is_dll_import: bool,
|
|
||||||
_: u28 = 0,
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Extern = struct {
|
pub const Extern = struct {
|
||||||
// name, alignment, addrspace come from `owner_nav`.
|
// name, is_const, alignment, addrspace come from `owner_nav`.
|
||||||
ty: Index,
|
ty: Index,
|
||||||
lib_name: OptionalNullTerminatedString,
|
lib_name: OptionalNullTerminatedString,
|
||||||
flags: Variable.Flags,
|
flags: Flags,
|
||||||
owner_nav: Nav.Index,
|
owner_nav: Nav.Index,
|
||||||
zir_index: TrackedInst.Index,
|
zir_index: TrackedInst.Index,
|
||||||
|
|
||||||
|
pub const Flags = packed struct(u32) {
|
||||||
|
linkage: std.builtin.GlobalLinkage,
|
||||||
|
visibility: std.builtin.SymbolVisibility,
|
||||||
|
is_threadlocal: bool,
|
||||||
|
is_dll_import: bool,
|
||||||
|
relocation: std.builtin.ExternOptions.Relocation,
|
||||||
|
_: u25 = 0,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Trailing:
|
/// Trailing:
|
||||||
@ -7248,14 +7258,17 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
|
|||||||
.ty = .comptime_float_type,
|
.ty = .comptime_float_type,
|
||||||
.storage = .{ .f128 = extraData(unwrapped_index.getExtra(ip), Float128, data).get() },
|
.storage = .{ .f128 = extraData(unwrapped_index.getExtra(ip), Float128, data).get() },
|
||||||
} },
|
} },
|
||||||
.variable => {
|
.variable, .threadlocal_variable => {
|
||||||
const extra = extraData(unwrapped_index.getExtra(ip), Tag.Variable, data);
|
const extra = extraData(unwrapped_index.getExtra(ip), Tag.Variable, data);
|
||||||
return .{ .variable = .{
|
return .{ .variable = .{
|
||||||
.ty = extra.ty,
|
.ty = extra.ty,
|
||||||
.init = extra.init,
|
.init = extra.init,
|
||||||
.owner_nav = extra.owner_nav,
|
.owner_nav = extra.owner_nav,
|
||||||
.is_threadlocal = extra.flags.is_threadlocal,
|
.is_threadlocal = switch (item.tag) {
|
||||||
.is_weak_linkage = extra.flags.is_weak_linkage,
|
else => unreachable,
|
||||||
|
.variable => false,
|
||||||
|
.threadlocal_variable => true,
|
||||||
|
},
|
||||||
} };
|
} };
|
||||||
},
|
},
|
||||||
.@"extern" => {
|
.@"extern" => {
|
||||||
@ -7265,10 +7278,12 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
|
|||||||
.name = nav.name,
|
.name = nav.name,
|
||||||
.ty = extra.ty,
|
.ty = extra.ty,
|
||||||
.lib_name = extra.lib_name,
|
.lib_name = extra.lib_name,
|
||||||
.is_const = extra.flags.is_const,
|
.linkage = extra.flags.linkage,
|
||||||
|
.visibility = extra.flags.visibility,
|
||||||
.is_threadlocal = extra.flags.is_threadlocal,
|
.is_threadlocal = extra.flags.is_threadlocal,
|
||||||
.is_weak_linkage = extra.flags.is_weak_linkage,
|
|
||||||
.is_dll_import = extra.flags.is_dll_import,
|
.is_dll_import = extra.flags.is_dll_import,
|
||||||
|
.relocation = extra.flags.relocation,
|
||||||
|
.is_const = nav.status.fully_resolved.is_const,
|
||||||
.alignment = nav.status.fully_resolved.alignment,
|
.alignment = nav.status.fully_resolved.alignment,
|
||||||
.@"addrspace" = nav.status.fully_resolved.@"addrspace",
|
.@"addrspace" = nav.status.fully_resolved.@"addrspace",
|
||||||
.zir_index = extra.zir_index,
|
.zir_index = extra.zir_index,
|
||||||
@ -7895,17 +7910,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
|
|||||||
const has_init = variable.init != .none;
|
const has_init = variable.init != .none;
|
||||||
if (has_init) assert(variable.ty == ip.typeOf(variable.init));
|
if (has_init) assert(variable.ty == ip.typeOf(variable.init));
|
||||||
items.appendAssumeCapacity(.{
|
items.appendAssumeCapacity(.{
|
||||||
.tag = .variable,
|
.tag = switch (variable.is_threadlocal) {
|
||||||
|
false => .variable,
|
||||||
|
true => .threadlocal_variable,
|
||||||
|
},
|
||||||
.data = try addExtra(extra, Tag.Variable{
|
.data = try addExtra(extra, Tag.Variable{
|
||||||
.ty = variable.ty,
|
.ty = variable.ty,
|
||||||
.init = variable.init,
|
.init = variable.init,
|
||||||
.owner_nav = variable.owner_nav,
|
.owner_nav = variable.owner_nav,
|
||||||
.flags = .{
|
|
||||||
.is_const = false,
|
|
||||||
.is_threadlocal = variable.is_threadlocal,
|
|
||||||
.is_weak_linkage = variable.is_weak_linkage,
|
|
||||||
.is_dll_import = false,
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@ -9128,6 +9140,7 @@ pub fn getExtern(
|
|||||||
.name = key.name,
|
.name = key.name,
|
||||||
.fqn = key.name,
|
.fqn = key.name,
|
||||||
.val = extern_index,
|
.val = extern_index,
|
||||||
|
.is_const = key.is_const,
|
||||||
.alignment = key.alignment,
|
.alignment = key.alignment,
|
||||||
.@"linksection" = .none,
|
.@"linksection" = .none,
|
||||||
.@"addrspace" = key.@"addrspace",
|
.@"addrspace" = key.@"addrspace",
|
||||||
@ -9136,10 +9149,11 @@ pub fn getExtern(
|
|||||||
.ty = key.ty,
|
.ty = key.ty,
|
||||||
.lib_name = key.lib_name,
|
.lib_name = key.lib_name,
|
||||||
.flags = .{
|
.flags = .{
|
||||||
.is_const = key.is_const,
|
.linkage = key.linkage,
|
||||||
|
.visibility = key.visibility,
|
||||||
.is_threadlocal = key.is_threadlocal,
|
.is_threadlocal = key.is_threadlocal,
|
||||||
.is_weak_linkage = key.is_weak_linkage,
|
|
||||||
.is_dll_import = key.is_dll_import,
|
.is_dll_import = key.is_dll_import,
|
||||||
|
.relocation = key.relocation,
|
||||||
},
|
},
|
||||||
.zir_index = key.zir_index,
|
.zir_index = key.zir_index,
|
||||||
.owner_nav = owner_nav,
|
.owner_nav = owner_nav,
|
||||||
@ -9714,6 +9728,7 @@ fn finishFuncInstance(
|
|||||||
.name = nav_name,
|
.name = nav_name,
|
||||||
.fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, tid, nav_name),
|
.fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, tid, nav_name),
|
||||||
.val = func_index,
|
.val = func_index,
|
||||||
|
.is_const = fn_owner_nav.status.fully_resolved.is_const,
|
||||||
.alignment = fn_owner_nav.status.fully_resolved.alignment,
|
.alignment = fn_owner_nav.status.fully_resolved.alignment,
|
||||||
.@"linksection" = fn_owner_nav.status.fully_resolved.@"linksection",
|
.@"linksection" = fn_owner_nav.status.fully_resolved.@"linksection",
|
||||||
.@"addrspace" = fn_owner_nav.status.fully_resolved.@"addrspace",
|
.@"addrspace" = fn_owner_nav.status.fully_resolved.@"addrspace",
|
||||||
@ -10300,13 +10315,13 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 {
|
|||||||
u32,
|
u32,
|
||||||
i32,
|
i32,
|
||||||
FuncAnalysis,
|
FuncAnalysis,
|
||||||
|
Tag.Extern.Flags,
|
||||||
Tag.TypePointer.Flags,
|
Tag.TypePointer.Flags,
|
||||||
Tag.TypeFunction.Flags,
|
Tag.TypeFunction.Flags,
|
||||||
Tag.TypePointer.PackedOffset,
|
Tag.TypePointer.PackedOffset,
|
||||||
Tag.TypeUnion.Flags,
|
Tag.TypeUnion.Flags,
|
||||||
Tag.TypeStruct.Flags,
|
Tag.TypeStruct.Flags,
|
||||||
Tag.TypeStructPacked.Flags,
|
Tag.TypeStructPacked.Flags,
|
||||||
Tag.Variable.Flags,
|
|
||||||
=> @bitCast(@field(item, field.name)),
|
=> @bitCast(@field(item, field.name)),
|
||||||
|
|
||||||
else => @compileError("bad field type: " ++ @typeName(field.type)),
|
else => @compileError("bad field type: " ++ @typeName(field.type)),
|
||||||
@ -10361,13 +10376,13 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat
|
|||||||
|
|
||||||
u32,
|
u32,
|
||||||
i32,
|
i32,
|
||||||
|
Tag.Extern.Flags,
|
||||||
Tag.TypePointer.Flags,
|
Tag.TypePointer.Flags,
|
||||||
Tag.TypeFunction.Flags,
|
Tag.TypeFunction.Flags,
|
||||||
Tag.TypePointer.PackedOffset,
|
Tag.TypePointer.PackedOffset,
|
||||||
Tag.TypeUnion.Flags,
|
Tag.TypeUnion.Flags,
|
||||||
Tag.TypeStruct.Flags,
|
Tag.TypeStruct.Flags,
|
||||||
Tag.TypeStructPacked.Flags,
|
Tag.TypeStructPacked.Flags,
|
||||||
Tag.Variable.Flags,
|
|
||||||
FuncAnalysis,
|
FuncAnalysis,
|
||||||
=> @bitCast(extra_item),
|
=> @bitCast(extra_item),
|
||||||
|
|
||||||
@ -11162,7 +11177,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
|
|||||||
.float_c_longdouble_f80 => @sizeOf(Float80),
|
.float_c_longdouble_f80 => @sizeOf(Float80),
|
||||||
.float_c_longdouble_f128 => @sizeOf(Float128),
|
.float_c_longdouble_f128 => @sizeOf(Float128),
|
||||||
.float_comptime_float => @sizeOf(Float128),
|
.float_comptime_float => @sizeOf(Float128),
|
||||||
.variable => @sizeOf(Tag.Variable),
|
.variable, .threadlocal_variable => @sizeOf(Tag.Variable),
|
||||||
.@"extern" => @sizeOf(Tag.Extern),
|
.@"extern" => @sizeOf(Tag.Extern),
|
||||||
.func_decl => @sizeOf(Tag.FuncDecl),
|
.func_decl => @sizeOf(Tag.FuncDecl),
|
||||||
.func_instance => b: {
|
.func_instance => b: {
|
||||||
@ -11282,6 +11297,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
|
|||||||
.float_c_longdouble_f128,
|
.float_c_longdouble_f128,
|
||||||
.float_comptime_float,
|
.float_comptime_float,
|
||||||
.variable,
|
.variable,
|
||||||
|
.threadlocal_variable,
|
||||||
.@"extern",
|
.@"extern",
|
||||||
.func_decl,
|
.func_decl,
|
||||||
.func_instance,
|
.func_instance,
|
||||||
@ -11414,6 +11430,7 @@ pub fn createNav(
|
|||||||
name: NullTerminatedString,
|
name: NullTerminatedString,
|
||||||
fqn: NullTerminatedString,
|
fqn: NullTerminatedString,
|
||||||
val: InternPool.Index,
|
val: InternPool.Index,
|
||||||
|
is_const: bool,
|
||||||
alignment: Alignment,
|
alignment: Alignment,
|
||||||
@"linksection": OptionalNullTerminatedString,
|
@"linksection": OptionalNullTerminatedString,
|
||||||
@"addrspace": std.builtin.AddressSpace,
|
@"addrspace": std.builtin.AddressSpace,
|
||||||
@ -11430,6 +11447,7 @@ pub fn createNav(
|
|||||||
.analysis = null,
|
.analysis = null,
|
||||||
.status = .{ .fully_resolved = .{
|
.status = .{ .fully_resolved = .{
|
||||||
.val = opts.val,
|
.val = opts.val,
|
||||||
|
.is_const = opts.is_const,
|
||||||
.alignment = opts.alignment,
|
.alignment = opts.alignment,
|
||||||
.@"linksection" = opts.@"linksection",
|
.@"linksection" = opts.@"linksection",
|
||||||
.@"addrspace" = opts.@"addrspace",
|
.@"addrspace" = opts.@"addrspace",
|
||||||
@ -11482,10 +11500,10 @@ pub fn resolveNavType(
|
|||||||
nav: Nav.Index,
|
nav: Nav.Index,
|
||||||
resolved: struct {
|
resolved: struct {
|
||||||
type: InternPool.Index,
|
type: InternPool.Index,
|
||||||
|
is_const: bool,
|
||||||
alignment: Alignment,
|
alignment: Alignment,
|
||||||
@"linksection": OptionalNullTerminatedString,
|
@"linksection": OptionalNullTerminatedString,
|
||||||
@"addrspace": std.builtin.AddressSpace,
|
@"addrspace": std.builtin.AddressSpace,
|
||||||
is_const: bool,
|
|
||||||
is_threadlocal: bool,
|
is_threadlocal: bool,
|
||||||
is_extern_decl: bool,
|
is_extern_decl: bool,
|
||||||
},
|
},
|
||||||
@ -11512,9 +11530,9 @@ pub fn resolveNavType(
|
|||||||
|
|
||||||
var bits = nav_bits[unwrapped.index];
|
var bits = nav_bits[unwrapped.index];
|
||||||
bits.status = if (resolved.is_extern_decl) .type_resolved_extern_decl else .type_resolved;
|
bits.status = if (resolved.is_extern_decl) .type_resolved_extern_decl else .type_resolved;
|
||||||
|
bits.is_const = resolved.is_const;
|
||||||
bits.alignment = resolved.alignment;
|
bits.alignment = resolved.alignment;
|
||||||
bits.@"addrspace" = resolved.@"addrspace";
|
bits.@"addrspace" = resolved.@"addrspace";
|
||||||
bits.is_const = resolved.is_const;
|
|
||||||
bits.is_threadlocal = resolved.is_threadlocal;
|
bits.is_threadlocal = resolved.is_threadlocal;
|
||||||
@atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);
|
@atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);
|
||||||
}
|
}
|
||||||
@ -11526,6 +11544,7 @@ pub fn resolveNavValue(
|
|||||||
nav: Nav.Index,
|
nav: Nav.Index,
|
||||||
resolved: struct {
|
resolved: struct {
|
||||||
val: InternPool.Index,
|
val: InternPool.Index,
|
||||||
|
is_const: bool,
|
||||||
alignment: Alignment,
|
alignment: Alignment,
|
||||||
@"linksection": OptionalNullTerminatedString,
|
@"linksection": OptionalNullTerminatedString,
|
||||||
@"addrspace": std.builtin.AddressSpace,
|
@"addrspace": std.builtin.AddressSpace,
|
||||||
@ -11553,6 +11572,7 @@ pub fn resolveNavValue(
|
|||||||
|
|
||||||
var bits = nav_bits[unwrapped.index];
|
var bits = nav_bits[unwrapped.index];
|
||||||
bits.status = .fully_resolved;
|
bits.status = .fully_resolved;
|
||||||
|
bits.is_const = resolved.is_const;
|
||||||
bits.alignment = resolved.alignment;
|
bits.alignment = resolved.alignment;
|
||||||
bits.@"addrspace" = resolved.@"addrspace";
|
bits.@"addrspace" = resolved.@"addrspace";
|
||||||
@atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);
|
@atomicStore(Nav.Repr.Bits, &nav_bits[unwrapped.index], bits, .release);
|
||||||
@ -12007,6 +12027,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
|
|||||||
.error_union_error,
|
.error_union_error,
|
||||||
.enum_tag,
|
.enum_tag,
|
||||||
.variable,
|
.variable,
|
||||||
|
.threadlocal_variable,
|
||||||
.@"extern",
|
.@"extern",
|
||||||
.func_decl,
|
.func_decl,
|
||||||
.func_instance,
|
.func_instance,
|
||||||
@ -12391,6 +12412,7 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
|
|||||||
.float_c_longdouble_f128,
|
.float_c_longdouble_f128,
|
||||||
.float_comptime_float,
|
.float_comptime_float,
|
||||||
.variable,
|
.variable,
|
||||||
|
.threadlocal_variable,
|
||||||
.@"extern",
|
.@"extern",
|
||||||
.func_decl,
|
.func_decl,
|
||||||
.func_instance,
|
.func_instance,
|
||||||
|
|||||||
59
src/Sema.zig
59
src/Sema.zig
@ -26089,10 +26089,12 @@ fn resolveExternOptions(
|
|||||||
zir_ref: Zir.Inst.Ref,
|
zir_ref: Zir.Inst.Ref,
|
||||||
) CompileError!struct {
|
) CompileError!struct {
|
||||||
name: InternPool.NullTerminatedString,
|
name: InternPool.NullTerminatedString,
|
||||||
library_name: InternPool.OptionalNullTerminatedString = .none,
|
library_name: InternPool.OptionalNullTerminatedString,
|
||||||
linkage: std.builtin.GlobalLinkage = .strong,
|
linkage: std.builtin.GlobalLinkage,
|
||||||
is_thread_local: bool = false,
|
visibility: std.builtin.SymbolVisibility,
|
||||||
is_dll_import: bool = false,
|
is_thread_local: bool,
|
||||||
|
is_dll_import: bool,
|
||||||
|
relocation: std.builtin.ExternOptions.Relocation,
|
||||||
} {
|
} {
|
||||||
const pt = sema.pt;
|
const pt = sema.pt;
|
||||||
const zcu = pt.zcu;
|
const zcu = pt.zcu;
|
||||||
@ -26105,8 +26107,10 @@ fn resolveExternOptions(
|
|||||||
const name_src = block.src(.{ .init_field_name = src.offset.node_offset_builtin_call_arg.builtin_call_node });
|
const name_src = block.src(.{ .init_field_name = src.offset.node_offset_builtin_call_arg.builtin_call_node });
|
||||||
const library_src = block.src(.{ .init_field_library = src.offset.node_offset_builtin_call_arg.builtin_call_node });
|
const library_src = block.src(.{ .init_field_library = src.offset.node_offset_builtin_call_arg.builtin_call_node });
|
||||||
const linkage_src = block.src(.{ .init_field_linkage = src.offset.node_offset_builtin_call_arg.builtin_call_node });
|
const linkage_src = block.src(.{ .init_field_linkage = src.offset.node_offset_builtin_call_arg.builtin_call_node });
|
||||||
|
const visibility_src = block.src(.{ .init_field_visibility = src.offset.node_offset_builtin_call_arg.builtin_call_node });
|
||||||
const thread_local_src = block.src(.{ .init_field_thread_local = src.offset.node_offset_builtin_call_arg.builtin_call_node });
|
const thread_local_src = block.src(.{ .init_field_thread_local = src.offset.node_offset_builtin_call_arg.builtin_call_node });
|
||||||
const dll_import_src = block.src(.{ .init_field_dll_import = src.offset.node_offset_builtin_call_arg.builtin_call_node });
|
const dll_import_src = block.src(.{ .init_field_dll_import = src.offset.node_offset_builtin_call_arg.builtin_call_node });
|
||||||
|
const relocation_src = block.src(.{ .init_field_relocation = src.offset.node_offset_builtin_call_arg.builtin_call_node });
|
||||||
|
|
||||||
const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), name_src);
|
const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "name", .no_embedded_nulls), name_src);
|
||||||
const name = try sema.toConstString(block, name_src, name_ref, .{ .simple = .extern_options });
|
const name = try sema.toConstString(block, name_src, name_ref, .{ .simple = .extern_options });
|
||||||
@ -26118,6 +26122,10 @@ fn resolveExternOptions(
|
|||||||
const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_ref, .{ .simple = .extern_options });
|
const linkage_val = try sema.resolveConstDefinedValue(block, linkage_src, linkage_ref, .{ .simple = .extern_options });
|
||||||
const linkage = try sema.interpretBuiltinType(block, linkage_src, linkage_val, std.builtin.GlobalLinkage);
|
const linkage = try sema.interpretBuiltinType(block, linkage_src, linkage_val, std.builtin.GlobalLinkage);
|
||||||
|
|
||||||
|
const visibility_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "visibility", .no_embedded_nulls), visibility_src);
|
||||||
|
const visibility_val = try sema.resolveConstDefinedValue(block, visibility_src, visibility_ref, .{ .simple = .extern_options });
|
||||||
|
const visibility = try sema.interpretBuiltinType(block, visibility_src, visibility_val, std.builtin.SymbolVisibility);
|
||||||
|
|
||||||
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);
|
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);
|
||||||
const is_thread_local_val = try sema.resolveConstDefinedValue(block, thread_local_src, is_thread_local, .{ .simple = .extern_options });
|
const is_thread_local_val = try sema.resolveConstDefinedValue(block, thread_local_src, is_thread_local, .{ .simple = .extern_options });
|
||||||
|
|
||||||
@ -26133,6 +26141,10 @@ fn resolveExternOptions(
|
|||||||
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);
|
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);
|
||||||
const is_dll_import_val = try sema.resolveConstDefinedValue(block, dll_import_src, is_dll_import_ref, .{ .simple = .extern_options });
|
const is_dll_import_val = try sema.resolveConstDefinedValue(block, dll_import_src, is_dll_import_ref, .{ .simple = .extern_options });
|
||||||
|
|
||||||
|
const relocation_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, pt.tid, "relocation", .no_embedded_nulls), relocation_src);
|
||||||
|
const relocation_val = try sema.resolveConstDefinedValue(block, relocation_src, relocation_ref, .{ .simple = .extern_options });
|
||||||
|
const relocation = try sema.interpretBuiltinType(block, relocation_src, relocation_val, std.builtin.ExternOptions.Relocation);
|
||||||
|
|
||||||
if (name.len == 0) {
|
if (name.len == 0) {
|
||||||
return sema.fail(block, name_src, "extern symbol name cannot be empty", .{});
|
return sema.fail(block, name_src, "extern symbol name cannot be empty", .{});
|
||||||
}
|
}
|
||||||
@ -26145,8 +26157,10 @@ fn resolveExternOptions(
|
|||||||
.name = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls),
|
.name = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls),
|
||||||
.library_name = try ip.getOrPutStringOpt(gpa, pt.tid, library_name, .no_embedded_nulls),
|
.library_name = try ip.getOrPutStringOpt(gpa, pt.tid, library_name, .no_embedded_nulls),
|
||||||
.linkage = linkage,
|
.linkage = linkage,
|
||||||
|
.visibility = visibility,
|
||||||
.is_thread_local = is_thread_local_val.toBool(),
|
.is_thread_local = is_thread_local_val.toBool(),
|
||||||
.is_dll_import = is_dll_import_val.toBool(),
|
.is_dll_import = is_dll_import_val.toBool(),
|
||||||
|
.relocation = relocation,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26178,6 +26192,17 @@ fn zirBuiltinExtern(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const options = try sema.resolveExternOptions(block, options_src, extra.rhs);
|
const options = try sema.resolveExternOptions(block, options_src, extra.rhs);
|
||||||
|
switch (options.linkage) {
|
||||||
|
.internal => if (options.visibility != .default) {
|
||||||
|
return sema.fail(block, options_src, "internal symbol cannot have non-default visibility", .{});
|
||||||
|
},
|
||||||
|
.strong, .weak => {},
|
||||||
|
.link_once => return sema.fail(block, options_src, "external symbol cannot have link once linkage", .{}),
|
||||||
|
}
|
||||||
|
switch (options.relocation) {
|
||||||
|
.any => {},
|
||||||
|
.pcrel => if (options.visibility == .default) return sema.fail(block, options_src, "cannot require a pc-relative relocation to a symbol with default visibility", .{}),
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: error for threadlocal functions, non-const functions, etc
|
// TODO: error for threadlocal functions, non-const functions, etc
|
||||||
|
|
||||||
@ -26190,10 +26215,12 @@ fn zirBuiltinExtern(
|
|||||||
.name = options.name,
|
.name = options.name,
|
||||||
.ty = ptr_info.child,
|
.ty = ptr_info.child,
|
||||||
.lib_name = options.library_name,
|
.lib_name = options.library_name,
|
||||||
.is_const = ptr_info.flags.is_const,
|
.linkage = options.linkage,
|
||||||
|
.visibility = options.visibility,
|
||||||
.is_threadlocal = options.is_thread_local,
|
.is_threadlocal = options.is_thread_local,
|
||||||
.is_weak_linkage = options.linkage == .weak,
|
|
||||||
.is_dll_import = options.is_dll_import,
|
.is_dll_import = options.is_dll_import,
|
||||||
|
.relocation = options.relocation,
|
||||||
|
.is_const = ptr_info.flags.is_const,
|
||||||
.alignment = ptr_info.flags.alignment,
|
.alignment = ptr_info.flags.alignment,
|
||||||
.@"addrspace" = ptr_info.flags.address_space,
|
.@"addrspace" = ptr_info.flags.address_space,
|
||||||
// This instruction is just for source locations.
|
// This instruction is just for source locations.
|
||||||
@ -31685,12 +31712,15 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
|
|||||||
|
|
||||||
const nav_status = ip.getNav(nav_index).status;
|
const nav_status = ip.getNav(nav_index).status;
|
||||||
|
|
||||||
const is_tlv_or_dllimport = switch (nav_status) {
|
const is_runtime = switch (nav_status) {
|
||||||
.unresolved => unreachable,
|
.unresolved => unreachable,
|
||||||
// dllimports go straight to `fully_resolved`; the only option is threadlocal
|
// dllimports go straight to `fully_resolved`; the only option is threadlocal
|
||||||
.type_resolved => |r| r.is_threadlocal,
|
.type_resolved => |r| r.is_threadlocal,
|
||||||
.fully_resolved => |r| switch (ip.indexToKey(r.val)) {
|
.fully_resolved => |r| switch (ip.indexToKey(r.val)) {
|
||||||
.@"extern" => |e| e.is_threadlocal or e.is_dll_import,
|
.@"extern" => |e| e.is_threadlocal or e.is_dll_import or switch (e.relocation) {
|
||||||
|
.any => false,
|
||||||
|
.pcrel => true,
|
||||||
|
},
|
||||||
.variable => |v| v.is_threadlocal,
|
.variable => |v| v.is_threadlocal,
|
||||||
else => false,
|
else => false,
|
||||||
},
|
},
|
||||||
@ -31699,7 +31729,7 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
|
|||||||
const ty, const alignment, const @"addrspace", const is_const = switch (nav_status) {
|
const ty, const alignment, const @"addrspace", const is_const = switch (nav_status) {
|
||||||
.unresolved => unreachable,
|
.unresolved => unreachable,
|
||||||
.type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },
|
.type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },
|
||||||
.fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", zcu.navValIsConst(r.val) },
|
.fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", r.is_const },
|
||||||
};
|
};
|
||||||
const ptr_ty = try pt.ptrTypeSema(.{
|
const ptr_ty = try pt.ptrTypeSema(.{
|
||||||
.child = ty,
|
.child = ty,
|
||||||
@ -31710,10 +31740,10 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (is_tlv_or_dllimport) {
|
if (is_runtime) {
|
||||||
// This pointer is runtime-known; we need to emit an AIR instruction to create it.
|
// This pointer is runtime-known; we need to emit an AIR instruction to create it.
|
||||||
return block.addInst(.{
|
return block.addInst(.{
|
||||||
.tag = .tlv_dllimport_ptr,
|
.tag = .runtime_nav_ptr,
|
||||||
.data = .{ .ty_nav = .{
|
.data = .{ .ty_nav = .{
|
||||||
.ty = ptr_ty.toIntern(),
|
.ty = ptr_ty.toIntern(),
|
||||||
.nav = nav_index,
|
.nav = nav_index,
|
||||||
@ -32508,11 +32538,11 @@ fn analyzeSlice(
|
|||||||
const actual_len = if (array_ty.zigTypeTag(zcu) == .array)
|
const actual_len = if (array_ty.zigTypeTag(zcu) == .array)
|
||||||
try pt.intRef(.usize, array_ty.arrayLenIncludingSentinel(zcu))
|
try pt.intRef(.usize, array_ty.arrayLenIncludingSentinel(zcu))
|
||||||
else if (slice_ty.isSlice(zcu)) l: {
|
else if (slice_ty.isSlice(zcu)) l: {
|
||||||
const slice_len_inst = try block.addTyOp(.slice_len, .usize, ptr_or_slice);
|
const slice_len = try sema.analyzeSliceLen(block, src, ptr_or_slice);
|
||||||
break :l if (slice_ty.sentinel(zcu) == null)
|
break :l if (slice_ty.sentinel(zcu) == null)
|
||||||
slice_len_inst
|
slice_len
|
||||||
else
|
else
|
||||||
try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true);
|
try sema.analyzeArithmetic(block, .add, slice_len, .one, src, end_src, end_src, true);
|
||||||
} else break :bounds_check;
|
} else break :bounds_check;
|
||||||
|
|
||||||
const actual_end = if (slice_sentinel != null)
|
const actual_end = if (slice_sentinel != null)
|
||||||
@ -36432,6 +36462,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
|
|||||||
.float_c_longdouble_f128,
|
.float_c_longdouble_f128,
|
||||||
.float_comptime_float,
|
.float_comptime_float,
|
||||||
.variable,
|
.variable,
|
||||||
|
.threadlocal_variable,
|
||||||
.@"extern",
|
.@"extern",
|
||||||
.func_decl,
|
.func_decl,
|
||||||
.func_instance,
|
.func_instance,
|
||||||
|
|||||||
12
src/Zcu.zig
12
src/Zcu.zig
@ -2047,6 +2047,7 @@ pub const SrcLoc = struct {
|
|||||||
.init_field_library,
|
.init_field_library,
|
||||||
.init_field_thread_local,
|
.init_field_thread_local,
|
||||||
.init_field_dll_import,
|
.init_field_dll_import,
|
||||||
|
.init_field_relocation,
|
||||||
=> |builtin_call_node| {
|
=> |builtin_call_node| {
|
||||||
const wanted = switch (src_loc.lazy) {
|
const wanted = switch (src_loc.lazy) {
|
||||||
.init_field_name => "name",
|
.init_field_name => "name",
|
||||||
@ -2059,6 +2060,7 @@ pub const SrcLoc = struct {
|
|||||||
.init_field_library => "library",
|
.init_field_library => "library",
|
||||||
.init_field_thread_local => "thread_local",
|
.init_field_thread_local => "thread_local",
|
||||||
.init_field_dll_import => "dll_import",
|
.init_field_dll_import => "dll_import",
|
||||||
|
.init_field_relocation => "relocation",
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
};
|
};
|
||||||
const tree = try src_loc.file_scope.getTree(zcu);
|
const tree = try src_loc.file_scope.getTree(zcu);
|
||||||
@ -2506,6 +2508,7 @@ pub const LazySrcLoc = struct {
|
|||||||
init_field_library: Ast.Node.Offset,
|
init_field_library: Ast.Node.Offset,
|
||||||
init_field_thread_local: Ast.Node.Offset,
|
init_field_thread_local: Ast.Node.Offset,
|
||||||
init_field_dll_import: Ast.Node.Offset,
|
init_field_dll_import: Ast.Node.Offset,
|
||||||
|
init_field_relocation: Ast.Node.Offset,
|
||||||
/// The source location points to the value of an item in a specific
|
/// The source location points to the value of an item in a specific
|
||||||
/// case of a `switch`.
|
/// case of a `switch`.
|
||||||
switch_case_item: SwitchItem,
|
switch_case_item: SwitchItem,
|
||||||
@ -4562,15 +4565,6 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.builtin.CallingConvention) union(enu
|
|||||||
return .ok;
|
return .ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given that a `Nav` has value `val`, determine if a ref of that `Nav` gives a `const` pointer.
|
|
||||||
pub fn navValIsConst(zcu: *const Zcu, val: InternPool.Index) bool {
|
|
||||||
return switch (zcu.intern_pool.indexToKey(val)) {
|
|
||||||
.variable => false,
|
|
||||||
.@"extern" => |e| e.is_const,
|
|
||||||
else => true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const CodegenFailError = error{
|
pub const CodegenFailError = error{
|
||||||
/// Indicates the error message has been already stored at `Zcu.failed_codegen`.
|
/// Indicates the error message has been already stored at `Zcu.failed_codegen`.
|
||||||
CodegenFail,
|
CodegenFail,
|
||||||
|
|||||||
@ -1153,18 +1153,23 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
|
|||||||
// First, we must resolve the declaration's type. To do this, we analyze the type body if available,
|
// First, we must resolve the declaration's type. To do this, we analyze the type body if available,
|
||||||
// or otherwise, we analyze the value body, populating `early_val` in the process.
|
// or otherwise, we analyze the value body, populating `early_val` in the process.
|
||||||
|
|
||||||
switch (zir_decl.kind) {
|
const is_const = is_const: switch (zir_decl.kind) {
|
||||||
.@"comptime" => unreachable, // this is not a Nav
|
.@"comptime" => unreachable, // this is not a Nav
|
||||||
.unnamed_test, .@"test", .decltest => assert(nav_ty.zigTypeTag(zcu) == .@"fn"),
|
.unnamed_test, .@"test", .decltest => {
|
||||||
.@"usingnamespace" => {},
|
assert(nav_ty.zigTypeTag(zcu) == .@"fn");
|
||||||
.@"const" => {},
|
break :is_const true;
|
||||||
.@"var" => try sema.validateVarType(
|
},
|
||||||
|
.@"usingnamespace", .@"const" => true,
|
||||||
|
.@"var" => {
|
||||||
|
try sema.validateVarType(
|
||||||
&block,
|
&block,
|
||||||
if (zir_decl.type_body != null) ty_src else init_src,
|
if (zir_decl.type_body != null) ty_src else init_src,
|
||||||
nav_ty,
|
nav_ty,
|
||||||
zir_decl.linkage == .@"extern",
|
zir_decl.linkage == .@"extern",
|
||||||
),
|
);
|
||||||
}
|
break :is_const false;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// Now that we know the type, we can evaluate the alignment, linksection, and addrspace, to determine
|
// Now that we know the type, we can evaluate the alignment, linksection, and addrspace, to determine
|
||||||
// the full pointer type of this declaration.
|
// the full pointer type of this declaration.
|
||||||
@ -1195,7 +1200,6 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
|
|||||||
.init = final_val.?.toIntern(),
|
.init = final_val.?.toIntern(),
|
||||||
.owner_nav = nav_id,
|
.owner_nav = nav_id,
|
||||||
.is_threadlocal = zir_decl.is_threadlocal,
|
.is_threadlocal = zir_decl.is_threadlocal,
|
||||||
.is_weak_linkage = false,
|
|
||||||
} })),
|
} })),
|
||||||
else => final_val.?,
|
else => final_val.?,
|
||||||
},
|
},
|
||||||
@ -1212,10 +1216,12 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
|
|||||||
.name = old_nav.name,
|
.name = old_nav.name,
|
||||||
.ty = nav_ty.toIntern(),
|
.ty = nav_ty.toIntern(),
|
||||||
.lib_name = try ip.getOrPutStringOpt(gpa, pt.tid, lib_name, .no_embedded_nulls),
|
.lib_name = try ip.getOrPutStringOpt(gpa, pt.tid, lib_name, .no_embedded_nulls),
|
||||||
.is_const = zir_decl.kind == .@"const",
|
|
||||||
.is_threadlocal = zir_decl.is_threadlocal,
|
.is_threadlocal = zir_decl.is_threadlocal,
|
||||||
.is_weak_linkage = false,
|
.linkage = .strong,
|
||||||
|
.visibility = .default,
|
||||||
.is_dll_import = false,
|
.is_dll_import = false,
|
||||||
|
.relocation = .any,
|
||||||
|
.is_const = is_const,
|
||||||
.alignment = modifiers.alignment,
|
.alignment = modifiers.alignment,
|
||||||
.@"addrspace" = modifiers.@"addrspace",
|
.@"addrspace" = modifiers.@"addrspace",
|
||||||
.zir_index = old_nav.analysis.?.zir_index, // `declaration` instruction
|
.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
|
|||||||
}
|
}
|
||||||
ip.resolveNavValue(nav_id, .{
|
ip.resolveNavValue(nav_id, .{
|
||||||
.val = nav_val.toIntern(),
|
.val = nav_val.toIntern(),
|
||||||
|
.is_const = is_const,
|
||||||
.alignment = .none,
|
.alignment = .none,
|
||||||
.@"linksection" = .none,
|
.@"linksection" = .none,
|
||||||
.@"addrspace" = .generic,
|
.@"addrspace" = .generic,
|
||||||
@ -1286,6 +1293,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
|
|||||||
|
|
||||||
ip.resolveNavValue(nav_id, .{
|
ip.resolveNavValue(nav_id, .{
|
||||||
.val = nav_val.toIntern(),
|
.val = nav_val.toIntern(),
|
||||||
|
.is_const = is_const,
|
||||||
.alignment = modifiers.alignment,
|
.alignment = modifiers.alignment,
|
||||||
.@"linksection" = modifiers.@"linksection",
|
.@"linksection" = modifiers.@"linksection",
|
||||||
.@"addrspace" = modifiers.@"addrspace",
|
.@"addrspace" = modifiers.@"addrspace",
|
||||||
@ -1515,8 +1523,6 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
|
|||||||
// the pointer modifiers, i.e. alignment, linksection, addrspace.
|
// the pointer modifiers, i.e. alignment, linksection, addrspace.
|
||||||
const modifiers = try sema.resolveNavPtrModifiers(&block, zir_decl, inst_resolved.inst, resolved_ty);
|
const modifiers = try sema.resolveNavPtrModifiers(&block, zir_decl, inst_resolved.inst, resolved_ty);
|
||||||
|
|
||||||
// Usually, we can infer this information from the resolved `Nav` value; see `Zcu.navValIsConst`.
|
|
||||||
// However, since we don't have one, we need to quickly check the ZIR to figure this out.
|
|
||||||
const is_const = switch (zir_decl.kind) {
|
const is_const = switch (zir_decl.kind) {
|
||||||
.@"comptime" => unreachable,
|
.@"comptime" => unreachable,
|
||||||
.unnamed_test, .@"test", .decltest, .@"usingnamespace", .@"const" => true,
|
.unnamed_test, .@"test", .decltest, .@"usingnamespace", .@"const" => true,
|
||||||
@ -1542,7 +1548,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
|
|||||||
r.alignment != modifiers.alignment or
|
r.alignment != modifiers.alignment or
|
||||||
r.@"linksection" != modifiers.@"linksection" or
|
r.@"linksection" != modifiers.@"linksection" or
|
||||||
r.@"addrspace" != modifiers.@"addrspace" or
|
r.@"addrspace" != modifiers.@"addrspace" or
|
||||||
zcu.navValIsConst(r.val) != is_const or
|
r.is_const != is_const or
|
||||||
(old_nav.getExtern(ip) != null) != is_extern_decl,
|
(old_nav.getExtern(ip) != null) != is_extern_decl,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1550,10 +1556,10 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
|
|||||||
|
|
||||||
ip.resolveNavType(nav_id, .{
|
ip.resolveNavType(nav_id, .{
|
||||||
.type = resolved_ty.toIntern(),
|
.type = resolved_ty.toIntern(),
|
||||||
|
.is_const = is_const,
|
||||||
.alignment = modifiers.alignment,
|
.alignment = modifiers.alignment,
|
||||||
.@"linksection" = modifiers.@"linksection",
|
.@"linksection" = modifiers.@"linksection",
|
||||||
.@"addrspace" = modifiers.@"addrspace",
|
.@"addrspace" = modifiers.@"addrspace",
|
||||||
.is_const = is_const,
|
|
||||||
.is_threadlocal = zir_decl.is_threadlocal,
|
.is_threadlocal = zir_decl.is_threadlocal,
|
||||||
.is_extern_decl = is_extern_decl,
|
.is_extern_decl = is_extern_decl,
|
||||||
});
|
});
|
||||||
@ -1750,7 +1756,7 @@ pub fn linkerUpdateFunc(pt: Zcu.PerThread, func_index: InternPool.Index, air: *A
|
|||||||
|
|
||||||
if (build_options.enable_debug_extensions and comp.verbose_air) {
|
if (build_options.enable_debug_extensions and comp.verbose_air) {
|
||||||
std.debug.print("# Begin Function AIR: {}:\n", .{nav.fqn.fmt(ip)});
|
std.debug.print("# Begin Function AIR: {}:\n", .{nav.fqn.fmt(ip)});
|
||||||
@import("../print_air.zig").dump(pt, air.*, liveness);
|
air.dump(pt, liveness);
|
||||||
std.debug.print("# End Function AIR: {}\n\n", .{nav.fqn.fmt(ip)});
|
std.debug.print("# End Function AIR: {}\n\n", .{nav.fqn.fmt(ip)});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3577,8 +3583,10 @@ pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!V
|
|||||||
.lib_name = e.lib_name,
|
.lib_name = e.lib_name,
|
||||||
.is_const = e.is_const,
|
.is_const = e.is_const,
|
||||||
.is_threadlocal = e.is_threadlocal,
|
.is_threadlocal = e.is_threadlocal,
|
||||||
.is_weak_linkage = e.is_weak_linkage,
|
.linkage = e.linkage,
|
||||||
|
.visibility = e.visibility,
|
||||||
.is_dll_import = e.is_dll_import,
|
.is_dll_import = e.is_dll_import,
|
||||||
|
.relocation = e.relocation,
|
||||||
.alignment = e.alignment,
|
.alignment = e.alignment,
|
||||||
.@"addrspace" = e.@"addrspace",
|
.@"addrspace" = e.@"addrspace",
|
||||||
.zir_index = e.zir_index,
|
.zir_index = e.zir_index,
|
||||||
@ -3954,7 +3962,7 @@ pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Err
|
|||||||
const ty, const alignment, const @"addrspace", const is_const = switch (ip.getNav(nav_id).status) {
|
const ty, const alignment, const @"addrspace", const is_const = switch (ip.getNav(nav_id).status) {
|
||||||
.unresolved => unreachable,
|
.unresolved => unreachable,
|
||||||
.type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },
|
.type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },
|
||||||
.fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", zcu.navValIsConst(r.val) },
|
.fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", r.is_const },
|
||||||
};
|
};
|
||||||
return pt.ptrType(.{
|
return pt.ptrType(.{
|
||||||
.child = ty,
|
.child = ty,
|
||||||
|
|||||||
@ -880,7 +880,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||||||
.is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
|
.is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
|
||||||
.error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
|
.error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
|
||||||
.vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
|
.vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
|
||||||
.tlv_dllimport_ptr => return self.fail("TODO implement tlv_dllimport_ptr", .{}),
|
.runtime_nav_ptr => return self.fail("TODO implement runtime_nav_ptr", .{}),
|
||||||
|
|
||||||
.c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
|
.c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
|
||||||
.c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
|
.c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
|
||||||
|
|||||||
@ -869,7 +869,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||||||
.is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
|
.is_named_enum_value => return self.fail("TODO implement is_named_enum_value", .{}),
|
||||||
.error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
|
.error_set_has_value => return self.fail("TODO implement error_set_has_value", .{}),
|
||||||
.vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
|
.vector_store_elem => return self.fail("TODO implement vector_store_elem", .{}),
|
||||||
.tlv_dllimport_ptr => return self.fail("TODO implement tlv_dllimport_ptr", .{}),
|
.runtime_nav_ptr => return self.fail("TODO implement runtime_nav_ptr", .{}),
|
||||||
|
|
||||||
.c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
|
.c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
|
||||||
.c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
|
.c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
|
||||||
|
|||||||
@ -1041,12 +1041,7 @@ fn formatAir(
|
|||||||
_: std.fmt.FormatOptions,
|
_: std.fmt.FormatOptions,
|
||||||
writer: anytype,
|
writer: anytype,
|
||||||
) @TypeOf(writer).Error!void {
|
) @TypeOf(writer).Error!void {
|
||||||
@import("../../print_air.zig").dumpInst(
|
data.func.air.dumpInst(data.inst, data.func.pt, data.func.liveness);
|
||||||
data.inst,
|
|
||||||
data.func.pt,
|
|
||||||
data.func.air,
|
|
||||||
data.func.liveness,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
fn fmtAir(func: *Func, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {
|
fn fmtAir(func: *Func, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {
|
||||||
return .{ .data = .{ .func = func, .inst = inst } };
|
return .{ .data = .{ .func = func, .inst = inst } };
|
||||||
@ -1656,7 +1651,7 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
|
|||||||
.wrap_errunion_payload => try func.airWrapErrUnionPayload(inst),
|
.wrap_errunion_payload => try func.airWrapErrUnionPayload(inst),
|
||||||
.wrap_errunion_err => try func.airWrapErrUnionErr(inst),
|
.wrap_errunion_err => try func.airWrapErrUnionErr(inst),
|
||||||
|
|
||||||
.tlv_dllimport_ptr => try func.airTlvDllimportPtr(inst),
|
.runtime_nav_ptr => try func.airRuntimeNavPtr(inst),
|
||||||
|
|
||||||
.add_optimized,
|
.add_optimized,
|
||||||
.sub_optimized,
|
.sub_optimized,
|
||||||
@ -3626,7 +3621,7 @@ fn airWrapErrUnionErr(func: *Func, inst: Air.Inst.Index) !void {
|
|||||||
return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
|
return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn airTlvDllimportPtr(func: *Func, inst: Air.Inst.Index) !void {
|
fn airRuntimeNavPtr(func: *Func, inst: Air.Inst.Index) !void {
|
||||||
const zcu = func.pt.zcu;
|
const zcu = func.pt.zcu;
|
||||||
const ip = &zcu.intern_pool;
|
const ip = &zcu.intern_pool;
|
||||||
const ty_nav = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
|
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 {
|
|||||||
break :sym sym;
|
break :sym sym;
|
||||||
}
|
}
|
||||||
break :sym try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav);
|
break :sym try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav);
|
||||||
} else return func.fail("TODO tlv_dllimport_ptr on {}", .{func.bin_file.tag});
|
} else return func.fail("TODO runtime_nav_ptr on {}", .{func.bin_file.tag});
|
||||||
|
|
||||||
const dest_mcv = try func.allocRegOrMem(ptr_ty, inst, true);
|
const dest_mcv = try func.allocRegOrMem(ptr_ty, inst, true);
|
||||||
if (dest_mcv.isRegister()) {
|
if (dest_mcv.isRegister()) {
|
||||||
|
|||||||
@ -723,7 +723,7 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
|
|||||||
.is_named_enum_value => @panic("TODO implement is_named_enum_value"),
|
.is_named_enum_value => @panic("TODO implement is_named_enum_value"),
|
||||||
.error_set_has_value => @panic("TODO implement error_set_has_value"),
|
.error_set_has_value => @panic("TODO implement error_set_has_value"),
|
||||||
.vector_store_elem => @panic("TODO implement vector_store_elem"),
|
.vector_store_elem => @panic("TODO implement vector_store_elem"),
|
||||||
.tlv_dllimport_ptr => @panic("TODO implement tlv_dllimport_ptr"),
|
.runtime_nav_ptr => @panic("TODO implement runtime_nav_ptr"),
|
||||||
|
|
||||||
.c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
|
.c_va_arg => return self.fail("TODO implement c_va_arg", .{}),
|
||||||
.c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
|
.c_va_copy => return self.fail("TODO implement c_va_copy", .{}),
|
||||||
|
|||||||
@ -2057,7 +2057,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
|||||||
.error_set_has_value => cg.airErrorSetHasValue(inst),
|
.error_set_has_value => cg.airErrorSetHasValue(inst),
|
||||||
.frame_addr => cg.airFrameAddress(inst),
|
.frame_addr => cg.airFrameAddress(inst),
|
||||||
|
|
||||||
.tlv_dllimport_ptr => cg.airTlvDllimportPtr(inst),
|
.runtime_nav_ptr => cg.airRuntimeNavPtr(inst),
|
||||||
|
|
||||||
.assembly,
|
.assembly,
|
||||||
.is_err_ptr,
|
.is_err_ptr,
|
||||||
@ -7616,7 +7616,7 @@ fn airFrameAddress(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
|||||||
return cg.finishAir(inst, .stack, &.{});
|
return cg.finishAir(inst, .stack, &.{});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn airTlvDllimportPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
fn airRuntimeNavPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
|
||||||
const ty_nav = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
|
const ty_nav = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
|
||||||
const mod = cg.pt.zcu.navFileScope(cg.owner_nav).mod.?;
|
const mod = cg.pt.zcu.navFileScope(cg.owner_nav).mod.?;
|
||||||
if (mod.single_threaded) {
|
if (mod.single_threaded) {
|
||||||
|
|||||||
@ -274,6 +274,12 @@ pub const MCValue = union(enum) {
|
|||||||
load_symbol: bits.SymbolOffset,
|
load_symbol: bits.SymbolOffset,
|
||||||
/// The address of the memory location not-yet-allocated by the linker.
|
/// The address of the memory location not-yet-allocated by the linker.
|
||||||
lea_symbol: bits.SymbolOffset,
|
lea_symbol: bits.SymbolOffset,
|
||||||
|
/// The value is in memory at an address not-yet-allocated by the linker.
|
||||||
|
/// This must use a non-got pc-relative relocation.
|
||||||
|
load_pcrel: bits.SymbolOffset,
|
||||||
|
/// The address of the memory location not-yet-allocated by the linker.
|
||||||
|
/// This must use a non-got pc-relative relocation.
|
||||||
|
lea_pcrel: bits.SymbolOffset,
|
||||||
/// The value is in memory at a constant offset from the address in a register.
|
/// The value is in memory at a constant offset from the address in a register.
|
||||||
indirect: bits.RegisterOffset,
|
indirect: bits.RegisterOffset,
|
||||||
/// The value is in memory.
|
/// The value is in memory.
|
||||||
@ -314,6 +320,7 @@ pub const MCValue = union(enum) {
|
|||||||
.eflags,
|
.eflags,
|
||||||
.register_overflow,
|
.register_overflow,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.lea_pcrel,
|
||||||
.lea_direct,
|
.lea_direct,
|
||||||
.lea_got,
|
.lea_got,
|
||||||
.lea_frame,
|
.lea_frame,
|
||||||
@ -327,6 +334,7 @@ pub const MCValue = union(enum) {
|
|||||||
.register_quadruple,
|
.register_quadruple,
|
||||||
.memory,
|
.memory,
|
||||||
.load_symbol,
|
.load_symbol,
|
||||||
|
.load_pcrel,
|
||||||
.load_got,
|
.load_got,
|
||||||
.load_direct,
|
.load_direct,
|
||||||
.indirect,
|
.indirect,
|
||||||
@ -429,6 +437,7 @@ pub const MCValue = union(enum) {
|
|||||||
.register_overflow,
|
.register_overflow,
|
||||||
.register_mask,
|
.register_mask,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.lea_pcrel,
|
||||||
.lea_direct,
|
.lea_direct,
|
||||||
.lea_got,
|
.lea_got,
|
||||||
.lea_frame,
|
.lea_frame,
|
||||||
@ -445,6 +454,7 @@ pub const MCValue = union(enum) {
|
|||||||
.load_got => |sym_index| .{ .lea_got = sym_index },
|
.load_got => |sym_index| .{ .lea_got = sym_index },
|
||||||
.load_frame => |frame_addr| .{ .lea_frame = frame_addr },
|
.load_frame => |frame_addr| .{ .lea_frame = frame_addr },
|
||||||
.load_symbol => |sym_off| .{ .lea_symbol = sym_off },
|
.load_symbol => |sym_off| .{ .lea_symbol = sym_off },
|
||||||
|
.load_pcrel => |sym_off| .{ .lea_pcrel = sym_off },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -466,6 +476,7 @@ pub const MCValue = union(enum) {
|
|||||||
.load_got,
|
.load_got,
|
||||||
.load_frame,
|
.load_frame,
|
||||||
.load_symbol,
|
.load_symbol,
|
||||||
|
.load_pcrel,
|
||||||
.elementwise_args,
|
.elementwise_args,
|
||||||
.reserved_frame,
|
.reserved_frame,
|
||||||
.air_ref,
|
.air_ref,
|
||||||
@ -477,6 +488,7 @@ pub const MCValue = union(enum) {
|
|||||||
.lea_got => |sym_index| .{ .load_got = sym_index },
|
.lea_got => |sym_index| .{ .load_got = sym_index },
|
||||||
.lea_frame => |frame_addr| .{ .load_frame = frame_addr },
|
.lea_frame => |frame_addr| .{ .load_frame = frame_addr },
|
||||||
.lea_symbol => |sym_index| .{ .load_symbol = sym_index },
|
.lea_symbol => |sym_index| .{ .load_symbol = sym_index },
|
||||||
|
.lea_pcrel => |sym_index| .{ .load_pcrel = sym_index },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,6 +517,8 @@ pub const MCValue = union(enum) {
|
|||||||
.load_frame,
|
.load_frame,
|
||||||
.load_symbol,
|
.load_symbol,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.load_pcrel,
|
||||||
|
.lea_pcrel,
|
||||||
=> switch (off) {
|
=> switch (off) {
|
||||||
0 => mcv,
|
0 => mcv,
|
||||||
else => unreachable, // not offsettable
|
else => unreachable, // not offsettable
|
||||||
@ -543,6 +557,7 @@ pub const MCValue = union(enum) {
|
|||||||
.elementwise_args,
|
.elementwise_args,
|
||||||
.reserved_frame,
|
.reserved_frame,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.lea_pcrel,
|
||||||
=> unreachable,
|
=> unreachable,
|
||||||
.memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| .{
|
.memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr| .{
|
||||||
.base = .{ .reg = .ds },
|
.base = .{ .reg = .ds },
|
||||||
@ -583,6 +598,18 @@ pub const MCValue = union(enum) {
|
|||||||
} },
|
} },
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
.load_pcrel => |sym_off| {
|
||||||
|
assert(sym_off.off == 0);
|
||||||
|
return .{
|
||||||
|
.base = .{ .pcrel = sym_off.sym_index },
|
||||||
|
.mod = .{ .rm = .{
|
||||||
|
.size = mod_rm.size,
|
||||||
|
.index = mod_rm.index,
|
||||||
|
.scale = mod_rm.scale,
|
||||||
|
.disp = sym_off.off + mod_rm.disp,
|
||||||
|
} },
|
||||||
|
};
|
||||||
|
},
|
||||||
.air_ref => |ref| (try function.resolveInst(ref)).mem(function, mod_rm),
|
.air_ref => |ref| (try function.resolveInst(ref)).mem(function, mod_rm),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -618,6 +645,8 @@ pub const MCValue = union(enum) {
|
|||||||
}),
|
}),
|
||||||
.load_symbol => |pl| try writer.print("[sym:{} + 0x{x}]", .{ pl.sym_index, pl.off }),
|
.load_symbol => |pl| try writer.print("[sym:{} + 0x{x}]", .{ pl.sym_index, pl.off }),
|
||||||
.lea_symbol => |pl| try writer.print("sym:{} + 0x{x}", .{ pl.sym_index, pl.off }),
|
.lea_symbol => |pl| try writer.print("sym:{} + 0x{x}", .{ pl.sym_index, pl.off }),
|
||||||
|
.load_pcrel => |pl| try writer.print("[sym@pcrel:{} + 0x{x}]", .{ pl.sym_index, pl.off }),
|
||||||
|
.lea_pcrel => |pl| try writer.print("sym@pcrel:{} + 0x{x}", .{ pl.sym_index, pl.off }),
|
||||||
.indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),
|
.indirect => |pl| try writer.print("[{s} + 0x{x}]", .{ @tagName(pl.reg), pl.off }),
|
||||||
.load_direct => |pl| try writer.print("[direct:{d}]", .{pl}),
|
.load_direct => |pl| try writer.print("[direct:{d}]", .{pl}),
|
||||||
.lea_direct => |pl| try writer.print("direct:{d}", .{pl}),
|
.lea_direct => |pl| try writer.print("direct:{d}", .{pl}),
|
||||||
@ -655,6 +684,8 @@ const InstTracking = struct {
|
|||||||
.lea_frame,
|
.lea_frame,
|
||||||
.load_symbol,
|
.load_symbol,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.load_pcrel,
|
||||||
|
.lea_pcrel,
|
||||||
=> result,
|
=> result,
|
||||||
.dead,
|
.dead,
|
||||||
.elementwise_args,
|
.elementwise_args,
|
||||||
@ -755,6 +786,8 @@ const InstTracking = struct {
|
|||||||
.lea_frame,
|
.lea_frame,
|
||||||
.load_symbol,
|
.load_symbol,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.load_pcrel,
|
||||||
|
.lea_pcrel,
|
||||||
=> assert(std.meta.eql(self.long, target.long)),
|
=> assert(std.meta.eql(self.long, target.long)),
|
||||||
.dead,
|
.dead,
|
||||||
.eflags,
|
.eflags,
|
||||||
@ -1228,12 +1261,7 @@ fn formatAir(
|
|||||||
_: std.fmt.FormatOptions,
|
_: std.fmt.FormatOptions,
|
||||||
writer: anytype,
|
writer: anytype,
|
||||||
) @TypeOf(writer).Error!void {
|
) @TypeOf(writer).Error!void {
|
||||||
@import("../../print_air.zig").dumpInst(
|
data.self.air.dumpInst(data.inst, data.self.pt, data.self.liveness);
|
||||||
data.inst,
|
|
||||||
data.self.pt,
|
|
||||||
data.self.air,
|
|
||||||
data.self.liveness,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {
|
fn fmtAir(self: *CodeGen, inst: Air.Inst.Index) std.fmt.Formatter(formatAir) {
|
||||||
return .{ .data = .{ .self = self, .inst = inst } };
|
return .{ .data = .{ .self = self, .inst = inst } };
|
||||||
@ -161477,11 +161505,13 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
|||||||
for (elems, 0..) |elem_ref, field_index| {
|
for (elems, 0..) |elem_ref, field_index| {
|
||||||
const elem_dies = bt.feed();
|
const elem_dies = bt.feed();
|
||||||
if (loaded_struct.fieldIsComptime(ip, field_index)) continue;
|
if (loaded_struct.fieldIsComptime(ip, field_index)) continue;
|
||||||
|
if (!hack_around_sema_opv_bugs or Type.fromInterned(loaded_struct.field_types.get(ip)[field_index]).hasRuntimeBitsIgnoreComptime(zcu)) {
|
||||||
var elem = try cg.tempFromOperand(elem_ref, elem_dies);
|
var elem = try cg.tempFromOperand(elem_ref, elem_dies);
|
||||||
try res.write(&elem, .{ .disp = @intCast(loaded_struct.offsets.get(ip)[field_index]) }, cg);
|
try res.write(&elem, .{ .disp = @intCast(loaded_struct.offsets.get(ip)[field_index]) }, cg);
|
||||||
try elem.die(cg);
|
try elem.die(cg);
|
||||||
try cg.resetTemps(reset_index);
|
try cg.resetTemps(reset_index);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
.@"packed" => return cg.fail("failed to select {s} {}", .{
|
.@"packed" => return cg.fail("failed to select {s} {}", .{
|
||||||
@tagName(air_tag),
|
@tagName(air_tag),
|
||||||
@ -163487,31 +163517,49 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
|||||||
};
|
};
|
||||||
for (ops) |op| try op.die(cg);
|
for (ops) |op| try op.die(cg);
|
||||||
},
|
},
|
||||||
.tlv_dllimport_ptr => switch (cg.bin_file.tag) {
|
.runtime_nav_ptr => switch (cg.bin_file.tag) {
|
||||||
.elf, .macho => {
|
.elf, .macho => {
|
||||||
const ty_nav = air_datas[@intFromEnum(inst)].ty_nav;
|
const ty_nav = air_datas[@intFromEnum(inst)].ty_nav;
|
||||||
|
|
||||||
const nav = ip.getNav(ty_nav.nav);
|
const nav = ip.getNav(ty_nav.nav);
|
||||||
const tlv_sym_index = sym: {
|
const sym_index, const relocation = sym: {
|
||||||
if (cg.bin_file.cast(.elf)) |elf_file| {
|
if (cg.bin_file.cast(.elf)) |elf_file| {
|
||||||
const zo = elf_file.zigObjectPtr().?;
|
const zo = elf_file.zigObjectPtr().?;
|
||||||
if (nav.getExtern(ip)) |e| {
|
if (nav.getExtern(ip)) |e| {
|
||||||
const sym = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip));
|
const sym = try elf_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip));
|
||||||
zo.symbol(sym).flags.is_extern_ptr = true;
|
linkage: switch (e.linkage) {
|
||||||
break :sym sym;
|
.internal => {},
|
||||||
|
.strong => switch (e.visibility) {
|
||||||
|
.default => zo.symbol(sym).flags.is_extern_ptr = true,
|
||||||
|
.hidden, .protected => {},
|
||||||
|
},
|
||||||
|
.weak => {
|
||||||
|
zo.symbol(sym).flags.weak = true;
|
||||||
|
continue :linkage .strong;
|
||||||
|
},
|
||||||
|
.link_once => unreachable,
|
||||||
}
|
}
|
||||||
break :sym try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav);
|
break :sym .{ sym, e.relocation };
|
||||||
}
|
} else break :sym .{ try zo.getOrCreateMetadataForNav(zcu, ty_nav.nav), .any };
|
||||||
if (cg.bin_file.cast(.macho)) |macho_file| {
|
} else if (cg.bin_file.cast(.macho)) |macho_file| {
|
||||||
const zo = macho_file.getZigObject().?;
|
const zo = macho_file.getZigObject().?;
|
||||||
if (nav.getExtern(ip)) |e| {
|
if (nav.getExtern(ip)) |e| {
|
||||||
const sym = try macho_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip));
|
const sym = try macho_file.getGlobalSymbol(nav.name.toSlice(ip), e.lib_name.toSlice(ip));
|
||||||
zo.symbols.items[sym].flags.is_extern_ptr = true;
|
linkage: switch (e.linkage) {
|
||||||
break :sym sym;
|
.internal => {},
|
||||||
|
.strong => switch (e.visibility) {
|
||||||
|
.default => zo.symbols.items[sym].flags.is_extern_ptr = true,
|
||||||
|
.hidden, .protected => {},
|
||||||
|
},
|
||||||
|
.weak => {
|
||||||
|
zo.symbols.items[sym].flags.weak = true;
|
||||||
|
continue :linkage .strong;
|
||||||
|
},
|
||||||
|
.link_once => unreachable,
|
||||||
}
|
}
|
||||||
break :sym try zo.getOrCreateMetadataForNav(macho_file, ty_nav.nav);
|
break :sym .{ sym, e.relocation };
|
||||||
}
|
} else break :sym .{ try zo.getOrCreateMetadataForNav(macho_file, ty_nav.nav), .any };
|
||||||
unreachable;
|
} else unreachable;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (cg.mod.pic) {
|
if (cg.mod.pic) {
|
||||||
@ -163520,13 +163568,14 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
|
|||||||
try cg.spillRegisters(&.{.rax});
|
try cg.spillRegisters(&.{.rax});
|
||||||
}
|
}
|
||||||
|
|
||||||
var slot = try cg.tempInit(.usize, .{ .lea_symbol = .{
|
var slot = try cg.tempInit(.usize, switch (relocation) {
|
||||||
.sym_index = tlv_sym_index,
|
.any => .{ .lea_symbol = .{ .sym_index = sym_index } },
|
||||||
} });
|
.pcrel => .{ .lea_pcrel = .{ .sym_index = sym_index } },
|
||||||
|
});
|
||||||
while (try slot.toRegClass(true, .general_purpose, cg)) {}
|
while (try slot.toRegClass(true, .general_purpose, cg)) {}
|
||||||
try slot.finish(inst, &.{}, &.{}, cg);
|
try slot.finish(inst, &.{}, &.{}, cg);
|
||||||
},
|
},
|
||||||
else => return cg.fail("TODO implement tlv/dllimport on {}", .{cg.bin_file.tag}),
|
else => return cg.fail("TODO implement runtime_nav_ptr on {}", .{cg.bin_file.tag}),
|
||||||
},
|
},
|
||||||
.c_va_arg => try cg.airVaArg(inst),
|
.c_va_arg => try cg.airVaArg(inst),
|
||||||
.c_va_copy => try cg.airVaCopy(inst),
|
.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
|
|||||||
.register,
|
.register,
|
||||||
.register_offset,
|
.register_offset,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.lea_pcrel,
|
||||||
.lea_direct,
|
.lea_direct,
|
||||||
.lea_got,
|
.lea_got,
|
||||||
.lea_frame,
|
.lea_frame,
|
||||||
@ -169196,6 +169246,7 @@ fn load(self: *CodeGen, dst_mcv: MCValue, ptr_ty: Type, ptr_mcv: MCValue) InnerE
|
|||||||
.memory,
|
.memory,
|
||||||
.indirect,
|
.indirect,
|
||||||
.load_symbol,
|
.load_symbol,
|
||||||
|
.load_pcrel,
|
||||||
.load_direct,
|
.load_direct,
|
||||||
.load_got,
|
.load_got,
|
||||||
.load_frame,
|
.load_frame,
|
||||||
@ -169407,6 +169458,7 @@ fn store(
|
|||||||
.register,
|
.register,
|
||||||
.register_offset,
|
.register_offset,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.lea_pcrel,
|
||||||
.lea_direct,
|
.lea_direct,
|
||||||
.lea_got,
|
.lea_got,
|
||||||
.lea_frame,
|
.lea_frame,
|
||||||
@ -169414,6 +169466,7 @@ fn store(
|
|||||||
.memory,
|
.memory,
|
||||||
.indirect,
|
.indirect,
|
||||||
.load_symbol,
|
.load_symbol,
|
||||||
|
.load_pcrel,
|
||||||
.load_direct,
|
.load_direct,
|
||||||
.load_got,
|
.load_got,
|
||||||
.load_frame,
|
.load_frame,
|
||||||
@ -169883,6 +169936,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
|
|||||||
.register_overflow,
|
.register_overflow,
|
||||||
.register_mask,
|
.register_mask,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.lea_pcrel,
|
||||||
.lea_direct,
|
.lea_direct,
|
||||||
.lea_got,
|
.lea_got,
|
||||||
.lea_frame,
|
.lea_frame,
|
||||||
@ -169892,7 +169946,7 @@ fn genUnOpMir(self: *CodeGen, mir_tag: Mir.Inst.FixedTag, dst_ty: Type, dst_mcv:
|
|||||||
=> unreachable, // unmodifiable destination
|
=> unreachable, // unmodifiable destination
|
||||||
.register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
|
.register => |dst_reg| try self.asmRegister(mir_tag, registerAlias(dst_reg, abi_size)),
|
||||||
.register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented
|
.register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented
|
||||||
.memory, .load_symbol, .load_got, .load_direct => {
|
.memory, .load_symbol, .load_pcrel, .load_got, .load_direct => {
|
||||||
const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
|
const addr_reg = try self.register_manager.allocReg(null, abi.RegisterClass.gp);
|
||||||
const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
|
const addr_reg_lock = self.register_manager.lockRegAssumeUnused(addr_reg);
|
||||||
defer self.register_manager.unlockReg(addr_reg_lock);
|
defer self.register_manager.unlockReg(addr_reg_lock);
|
||||||
@ -171552,6 +171606,8 @@ fn genBinOp(
|
|||||||
.register_mask,
|
.register_mask,
|
||||||
.load_symbol,
|
.load_symbol,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.load_pcrel,
|
||||||
|
.lea_pcrel,
|
||||||
.load_direct,
|
.load_direct,
|
||||||
.lea_direct,
|
.lea_direct,
|
||||||
.load_got,
|
.load_got,
|
||||||
@ -172740,6 +172796,7 @@ fn genBinOpMir(
|
|||||||
.lea_got,
|
.lea_got,
|
||||||
.lea_frame,
|
.lea_frame,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.lea_pcrel,
|
||||||
.elementwise_args,
|
.elementwise_args,
|
||||||
.reserved_frame,
|
.reserved_frame,
|
||||||
.air_ref,
|
.air_ref,
|
||||||
@ -172831,6 +172888,8 @@ fn genBinOpMir(
|
|||||||
.indirect,
|
.indirect,
|
||||||
.load_symbol,
|
.load_symbol,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.load_pcrel,
|
||||||
|
.lea_pcrel,
|
||||||
.load_direct,
|
.load_direct,
|
||||||
.lea_direct,
|
.lea_direct,
|
||||||
.load_got,
|
.load_got,
|
||||||
@ -172906,7 +172965,7 @@ fn genBinOpMir(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
.memory, .indirect, .load_symbol, .load_got, .load_direct, .load_frame => {
|
.memory, .indirect, .load_symbol, .load_pcrel, .load_got, .load_direct, .load_frame => {
|
||||||
const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock };
|
const OpInfo = ?struct { addr_reg: Register, addr_lock: RegisterLock };
|
||||||
const limb_abi_size: u32 = @min(abi_size, 8);
|
const limb_abi_size: u32 = @min(abi_size, 8);
|
||||||
|
|
||||||
@ -172953,8 +173012,9 @@ fn genBinOpMir(
|
|||||||
.load_frame,
|
.load_frame,
|
||||||
.lea_frame,
|
.lea_frame,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.lea_pcrel,
|
||||||
=> null,
|
=> null,
|
||||||
.memory, .load_symbol, .load_got, .load_direct => src: {
|
.memory, .load_symbol, .load_pcrel, .load_got, .load_direct => src: {
|
||||||
switch (resolved_src_mcv) {
|
switch (resolved_src_mcv) {
|
||||||
.memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr))) != null and
|
.memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr))) != null and
|
||||||
std.math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null)
|
std.math.cast(i32, @as(i64, @bitCast(addr)) + abi_size - limb_abi_size) != null)
|
||||||
@ -173093,6 +173153,8 @@ fn genBinOpMir(
|
|||||||
.indirect,
|
.indirect,
|
||||||
.load_symbol,
|
.load_symbol,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.load_pcrel,
|
||||||
|
.lea_pcrel,
|
||||||
.load_direct,
|
.load_direct,
|
||||||
.lea_direct,
|
.lea_direct,
|
||||||
.load_got,
|
.load_got,
|
||||||
@ -173160,6 +173222,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
|
|||||||
.register_overflow,
|
.register_overflow,
|
||||||
.register_mask,
|
.register_mask,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.lea_pcrel,
|
||||||
.lea_direct,
|
.lea_direct,
|
||||||
.lea_got,
|
.lea_got,
|
||||||
.lea_frame,
|
.lea_frame,
|
||||||
@ -173222,6 +173285,8 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
|
|||||||
.eflags,
|
.eflags,
|
||||||
.load_symbol,
|
.load_symbol,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.load_pcrel,
|
||||||
|
.lea_pcrel,
|
||||||
.load_direct,
|
.load_direct,
|
||||||
.lea_direct,
|
.lea_direct,
|
||||||
.load_got,
|
.load_got,
|
||||||
@ -173281,7 +173346,7 @@ fn genIntMulComplexOpMir(self: *CodeGen, dst_ty: Type, dst_mcv: MCValue, src_mcv
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented
|
.register_pair, .register_triple, .register_quadruple => unreachable, // unimplemented
|
||||||
.memory, .indirect, .load_symbol, .load_direct, .load_got, .load_frame => {
|
.memory, .indirect, .load_symbol, .load_pcrel, .load_direct, .load_got, .load_frame => {
|
||||||
const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
|
const tmp_reg = try self.copyToTmpRegister(dst_ty, dst_mcv);
|
||||||
const tmp_mcv = MCValue{ .register = tmp_reg };
|
const tmp_mcv = MCValue{ .register = tmp_reg };
|
||||||
const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
|
const tmp_lock = self.register_manager.lockRegAssumeUnused(tmp_reg);
|
||||||
@ -173450,7 +173515,8 @@ fn genLocalDebugInfo(
|
|||||||
.disp = frame_addr.off,
|
.disp = frame_addr.off,
|
||||||
} },
|
} },
|
||||||
}),
|
}),
|
||||||
.lea_symbol => |sym_off| try self.asmAirMemory(.dbg_local, inst, .{
|
// debug info should explicitly ignore pcrel requirements
|
||||||
|
.lea_symbol, .lea_pcrel => |sym_off| try self.asmAirMemory(.dbg_local, inst, .{
|
||||||
.base = .{ .reloc = sym_off.sym_index },
|
.base = .{ .reloc = sym_off.sym_index },
|
||||||
.mod = .{ .rm = .{
|
.mod = .{ .rm = .{
|
||||||
.size = .qword,
|
.size = .qword,
|
||||||
@ -174108,12 +174174,13 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
|
|||||||
.lea_got,
|
.lea_got,
|
||||||
.lea_frame,
|
.lea_frame,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.lea_pcrel,
|
||||||
.elementwise_args,
|
.elementwise_args,
|
||||||
.reserved_frame,
|
.reserved_frame,
|
||||||
.air_ref,
|
.air_ref,
|
||||||
=> unreachable,
|
=> unreachable,
|
||||||
.register, .register_pair, .register_triple, .register_quadruple, .load_frame => null,
|
.register, .register_pair, .register_triple, .register_quadruple, .load_frame => null,
|
||||||
.memory, .load_symbol, .load_got, .load_direct => dst: {
|
.memory, .load_symbol, .load_pcrel, .load_got, .load_direct => dst: {
|
||||||
switch (resolved_dst_mcv) {
|
switch (resolved_dst_mcv) {
|
||||||
.memory => |addr| if (std.math.cast(
|
.memory => |addr| if (std.math.cast(
|
||||||
i32,
|
i32,
|
||||||
@ -174122,7 +174189,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
|
|||||||
i32,
|
i32,
|
||||||
@as(i64, @bitCast(addr)) + abi_size - 8,
|
@as(i64, @bitCast(addr)) + abi_size - 8,
|
||||||
) != null) break :dst null,
|
) != null) break :dst null,
|
||||||
.load_symbol, .load_got, .load_direct => {},
|
.load_symbol, .load_pcrel, .load_got, .load_direct => {},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174160,6 +174227,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
|
|||||||
.register_mask,
|
.register_mask,
|
||||||
.indirect,
|
.indirect,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.lea_pcrel,
|
||||||
.lea_direct,
|
.lea_direct,
|
||||||
.lea_got,
|
.lea_got,
|
||||||
.lea_frame,
|
.lea_frame,
|
||||||
@ -174168,7 +174236,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
|
|||||||
.air_ref,
|
.air_ref,
|
||||||
=> unreachable,
|
=> unreachable,
|
||||||
.register_pair, .register_triple, .register_quadruple, .load_frame => null,
|
.register_pair, .register_triple, .register_quadruple, .load_frame => null,
|
||||||
.memory, .load_symbol, .load_got, .load_direct => src: {
|
.memory, .load_symbol, .load_pcrel, .load_got, .load_direct => src: {
|
||||||
switch (resolved_src_mcv) {
|
switch (resolved_src_mcv) {
|
||||||
.memory => |addr| if (std.math.cast(
|
.memory => |addr| if (std.math.cast(
|
||||||
i32,
|
i32,
|
||||||
@ -174177,7 +174245,7 @@ fn airCmp(self: *CodeGen, inst: Air.Inst.Index, op: std.math.CompareOperator) !v
|
|||||||
i32,
|
i32,
|
||||||
@as(i64, @bitCast(addr)) + abi_size - 8,
|
@as(i64, @bitCast(addr)) + abi_size - 8,
|
||||||
) != null) break :src null,
|
) != null) break :src null,
|
||||||
.load_symbol, .load_got, .load_direct => {},
|
.load_symbol, .load_pcrel, .load_got, .load_direct => {},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174568,6 +174636,7 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)
|
|||||||
.lea_direct,
|
.lea_direct,
|
||||||
.lea_got,
|
.lea_got,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.lea_pcrel,
|
||||||
.elementwise_args,
|
.elementwise_args,
|
||||||
.reserved_frame,
|
.reserved_frame,
|
||||||
.air_ref,
|
.air_ref,
|
||||||
@ -174616,6 +174685,7 @@ fn isNull(self: *CodeGen, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue)
|
|||||||
|
|
||||||
.memory,
|
.memory,
|
||||||
.load_symbol,
|
.load_symbol,
|
||||||
|
.load_pcrel,
|
||||||
.load_got,
|
.load_got,
|
||||||
.load_direct,
|
.load_direct,
|
||||||
=> {
|
=> {
|
||||||
@ -174947,8 +175017,7 @@ fn lowerSwitchBr(
|
|||||||
) !void {
|
) !void {
|
||||||
const zcu = cg.pt.zcu;
|
const zcu = cg.pt.zcu;
|
||||||
const condition_ty = cg.typeOf(switch_br.operand);
|
const condition_ty = cg.typeOf(switch_br.operand);
|
||||||
const condition_int_info = cg.intInfo(condition_ty).?;
|
const unsigned_condition_ty = try cg.pt.intType(.unsigned, cg.intInfo(condition_ty).?.bits);
|
||||||
const condition_int_ty = try cg.pt.intType(condition_int_info.signedness, condition_int_info.bits);
|
|
||||||
|
|
||||||
const ExpectedContents = extern struct {
|
const ExpectedContents = extern struct {
|
||||||
liveness_deaths: [1 << 8 | 1]Air.Inst.Index,
|
liveness_deaths: [1 << 8 | 1]Air.Inst.Index,
|
||||||
@ -175019,8 +175088,8 @@ fn lowerSwitchBr(
|
|||||||
.{ .air_ref = Air.internedToRef(min.?.toIntern()) },
|
.{ .air_ref = Air.internedToRef(min.?.toIntern()) },
|
||||||
);
|
);
|
||||||
const else_reloc = if (switch_br.else_body_len > 0) else_reloc: {
|
const else_reloc = if (switch_br.else_body_len > 0) else_reloc: {
|
||||||
var cond_temp = try cg.tempInit(condition_ty, condition_index);
|
var cond_temp = try cg.tempInit(unsigned_condition_ty, condition_index);
|
||||||
var table_max_temp = try cg.tempFromValue(try cg.pt.intValue(condition_int_ty, table_len - 1));
|
var table_max_temp = try cg.tempFromValue(try cg.pt.intValue(unsigned_condition_ty, table_len - 1));
|
||||||
const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, cg) catch |err| switch (err) {
|
const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, cg) catch |err| switch (err) {
|
||||||
error.SelectFailed => unreachable,
|
error.SelectFailed => unreachable,
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
@ -175348,8 +175417,7 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void {
|
|||||||
|
|
||||||
if (self.loop_switches.getPtr(br.block_inst)) |table| {
|
if (self.loop_switches.getPtr(br.block_inst)) |table| {
|
||||||
const condition_ty = self.typeOf(br.operand);
|
const condition_ty = self.typeOf(br.operand);
|
||||||
const condition_int_info = self.intInfo(condition_ty).?;
|
const unsigned_condition_ty = try self.pt.intType(.unsigned, self.intInfo(condition_ty).?.bits);
|
||||||
const condition_int_ty = try self.pt.intType(condition_int_info.signedness, condition_int_info.bits);
|
|
||||||
const condition_mcv = block_tracking.short;
|
const condition_mcv = block_tracking.short;
|
||||||
try self.spillEflagsIfOccupied();
|
try self.spillEflagsIfOccupied();
|
||||||
if (table.min.orderAgainstZero(self.pt.zcu).compare(.neq)) try self.genBinOpMir(
|
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 {
|
|||||||
switch (table.else_relocs) {
|
switch (table.else_relocs) {
|
||||||
.@"unreachable" => {},
|
.@"unreachable" => {},
|
||||||
.forward => |*else_relocs| {
|
.forward => |*else_relocs| {
|
||||||
var cond_temp = try self.tempInit(condition_ty, condition_mcv);
|
var cond_temp = try self.tempInit(unsigned_condition_ty, condition_mcv);
|
||||||
var table_max_temp = try self.tempFromValue(try self.pt.intValue(condition_int_ty, table.len - 1));
|
var table_max_temp = try self.tempFromValue(try self.pt.intValue(unsigned_condition_ty, table.len - 1));
|
||||||
const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, self) catch |err| switch (err) {
|
const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, self) catch |err| switch (err) {
|
||||||
error.SelectFailed => unreachable,
|
error.SelectFailed => unreachable,
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
@ -175373,8 +175441,8 @@ fn airSwitchDispatch(self: *CodeGen, inst: Air.Inst.Index) !void {
|
|||||||
try cc_temp.die(self);
|
try cc_temp.die(self);
|
||||||
},
|
},
|
||||||
.backward => |else_reloc| {
|
.backward => |else_reloc| {
|
||||||
var cond_temp = try self.tempInit(condition_ty, condition_mcv);
|
var cond_temp = try self.tempInit(unsigned_condition_ty, condition_mcv);
|
||||||
var table_max_temp = try self.tempFromValue(try self.pt.intValue(condition_int_ty, table.len - 1));
|
var table_max_temp = try self.tempFromValue(try self.pt.intValue(unsigned_condition_ty, table.len - 1));
|
||||||
const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, self) catch |err| switch (err) {
|
const cc_temp = cond_temp.cmpInts(.gt, &table_max_temp, self) catch |err| switch (err) {
|
||||||
error.SelectFailed => unreachable,
|
error.SelectFailed => unreachable,
|
||||||
else => |e| return e,
|
else => |e| return e,
|
||||||
@ -176625,6 +176693,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
|
|||||||
.lea_got,
|
.lea_got,
|
||||||
.lea_frame,
|
.lea_frame,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.lea_pcrel,
|
||||||
.elementwise_args,
|
.elementwise_args,
|
||||||
.reserved_frame,
|
.reserved_frame,
|
||||||
.air_ref,
|
.air_ref,
|
||||||
@ -176719,7 +176788,7 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
.load_symbol, .load_direct, .load_got => {
|
.load_symbol, .load_pcrel, .load_direct, .load_got => {
|
||||||
const src_addr_reg =
|
const src_addr_reg =
|
||||||
(try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
|
(try self.register_manager.allocReg(null, abi.RegisterClass.gp)).to64();
|
||||||
const src_addr_lock = self.register_manager.lockRegAssumeUnused(src_addr_reg);
|
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
|
|||||||
.undef => if (opts.safety and part_i > 0) .{ .register = dst_regs[0] } else .undef,
|
.undef => if (opts.safety and part_i > 0) .{ .register = dst_regs[0] } else .undef,
|
||||||
dst_tag => |src_regs| .{ .register = src_regs[part_i] },
|
dst_tag => |src_regs| .{ .register = src_regs[part_i] },
|
||||||
.memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(),
|
.memory, .indirect, .load_frame => src_mcv.address().offset(part_disp).deref(),
|
||||||
.load_symbol, .load_direct, .load_got => .{ .indirect = .{
|
.load_symbol, .load_pcrel, .load_direct, .load_got => .{ .indirect = .{
|
||||||
.reg = src_info.?.addr_reg,
|
.reg = src_info.?.addr_reg,
|
||||||
.off = part_disp,
|
.off = part_disp,
|
||||||
} },
|
} },
|
||||||
@ -176773,11 +176842,11 @@ fn genCopy(self: *CodeGen, ty: Type, dst_mcv: MCValue, src_mcv: MCValue, opts: C
|
|||||||
src_mcv,
|
src_mcv,
|
||||||
opts,
|
opts,
|
||||||
),
|
),
|
||||||
.memory, .load_symbol, .load_direct, .load_got => {
|
.memory, .load_symbol, .load_pcrel, .load_direct, .load_got => {
|
||||||
switch (dst_mcv) {
|
switch (dst_mcv) {
|
||||||
.memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
|
.memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
|
||||||
return self.genSetMem(.{ .reg = .ds }, small_addr, ty, src_mcv, opts),
|
return self.genSetMem(.{ .reg = .ds }, small_addr, ty, src_mcv, opts),
|
||||||
.load_symbol, .load_direct, .load_got => {},
|
.load_symbol, .load_pcrel, .load_direct, .load_got => {},
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177234,7 +177303,7 @@ fn genSetReg(
|
|||||||
if (src_reg_mask.info.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size));
|
if (src_reg_mask.info.inverted) try self.asmRegister(.{ ._, .not }, registerAlias(bits_reg, abi_size));
|
||||||
try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{});
|
try self.genSetReg(dst_reg, ty, .{ .register = bits_reg }, .{});
|
||||||
},
|
},
|
||||||
.memory, .load_symbol, .load_direct, .load_got => {
|
.memory, .load_symbol, .load_pcrel, .load_direct, .load_got => {
|
||||||
switch (src_mcv) {
|
switch (src_mcv) {
|
||||||
.memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
|
.memory => |addr| if (std.math.cast(i32, @as(i64, @bitCast(addr)))) |small_addr|
|
||||||
return (try self.moveStrategy(
|
return (try self.moveStrategy(
|
||||||
@ -177263,6 +177332,21 @@ fn genSetReg(
|
|||||||
.segment, .mmx, .ip, .cr, .dr => unreachable,
|
.segment, .mmx, .ip, .cr, .dr => unreachable,
|
||||||
.x87, .sse => {},
|
.x87, .sse => {},
|
||||||
},
|
},
|
||||||
|
.load_pcrel => |sym_off| switch (dst_reg.class()) {
|
||||||
|
.general_purpose, .gphi => {
|
||||||
|
assert(sym_off.off == 0);
|
||||||
|
try self.asmRegisterMemory(.{ ._, .mov }, dst_alias, .{
|
||||||
|
.base = .{ .pcrel = sym_off.sym_index },
|
||||||
|
.mod = .{ .rm = .{
|
||||||
|
.size = self.memSize(ty),
|
||||||
|
.disp = sym_off.off,
|
||||||
|
} },
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
.segment, .mmx, .ip, .cr, .dr => unreachable,
|
||||||
|
.x87, .sse => {},
|
||||||
|
},
|
||||||
.load_direct => |sym_index| switch (dst_reg.class()) {
|
.load_direct => |sym_index| switch (dst_reg.class()) {
|
||||||
.general_purpose, .gphi => {
|
.general_purpose, .gphi => {
|
||||||
_ = try self.addInst(.{
|
_ = try self.addInst(.{
|
||||||
@ -177313,6 +177397,28 @@ fn genSetReg(
|
|||||||
@tagName(self.bin_file.tag),
|
@tagName(self.bin_file.tag),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
.lea_pcrel => |sym_off| switch (self.bin_file.tag) {
|
||||||
|
.elf, .macho => {
|
||||||
|
try self.asmRegisterMemory(
|
||||||
|
.{ ._, .lea },
|
||||||
|
dst_reg.to64(),
|
||||||
|
.{
|
||||||
|
.base = .{ .pcrel = sym_off.sym_index },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (sym_off.off != 0) try self.asmRegisterMemory(
|
||||||
|
.{ ._, .lea },
|
||||||
|
dst_reg.to64(),
|
||||||
|
.{
|
||||||
|
.base = .{ .reg = dst_reg.to64() },
|
||||||
|
.mod = .{ .rm = .{ .disp = sym_off.off } },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
else => return self.fail("TODO emit symbol sequence on {s}", .{
|
||||||
|
@tagName(self.bin_file.tag),
|
||||||
|
}),
|
||||||
|
},
|
||||||
.lea_direct, .lea_got => |sym_index| _ = try self.addInst(.{
|
.lea_direct, .lea_got => |sym_index| _ = try self.addInst(.{
|
||||||
.tag = switch (src_mcv) {
|
.tag = switch (src_mcv) {
|
||||||
.lea_direct => .lea,
|
.lea_direct => .lea,
|
||||||
@ -177350,6 +177456,7 @@ fn genSetMem(
|
|||||||
.frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } },
|
.frame => |base_frame_index| .{ .lea_frame = .{ .index = base_frame_index, .off = disp } },
|
||||||
.table, .rip_inst => unreachable,
|
.table, .rip_inst => unreachable,
|
||||||
.reloc => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index, .off = disp } },
|
.reloc => |sym_index| .{ .lea_symbol = .{ .sym_index = sym_index, .off = disp } },
|
||||||
|
.pcrel => |sym_index| .{ .lea_pcrel = .{ .sym_index = sym_index, .off = disp } },
|
||||||
};
|
};
|
||||||
switch (src_mcv) {
|
switch (src_mcv) {
|
||||||
.none,
|
.none,
|
||||||
@ -177466,7 +177573,7 @@ fn genSetMem(
|
|||||||
.off = disp,
|
.off = disp,
|
||||||
}).compare(.gte, src_align),
|
}).compare(.gte, src_align),
|
||||||
.table, .rip_inst => unreachable,
|
.table, .rip_inst => unreachable,
|
||||||
.reloc => false,
|
.reloc, .pcrel => false,
|
||||||
})).write(
|
})).write(
|
||||||
self,
|
self,
|
||||||
.{ .base = base, .mod = .{ .rm = .{
|
.{ .base = base, .mod = .{ .rm = .{
|
||||||
@ -177557,6 +177664,8 @@ fn genSetMem(
|
|||||||
.lea_frame,
|
.lea_frame,
|
||||||
.load_symbol,
|
.load_symbol,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.load_pcrel,
|
||||||
|
.lea_pcrel,
|
||||||
=> switch (abi_size) {
|
=> switch (abi_size) {
|
||||||
0 => {},
|
0 => {},
|
||||||
1, 2, 4, 8 => {
|
1, 2, 4, 8 => {
|
||||||
@ -178110,7 +178219,7 @@ fn airCmpxchg(self: *CodeGen, inst: Air.Inst.Index) !void {
|
|||||||
.off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
|
.off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
|
||||||
}
|
}
|
||||||
const ptr_lock = switch (ptr_mem.base) {
|
const ptr_lock = switch (ptr_mem.base) {
|
||||||
.none, .frame, .reloc => null,
|
.none, .frame, .reloc, .pcrel => null,
|
||||||
.reg => |reg| self.register_manager.lockReg(reg),
|
.reg => |reg| self.register_manager.lockReg(reg),
|
||||||
.table, .rip_inst => unreachable,
|
.table, .rip_inst => unreachable,
|
||||||
};
|
};
|
||||||
@ -178193,7 +178302,7 @@ fn atomicOp(
|
|||||||
.off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
|
.off => return self.fail("TODO airCmpxchg with {s}", .{@tagName(ptr_mcv)}),
|
||||||
}
|
}
|
||||||
const mem_lock = switch (ptr_mem.base) {
|
const mem_lock = switch (ptr_mem.base) {
|
||||||
.none, .frame, .reloc => null,
|
.none, .frame, .reloc, .pcrel => null,
|
||||||
.reg => |reg| self.register_manager.lockReg(reg),
|
.reg => |reg| self.register_manager.lockReg(reg),
|
||||||
.table, .rip_inst => unreachable,
|
.table, .rip_inst => unreachable,
|
||||||
};
|
};
|
||||||
@ -182266,6 +182375,8 @@ const Temp = struct {
|
|||||||
.memory,
|
.memory,
|
||||||
.load_symbol,
|
.load_symbol,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.load_pcrel,
|
||||||
|
.lea_pcrel,
|
||||||
.indirect,
|
.indirect,
|
||||||
.load_direct,
|
.load_direct,
|
||||||
.lea_direct,
|
.lea_direct,
|
||||||
@ -182427,6 +182538,22 @@ const Temp = struct {
|
|||||||
assert(limb_index == 0);
|
assert(limb_index == 0);
|
||||||
new_temp_index.tracking(cg).* = .init(.{ .lea_symbol = sym_off });
|
new_temp_index.tracking(cg).* = .init(.{ .lea_symbol = sym_off });
|
||||||
},
|
},
|
||||||
|
.load_pcrel => |sym_off| {
|
||||||
|
const new_reg =
|
||||||
|
try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
|
||||||
|
new_temp_index.tracking(cg).* = .init(.{ .register = new_reg });
|
||||||
|
try cg.asmRegisterMemory(.{ ._, .mov }, new_reg.to64(), .{
|
||||||
|
.base = .{ .pcrel = sym_off.sym_index },
|
||||||
|
.mod = .{ .rm = .{
|
||||||
|
.size = .qword,
|
||||||
|
.disp = sym_off.off + @as(u31, limb_index) * 8,
|
||||||
|
} },
|
||||||
|
});
|
||||||
|
},
|
||||||
|
.lea_pcrel => |sym_off| {
|
||||||
|
assert(limb_index == 0);
|
||||||
|
new_temp_index.tracking(cg).* = .init(.{ .lea_pcrel = sym_off });
|
||||||
|
},
|
||||||
.load_frame => |frame_addr| {
|
.load_frame => |frame_addr| {
|
||||||
const new_reg =
|
const new_reg =
|
||||||
try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
|
try cg.register_manager.allocReg(new_temp_index.toIndex(), abi.RegisterClass.gp);
|
||||||
@ -182721,11 +182848,12 @@ const Temp = struct {
|
|||||||
.memory,
|
.memory,
|
||||||
.indirect,
|
.indirect,
|
||||||
.load_symbol,
|
.load_symbol,
|
||||||
|
.load_pcrel,
|
||||||
.load_direct,
|
.load_direct,
|
||||||
.load_got,
|
.load_got,
|
||||||
.load_frame,
|
.load_frame,
|
||||||
=> return temp.toRegClass(true, .general_purpose, cg),
|
=> return temp.toRegClass(true, .general_purpose, cg),
|
||||||
.lea_symbol => |sym_off| {
|
.lea_symbol, .lea_pcrel => |sym_off| {
|
||||||
const off = sym_off.off;
|
const off = sym_off.off;
|
||||||
// hack around linker relocation bugs
|
// hack around linker relocation bugs
|
||||||
if (false and off == 0) return false;
|
if (false and off == 0) return false;
|
||||||
@ -187464,6 +187592,8 @@ const Temp = struct {
|
|||||||
.memory,
|
.memory,
|
||||||
.load_symbol,
|
.load_symbol,
|
||||||
.lea_symbol,
|
.lea_symbol,
|
||||||
|
.load_pcrel,
|
||||||
|
.lea_pcrel,
|
||||||
.indirect,
|
.indirect,
|
||||||
.load_direct,
|
.load_direct,
|
||||||
.lea_direct,
|
.lea_direct,
|
||||||
@ -190044,6 +190174,7 @@ const Select = struct {
|
|||||||
.register => |base_reg| .{ .reg = base_reg.toSize(.ptr, s.cg.target) },
|
.register => |base_reg| .{ .reg = base_reg.toSize(.ptr, s.cg.target) },
|
||||||
.register_offset => |base_reg_off| .{ .reg = base_reg_off.reg.toSize(.ptr, s.cg.target) },
|
.register_offset => |base_reg_off| .{ .reg = base_reg_off.reg.toSize(.ptr, s.cg.target) },
|
||||||
.lea_symbol => |base_sym_off| .{ .reloc = base_sym_off.sym_index },
|
.lea_symbol => |base_sym_off| .{ .reloc = base_sym_off.sym_index },
|
||||||
|
.lea_pcrel => |base_sym_off| .{ .pcrel = base_sym_off.sym_index },
|
||||||
},
|
},
|
||||||
.mod = .{ .rm = .{
|
.mod = .{ .rm = .{
|
||||||
.size = op.flags.base.size,
|
.size = op.flags.base.size,
|
||||||
|
|||||||
@ -189,12 +189,12 @@ pub fn emitMir(emit: *Emit) Error!void {
|
|||||||
.r_addend = lowered_relocs[0].off,
|
.r_addend = lowered_relocs[0].off,
|
||||||
}, zo);
|
}, zo);
|
||||||
},
|
},
|
||||||
.linker_reloc => |sym_index| if (emit.lower.bin_file.cast(.elf)) |elf_file| {
|
.linker_reloc, .linker_pcrel => |sym_index| if (emit.lower.bin_file.cast(.elf)) |elf_file| {
|
||||||
const zo = elf_file.zigObjectPtr().?;
|
const zo = elf_file.zigObjectPtr().?;
|
||||||
const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
|
const atom = zo.symbol(emit.atom_index).atom(elf_file).?;
|
||||||
const sym = zo.symbol(sym_index);
|
const sym = zo.symbol(sym_index);
|
||||||
if (emit.lower.pic) {
|
if (emit.lower.pic) {
|
||||||
const r_type: u32 = if (sym.flags.is_extern_ptr)
|
const r_type: u32 = if (sym.flags.is_extern_ptr and lowered_relocs[0].target != .linker_pcrel)
|
||||||
@intFromEnum(std.elf.R_X86_64.GOTPCREL)
|
@intFromEnum(std.elf.R_X86_64.GOTPCREL)
|
||||||
else
|
else
|
||||||
@intFromEnum(std.elf.R_X86_64.PC32);
|
@intFromEnum(std.elf.R_X86_64.PC32);
|
||||||
@ -218,7 +218,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
|||||||
const zo = macho_file.getZigObject().?;
|
const zo = macho_file.getZigObject().?;
|
||||||
const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;
|
const atom = zo.symbols.items[emit.atom_index].getAtom(macho_file).?;
|
||||||
const sym = &zo.symbols.items[sym_index];
|
const sym = &zo.symbols.items[sym_index];
|
||||||
const @"type": link.File.MachO.Relocation.Type = if (sym.flags.is_extern_ptr)
|
const @"type": link.File.MachO.Relocation.Type = if (sym.flags.is_extern_ptr and lowered_relocs[0].target != .linker_pcrel)
|
||||||
.got_load
|
.got_load
|
||||||
else if (sym.flags.tlv)
|
else if (sym.flags.tlv)
|
||||||
.tlv
|
.tlv
|
||||||
@ -378,9 +378,9 @@ pub fn emitMir(emit: *Emit) Error!void {
|
|||||||
};
|
};
|
||||||
break :stack_value &loc_buf[0];
|
break :stack_value &loc_buf[0];
|
||||||
} } },
|
} } },
|
||||||
.pseudo_dbg_local_as => .{ mir_inst.data.as.air_inst, .{ .addr = .{
|
.pseudo_dbg_local_as => .{ mir_inst.data.as.air_inst, .{
|
||||||
.sym = mir_inst.data.as.sym_index,
|
.addr_reloc = mir_inst.data.as.sym_index,
|
||||||
} } },
|
} },
|
||||||
.pseudo_dbg_local_aso => loc: {
|
.pseudo_dbg_local_aso => loc: {
|
||||||
const sym_off = emit.lower.mir.extraData(
|
const sym_off = emit.lower.mir.extraData(
|
||||||
bits.SymbolOffset,
|
bits.SymbolOffset,
|
||||||
@ -388,7 +388,7 @@ pub fn emitMir(emit: *Emit) Error!void {
|
|||||||
).data;
|
).data;
|
||||||
break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{
|
break :loc .{ mir_inst.data.ax.air_inst, .{ .plus = .{
|
||||||
sym: {
|
sym: {
|
||||||
loc_buf[0] = .{ .addr = .{ .sym = sym_off.sym_index } };
|
loc_buf[0] = .{ .addr_reloc = sym_off.sym_index };
|
||||||
break :sym &loc_buf[0];
|
break :sym &loc_buf[0];
|
||||||
},
|
},
|
||||||
off: {
|
off: {
|
||||||
@ -437,7 +437,8 @@ pub fn emitMir(emit: *Emit) Error!void {
|
|||||||
.none => .{ .constu = 0 },
|
.none => .{ .constu = 0 },
|
||||||
.reg => |reg| .{ .breg = reg.dwarfNum() },
|
.reg => |reg| .{ .breg = reg.dwarfNum() },
|
||||||
.frame, .table, .rip_inst => unreachable,
|
.frame, .table, .rip_inst => unreachable,
|
||||||
.reloc => |sym_index| .{ .addr = .{ .sym = sym_index } },
|
.reloc => |sym_index| .{ .addr_reloc = sym_index },
|
||||||
|
.pcrel => unreachable,
|
||||||
};
|
};
|
||||||
break :base &loc_buf[0];
|
break :base &loc_buf[0];
|
||||||
},
|
},
|
||||||
|
|||||||
@ -66,6 +66,7 @@ pub const Reloc = struct {
|
|||||||
inst: Mir.Inst.Index,
|
inst: Mir.Inst.Index,
|
||||||
table,
|
table,
|
||||||
linker_reloc: u32,
|
linker_reloc: u32,
|
||||||
|
linker_pcrel: u32,
|
||||||
linker_tlsld: u32,
|
linker_tlsld: u32,
|
||||||
linker_dtpoff: u32,
|
linker_dtpoff: u32,
|
||||||
linker_extern_fn: u32,
|
linker_extern_fn: u32,
|
||||||
@ -421,9 +422,9 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
|
|||||||
for (emit_ops, ops, 0..) |*emit_op, op, op_index| {
|
for (emit_ops, ops, 0..) |*emit_op, op, op_index| {
|
||||||
emit_op.* = switch (op) {
|
emit_op.* = switch (op) {
|
||||||
else => op,
|
else => op,
|
||||||
.mem => |mem_op| switch (mem_op.base()) {
|
.mem => |mem_op| op: switch (mem_op.base()) {
|
||||||
else => op,
|
else => op,
|
||||||
.reloc => |sym_index| op: {
|
.reloc => |sym_index| {
|
||||||
assert(prefix == .none);
|
assert(prefix == .none);
|
||||||
assert(mem_op.sib.disp == 0);
|
assert(mem_op.sib.disp == 0);
|
||||||
assert(mem_op.sib.scale_index.scale == 0);
|
assert(mem_op.sib.scale_index.scale == 0);
|
||||||
@ -559,6 +560,22 @@ fn emit(lower: *Lower, prefix: Prefix, mnemonic: Mnemonic, ops: []const Operand)
|
|||||||
return lower.fail("TODO: bin format '{s}'", .{@tagName(lower.bin_file.tag)});
|
return lower.fail("TODO: bin format '{s}'", .{@tagName(lower.bin_file.tag)});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
.pcrel => |sym_index| {
|
||||||
|
assert(prefix == .none);
|
||||||
|
assert(mem_op.sib.disp == 0);
|
||||||
|
assert(mem_op.sib.scale_index.scale == 0);
|
||||||
|
|
||||||
|
_ = lower.reloc(@intCast(op_index), .{ .linker_pcrel = sym_index }, 0);
|
||||||
|
break :op switch (lower.bin_file.tag) {
|
||||||
|
.elf => op,
|
||||||
|
.macho => switch (mnemonic) {
|
||||||
|
.lea => .{ .mem = Memory.initRip(.none, 0) },
|
||||||
|
.mov => .{ .mem = Memory.initRip(mem_op.sib.ptr_size, 0) },
|
||||||
|
else => unreachable,
|
||||||
|
},
|
||||||
|
else => |tag| return lower.fail("TODO: bin format '{s}'", .{@tagName(tag)}),
|
||||||
|
};
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1866,7 +1866,7 @@ pub const Memory = struct {
|
|||||||
.none, .table => undefined,
|
.none, .table => undefined,
|
||||||
.reg => |reg| @intFromEnum(reg),
|
.reg => |reg| @intFromEnum(reg),
|
||||||
.frame => |frame_index| @intFromEnum(frame_index),
|
.frame => |frame_index| @intFromEnum(frame_index),
|
||||||
.reloc => |sym_index| sym_index,
|
.reloc, .pcrel => |sym_index| sym_index,
|
||||||
.rip_inst => |inst_index| inst_index,
|
.rip_inst => |inst_index| inst_index,
|
||||||
},
|
},
|
||||||
.off = switch (mem.mod) {
|
.off = switch (mem.mod) {
|
||||||
@ -1895,6 +1895,7 @@ pub const Memory = struct {
|
|||||||
.frame => .{ .frame = @enumFromInt(mem.base) },
|
.frame => .{ .frame = @enumFromInt(mem.base) },
|
||||||
.table => .table,
|
.table => .table,
|
||||||
.reloc => .{ .reloc = mem.base },
|
.reloc => .{ .reloc = mem.base },
|
||||||
|
.pcrel => .{ .pcrel = mem.base },
|
||||||
.rip_inst => .{ .rip_inst = mem.base },
|
.rip_inst => .{ .rip_inst = mem.base },
|
||||||
},
|
},
|
||||||
.scale_index = switch (mem.info.index) {
|
.scale_index = switch (mem.info.index) {
|
||||||
@ -1959,7 +1960,7 @@ pub fn resolveFrameAddr(mir: Mir, frame_addr: bits.FrameAddr) bits.RegisterOffse
|
|||||||
|
|
||||||
pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory {
|
pub fn resolveFrameLoc(mir: Mir, mem: Memory) Memory {
|
||||||
return switch (mem.info.base) {
|
return switch (mem.info.base) {
|
||||||
.none, .reg, .table, .reloc, .rip_inst => mem,
|
.none, .reg, .table, .reloc, .pcrel, .rip_inst => mem,
|
||||||
.frame => if (mir.frame_locs.len > 0) .{
|
.frame => if (mir.frame_locs.len > 0) .{
|
||||||
.info = .{
|
.info = .{
|
||||||
.base = .reg,
|
.base = .reg,
|
||||||
|
|||||||
@ -762,6 +762,7 @@ pub const Memory = struct {
|
|||||||
frame: FrameIndex,
|
frame: FrameIndex,
|
||||||
table,
|
table,
|
||||||
reloc: u32,
|
reloc: u32,
|
||||||
|
pcrel: u32,
|
||||||
rip_inst: Mir.Inst.Index,
|
rip_inst: Mir.Inst.Index,
|
||||||
|
|
||||||
pub const Tag = @typeInfo(Base).@"union".tag_type.?;
|
pub const Tag = @typeInfo(Base).@"union".tag_type.?;
|
||||||
|
|||||||
@ -138,7 +138,7 @@ pub const Instruction = struct {
|
|||||||
.moffs => true,
|
.moffs => true,
|
||||||
.rip => false,
|
.rip => false,
|
||||||
.sib => |s| switch (s.base) {
|
.sib => |s| switch (s.base) {
|
||||||
.none, .frame, .table, .reloc, .rip_inst => false,
|
.none, .frame, .table, .reloc, .pcrel, .rip_inst => false,
|
||||||
.reg => |reg| reg.isClass(.segment),
|
.reg => |reg| reg.isClass(.segment),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -211,7 +211,7 @@ pub const Instruction = struct {
|
|||||||
.none, .imm => 0b00,
|
.none, .imm => 0b00,
|
||||||
.reg => |reg| @truncate(reg.enc() >> 3),
|
.reg => |reg| @truncate(reg.enc() >> 3),
|
||||||
.mem => |mem| switch (mem.base()) {
|
.mem => |mem| switch (mem.base()) {
|
||||||
.none, .frame, .table, .reloc, .rip_inst => 0b00, // rsp, rbp, and rip are not extended
|
.none, .frame, .table, .reloc, .pcrel, .rip_inst => 0b00, // rsp, rbp, and rip are not extended
|
||||||
.reg => |reg| @truncate(reg.enc() >> 3),
|
.reg => |reg| @truncate(reg.enc() >> 3),
|
||||||
},
|
},
|
||||||
.bytes => unreachable,
|
.bytes => unreachable,
|
||||||
@ -282,6 +282,7 @@ pub const Instruction = struct {
|
|||||||
.frame => |frame_index| try writer.print("{}", .{frame_index}),
|
.frame => |frame_index| try writer.print("{}", .{frame_index}),
|
||||||
.table => try writer.print("Table", .{}),
|
.table => try writer.print("Table", .{}),
|
||||||
.reloc => |sym_index| try writer.print("Symbol({d})", .{sym_index}),
|
.reloc => |sym_index| try writer.print("Symbol({d})", .{sym_index}),
|
||||||
|
.pcrel => |sym_index| try writer.print("PcRelSymbol({d})", .{sym_index}),
|
||||||
.rip_inst => |inst_index| try writer.print("RipInst({d})", .{inst_index}),
|
.rip_inst => |inst_index| try writer.print("RipInst({d})", .{inst_index}),
|
||||||
}
|
}
|
||||||
if (mem.scaleIndex()) |si| {
|
if (mem.scaleIndex()) |si| {
|
||||||
@ -721,7 +722,7 @@ pub const Instruction = struct {
|
|||||||
try encoder.modRm_indirectDisp32(operand_enc, 0);
|
try encoder.modRm_indirectDisp32(operand_enc, 0);
|
||||||
try encoder.disp32(undefined);
|
try encoder.disp32(undefined);
|
||||||
} else return error.CannotEncode,
|
} else return error.CannotEncode,
|
||||||
.rip_inst => {
|
.pcrel, .rip_inst => {
|
||||||
try encoder.modRm_RIPDisp32(operand_enc);
|
try encoder.modRm_RIPDisp32(operand_enc);
|
||||||
try encoder.disp32(sib.disp);
|
try encoder.disp32(sib.disp);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -921,41 +921,74 @@ fn genNavRef(
|
|||||||
const nav = ip.getNav(nav_index);
|
const nav = ip.getNav(nav_index);
|
||||||
assert(!nav.isThreadlocal(ip));
|
assert(!nav.isThreadlocal(ip));
|
||||||
|
|
||||||
const is_extern, const lib_name = if (nav.getExtern(ip)) |e|
|
const lib_name, const linkage, const visibility = if (nav.getExtern(ip)) |e|
|
||||||
.{ true, e.lib_name }
|
.{ e.lib_name, e.linkage, e.visibility }
|
||||||
else
|
else
|
||||||
.{ false, .none };
|
.{ .none, .internal, .default };
|
||||||
|
|
||||||
const name = nav.name;
|
const name = nav.name;
|
||||||
if (lf.cast(.elf)) |elf_file| {
|
if (lf.cast(.elf)) |elf_file| {
|
||||||
const zo = elf_file.zigObjectPtr().?;
|
const zo = elf_file.zigObjectPtr().?;
|
||||||
if (is_extern) {
|
switch (linkage) {
|
||||||
const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
|
.internal => {
|
||||||
zo.symbol(sym_index).flags.is_extern_ptr = true;
|
|
||||||
return .{ .mcv = .{ .lea_symbol = sym_index } };
|
|
||||||
}
|
|
||||||
const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index);
|
const sym_index = try zo.getOrCreateMetadataForNav(zcu, nav_index);
|
||||||
return .{ .mcv = .{ .lea_symbol = sym_index } };
|
return .{ .mcv = .{ .lea_symbol = sym_index } };
|
||||||
|
},
|
||||||
|
.strong, .weak => {
|
||||||
|
const sym_index = try elf_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
|
||||||
|
switch (linkage) {
|
||||||
|
.internal => unreachable,
|
||||||
|
.strong => {},
|
||||||
|
.weak => zo.symbol(sym_index).flags.weak = true,
|
||||||
|
.link_once => unreachable,
|
||||||
|
}
|
||||||
|
switch (visibility) {
|
||||||
|
.default => zo.symbol(sym_index).flags.is_extern_ptr = true,
|
||||||
|
.hidden, .protected => {},
|
||||||
|
}
|
||||||
|
return .{ .mcv = .{ .lea_symbol = sym_index } };
|
||||||
|
},
|
||||||
|
.link_once => unreachable,
|
||||||
|
}
|
||||||
} else if (lf.cast(.macho)) |macho_file| {
|
} else if (lf.cast(.macho)) |macho_file| {
|
||||||
const zo = macho_file.getZigObject().?;
|
const zo = macho_file.getZigObject().?;
|
||||||
if (is_extern) {
|
switch (linkage) {
|
||||||
const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
|
.internal => {
|
||||||
zo.symbols.items[sym_index].flags.is_extern_ptr = true;
|
|
||||||
return .{ .mcv = .{ .lea_symbol = sym_index } };
|
|
||||||
}
|
|
||||||
const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);
|
const sym_index = try zo.getOrCreateMetadataForNav(macho_file, nav_index);
|
||||||
const sym = zo.symbols.items[sym_index];
|
const sym = zo.symbols.items[sym_index];
|
||||||
return .{ .mcv = .{ .lea_symbol = sym.nlist_idx } };
|
return .{ .mcv = .{ .lea_symbol = sym.nlist_idx } };
|
||||||
} else if (lf.cast(.coff)) |coff_file| {
|
},
|
||||||
if (is_extern) {
|
.strong, .weak => {
|
||||||
// TODO audit this
|
const sym_index = try macho_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
|
||||||
const global_index = try coff_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
|
switch (linkage) {
|
||||||
try coff_file.need_got_table.put(gpa, global_index, {}); // needs GOT
|
.internal => unreachable,
|
||||||
return .{ .mcv = .{ .load_got = link.File.Coff.global_symbol_bit | global_index } };
|
.strong => {},
|
||||||
|
.weak => zo.symbols.items[sym_index].flags.weak = true,
|
||||||
|
.link_once => unreachable,
|
||||||
}
|
}
|
||||||
|
switch (visibility) {
|
||||||
|
.default => zo.symbols.items[sym_index].flags.is_extern_ptr = true,
|
||||||
|
.hidden, .protected => {},
|
||||||
|
}
|
||||||
|
return .{ .mcv = .{ .lea_symbol = sym_index } };
|
||||||
|
},
|
||||||
|
.link_once => unreachable,
|
||||||
|
}
|
||||||
|
} else if (lf.cast(.coff)) |coff_file| {
|
||||||
|
// TODO audit this
|
||||||
|
switch (linkage) {
|
||||||
|
.internal => {
|
||||||
const atom_index = try coff_file.getOrCreateAtomForNav(nav_index);
|
const atom_index = try coff_file.getOrCreateAtomForNav(nav_index);
|
||||||
const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
|
const sym_index = coff_file.getAtom(atom_index).getSymbolIndex().?;
|
||||||
return .{ .mcv = .{ .load_got = sym_index } };
|
return .{ .mcv = .{ .load_got = sym_index } };
|
||||||
|
},
|
||||||
|
.strong, .weak => {
|
||||||
|
const global_index = try coff_file.getGlobalSymbol(name.toSlice(ip), lib_name.toSlice(ip));
|
||||||
|
try coff_file.need_got_table.put(gpa, global_index, {}); // needs GOT
|
||||||
|
return .{ .mcv = .{ .load_got = link.File.Coff.global_symbol_bit | global_index } };
|
||||||
|
},
|
||||||
|
.link_once => unreachable,
|
||||||
|
}
|
||||||
} else if (lf.cast(.plan9)) |p9| {
|
} else if (lf.cast(.plan9)) |p9| {
|
||||||
const atom_index = try p9.seeNav(pt, nav_index);
|
const atom_index = try p9.seeNav(pt, nav_index);
|
||||||
const atom = p9.getAtom(atom_index);
|
const atom = p9.getAtom(atom_index);
|
||||||
|
|||||||
@ -2255,19 +2255,30 @@ pub const DeclGen = struct {
|
|||||||
fn renderFwdDecl(
|
fn renderFwdDecl(
|
||||||
dg: *DeclGen,
|
dg: *DeclGen,
|
||||||
nav_index: InternPool.Nav.Index,
|
nav_index: InternPool.Nav.Index,
|
||||||
flags: struct {
|
flags: packed struct {
|
||||||
is_extern: bool,
|
|
||||||
is_const: bool,
|
is_const: bool,
|
||||||
is_threadlocal: bool,
|
is_threadlocal: bool,
|
||||||
is_weak_linkage: bool,
|
linkage: std.builtin.GlobalLinkage,
|
||||||
|
visibility: std.builtin.SymbolVisibility,
|
||||||
},
|
},
|
||||||
) !void {
|
) !void {
|
||||||
const zcu = dg.pt.zcu;
|
const zcu = dg.pt.zcu;
|
||||||
const ip = &zcu.intern_pool;
|
const ip = &zcu.intern_pool;
|
||||||
const nav = ip.getNav(nav_index);
|
const nav = ip.getNav(nav_index);
|
||||||
const fwd = dg.fwdDeclWriter();
|
const fwd = dg.fwdDeclWriter();
|
||||||
try fwd.writeAll(if (flags.is_extern) "zig_extern " else "static ");
|
try fwd.writeAll(switch (flags.linkage) {
|
||||||
if (flags.is_weak_linkage) try fwd.writeAll("zig_weak_linkage ");
|
.internal => "static ",
|
||||||
|
.strong, .weak, .link_once => "zig_extern ",
|
||||||
|
});
|
||||||
|
switch (flags.linkage) {
|
||||||
|
.internal, .strong => {},
|
||||||
|
.weak => try fwd.writeAll("zig_weak_linkage "),
|
||||||
|
.link_once => return dg.fail("TODO: CBE: implement linkonce linkage?", .{}),
|
||||||
|
}
|
||||||
|
switch (flags.linkage) {
|
||||||
|
.internal => {},
|
||||||
|
.strong, .weak, .link_once => try fwd.print("zig_visibility({s}) ", .{@tagName(flags.visibility)}),
|
||||||
|
}
|
||||||
if (flags.is_threadlocal and !dg.mod.single_threaded) try fwd.writeAll("zig_threadlocal ");
|
if (flags.is_threadlocal and !dg.mod.single_threaded) try fwd.writeAll("zig_threadlocal ");
|
||||||
try dg.renderTypeAndName(
|
try dg.renderTypeAndName(
|
||||||
fwd,
|
fwd,
|
||||||
@ -2994,10 +3005,10 @@ pub fn genDecl(o: *Object) !void {
|
|||||||
switch (ip.indexToKey(nav.status.fully_resolved.val)) {
|
switch (ip.indexToKey(nav.status.fully_resolved.val)) {
|
||||||
.@"extern" => |@"extern"| {
|
.@"extern" => |@"extern"| {
|
||||||
if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{
|
if (!ip.isFunctionType(nav_ty.toIntern())) return o.dg.renderFwdDecl(o.dg.pass.nav, .{
|
||||||
.is_extern = true,
|
|
||||||
.is_const = @"extern".is_const,
|
.is_const = @"extern".is_const,
|
||||||
.is_threadlocal = @"extern".is_threadlocal,
|
.is_threadlocal = @"extern".is_threadlocal,
|
||||||
.is_weak_linkage = @"extern".is_weak_linkage,
|
.linkage = @"extern".linkage,
|
||||||
|
.visibility = @"extern".visibility,
|
||||||
});
|
});
|
||||||
|
|
||||||
const fwd = o.dg.fwdDeclWriter();
|
const fwd = o.dg.fwdDeclWriter();
|
||||||
@ -3016,13 +3027,12 @@ pub fn genDecl(o: *Object) !void {
|
|||||||
},
|
},
|
||||||
.variable => |variable| {
|
.variable => |variable| {
|
||||||
try o.dg.renderFwdDecl(o.dg.pass.nav, .{
|
try o.dg.renderFwdDecl(o.dg.pass.nav, .{
|
||||||
.is_extern = false,
|
|
||||||
.is_const = false,
|
.is_const = false,
|
||||||
.is_threadlocal = variable.is_threadlocal,
|
.is_threadlocal = variable.is_threadlocal,
|
||||||
.is_weak_linkage = variable.is_weak_linkage,
|
.linkage = .internal,
|
||||||
|
.visibility = .default,
|
||||||
});
|
});
|
||||||
const w = o.writer();
|
const w = o.writer();
|
||||||
if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
|
|
||||||
if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");
|
if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");
|
||||||
if (nav.status.fully_resolved.@"linksection".toSlice(&zcu.intern_pool)) |s|
|
if (nav.status.fully_resolved.@"linksection".toSlice(&zcu.intern_pool)) |s|
|
||||||
try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
|
try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
|
||||||
@ -3467,7 +3477,7 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
|
|||||||
.error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
|
.error_set_has_value => return f.fail("TODO: C backend: implement error_set_has_value", .{}),
|
||||||
.vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),
|
.vector_store_elem => return f.fail("TODO: C backend: implement vector_store_elem", .{}),
|
||||||
|
|
||||||
.tlv_dllimport_ptr => try airTlvDllimportPtr(f, inst),
|
.runtime_nav_ptr => try airRuntimeNavPtr(f, inst),
|
||||||
|
|
||||||
.c_va_start => try airCVaStart(f, inst),
|
.c_va_start => try airCVaStart(f, inst),
|
||||||
.c_va_arg => try airCVaArg(f, inst),
|
.c_va_arg => try airCVaArg(f, inst),
|
||||||
@ -7672,7 +7682,7 @@ fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
|
|||||||
return local;
|
return local;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn airTlvDllimportPtr(f: *Function, inst: Air.Inst.Index) !CValue {
|
fn airRuntimeNavPtr(f: *Function, inst: Air.Inst.Index) !CValue {
|
||||||
const ty_nav = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
|
const ty_nav = f.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
|
||||||
const writer = f.object.writer();
|
const writer = f.object.writer();
|
||||||
const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty));
|
const local = try f.allocLocal(inst, .fromInterned(ty_nav.ty));
|
||||||
|
|||||||
@ -2979,36 +2979,49 @@ pub const Object = struct {
|
|||||||
const zcu = pt.zcu;
|
const zcu = pt.zcu;
|
||||||
const ip = &zcu.intern_pool;
|
const ip = &zcu.intern_pool;
|
||||||
const nav = ip.getNav(nav_index);
|
const nav = ip.getNav(nav_index);
|
||||||
const is_extern, const is_threadlocal, const is_weak_linkage, const is_dll_import = switch (nav.status) {
|
const linkage: std.builtin.GlobalLinkage, const visibility: Builder.Visibility, const is_threadlocal, const is_dll_import = switch (nav.status) {
|
||||||
.unresolved => unreachable,
|
.unresolved => unreachable,
|
||||||
.fully_resolved => |r| switch (ip.indexToKey(r.val)) {
|
.fully_resolved => |r| switch (ip.indexToKey(r.val)) {
|
||||||
.variable => |variable| .{ false, variable.is_threadlocal, variable.is_weak_linkage, false },
|
.variable => |variable| .{ .internal, .default, variable.is_threadlocal, false },
|
||||||
.@"extern" => |@"extern"| .{ true, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import },
|
.@"extern" => |@"extern"| .{ @"extern".linkage, .fromSymbolVisibility(@"extern".visibility), @"extern".is_threadlocal, @"extern".is_dll_import },
|
||||||
else => .{ false, false, false, false },
|
else => .{ .internal, .default, false, false },
|
||||||
},
|
},
|
||||||
// This means it's a source declaration which is not `extern`!
|
// This means it's a source declaration which is not `extern`!
|
||||||
.type_resolved => |r| .{ false, r.is_threadlocal, false, false },
|
.type_resolved => |r| .{ .internal, .default, r.is_threadlocal, false },
|
||||||
};
|
};
|
||||||
|
|
||||||
const variable_index = try o.builder.addVariable(
|
const variable_index = try o.builder.addVariable(
|
||||||
try o.builder.strtabString((if (is_extern) nav.name else nav.fqn).toSlice(ip)),
|
try o.builder.strtabString(switch (linkage) {
|
||||||
|
.internal => nav.fqn,
|
||||||
|
.strong, .weak => nav.name,
|
||||||
|
.link_once => unreachable,
|
||||||
|
}.toSlice(ip)),
|
||||||
try o.lowerType(Type.fromInterned(nav.typeOf(ip))),
|
try o.lowerType(Type.fromInterned(nav.typeOf(ip))),
|
||||||
toLlvmGlobalAddressSpace(nav.getAddrspace(), zcu.getTarget()),
|
toLlvmGlobalAddressSpace(nav.getAddrspace(), zcu.getTarget()),
|
||||||
);
|
);
|
||||||
gop.value_ptr.* = variable_index.ptrConst(&o.builder).global;
|
gop.value_ptr.* = variable_index.ptrConst(&o.builder).global;
|
||||||
|
|
||||||
// This is needed for declarations created by `@extern`.
|
// This is needed for declarations created by `@extern`.
|
||||||
if (is_extern) {
|
switch (linkage) {
|
||||||
variable_index.setLinkage(.external, &o.builder);
|
.internal => {
|
||||||
|
variable_index.setLinkage(.internal, &o.builder);
|
||||||
|
variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
|
||||||
|
},
|
||||||
|
.strong, .weak => {
|
||||||
|
variable_index.setLinkage(switch (linkage) {
|
||||||
|
.internal => unreachable,
|
||||||
|
.strong => .external,
|
||||||
|
.weak => .extern_weak,
|
||||||
|
.link_once => unreachable,
|
||||||
|
}, &o.builder);
|
||||||
variable_index.setUnnamedAddr(.default, &o.builder);
|
variable_index.setUnnamedAddr(.default, &o.builder);
|
||||||
if (is_threadlocal and !zcu.navFileScope(nav_index).mod.?.single_threaded)
|
if (is_threadlocal and !zcu.navFileScope(nav_index).mod.?.single_threaded)
|
||||||
variable_index.setThreadLocal(.generaldynamic, &o.builder);
|
variable_index.setThreadLocal(.generaldynamic, &o.builder);
|
||||||
if (is_weak_linkage) variable_index.setLinkage(.extern_weak, &o.builder);
|
|
||||||
if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder);
|
if (is_dll_import) variable_index.setDllStorageClass(.dllimport, &o.builder);
|
||||||
} else {
|
},
|
||||||
variable_index.setLinkage(.internal, &o.builder);
|
.link_once => unreachable,
|
||||||
variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
|
|
||||||
}
|
}
|
||||||
|
variable_index.setVisibility(visibility, &o.builder);
|
||||||
return variable_index;
|
return variable_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4530,14 +4543,14 @@ pub const NavGen = struct {
|
|||||||
const nav = ip.getNav(nav_index);
|
const nav = ip.getNav(nav_index);
|
||||||
const resolved = nav.status.fully_resolved;
|
const resolved = nav.status.fully_resolved;
|
||||||
|
|
||||||
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)) {
|
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)) {
|
||||||
.variable => |variable| .{ false, .none, variable.is_threadlocal, variable.is_weak_linkage, false, false, variable.init, variable.owner_nav },
|
.variable => |variable| .{ .none, .internal, .default, variable.is_threadlocal, false, false, variable.init, variable.owner_nav },
|
||||||
.@"extern" => |@"extern"| .{ true, @"extern".lib_name, @"extern".is_threadlocal, @"extern".is_weak_linkage, @"extern".is_dll_import, @"extern".is_const, .none, @"extern".owner_nav },
|
.@"extern" => |@"extern"| .{ @"extern".lib_name, @"extern".linkage, .fromSymbolVisibility(@"extern".visibility), @"extern".is_threadlocal, @"extern".is_dll_import, @"extern".is_const, .none, @"extern".owner_nav },
|
||||||
else => .{ false, .none, false, false, false, true, resolved.val, nav_index },
|
else => .{ .none, .internal, .default, false, false, true, resolved.val, nav_index },
|
||||||
};
|
};
|
||||||
const ty = Type.fromInterned(nav.typeOf(ip));
|
const ty = Type.fromInterned(nav.typeOf(ip));
|
||||||
|
|
||||||
if (is_extern and ip.isFunctionType(ty.toIntern())) {
|
if (linkage != .internal and ip.isFunctionType(ty.toIntern())) {
|
||||||
_ = try o.resolveLlvmFunction(owner_nav);
|
_ = try o.resolveLlvmFunction(owner_nav);
|
||||||
} else {
|
} else {
|
||||||
const variable_index = try o.resolveGlobalNav(nav_index);
|
const variable_index = try o.resolveGlobalNav(nav_index);
|
||||||
@ -4549,6 +4562,7 @@ pub const NavGen = struct {
|
|||||||
.none => .no_init,
|
.none => .no_init,
|
||||||
else => try o.lowerValue(init_val),
|
else => try o.lowerValue(init_val),
|
||||||
}, &o.builder);
|
}, &o.builder);
|
||||||
|
variable_index.setVisibility(visibility, &o.builder);
|
||||||
|
|
||||||
const file_scope = zcu.navFileScopeIndex(nav_index);
|
const file_scope = zcu.navFileScopeIndex(nav_index);
|
||||||
const mod = zcu.fileByIndex(file_scope).mod.?;
|
const mod = zcu.fileByIndex(file_scope).mod.?;
|
||||||
@ -4568,7 +4582,7 @@ pub const NavGen = struct {
|
|||||||
line_number,
|
line_number,
|
||||||
try o.lowerDebugType(ty),
|
try o.lowerDebugType(ty),
|
||||||
variable_index,
|
variable_index,
|
||||||
.{ .local = !is_extern },
|
.{ .local = linkage == .internal },
|
||||||
);
|
);
|
||||||
|
|
||||||
const debug_expression = try o.builder.debugExpression(&.{});
|
const debug_expression = try o.builder.debugExpression(&.{});
|
||||||
@ -4583,7 +4597,9 @@ pub const NavGen = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_extern) {
|
switch (linkage) {
|
||||||
|
.internal => {},
|
||||||
|
.strong, .weak => {
|
||||||
const global_index = o.nav_map.get(nav_index).?;
|
const global_index = o.nav_map.get(nav_index).?;
|
||||||
|
|
||||||
const decl_name = decl_name: {
|
const decl_name = decl_name: {
|
||||||
@ -4606,7 +4622,6 @@ pub const NavGen = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try global_index.rename(decl_name, &o.builder);
|
try global_index.rename(decl_name, &o.builder);
|
||||||
global_index.setLinkage(.external, &o.builder);
|
|
||||||
global_index.setUnnamedAddr(.default, &o.builder);
|
global_index.setUnnamedAddr(.default, &o.builder);
|
||||||
if (is_dll_import) {
|
if (is_dll_import) {
|
||||||
global_index.setDllStorageClass(.dllimport, &o.builder);
|
global_index.setDllStorageClass(.dllimport, &o.builder);
|
||||||
@ -4614,7 +4629,15 @@ pub const NavGen = struct {
|
|||||||
global_index.setDllStorageClass(.default, &o.builder);
|
global_index.setDllStorageClass(.default, &o.builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_weak_linkage) global_index.setLinkage(.extern_weak, &o.builder);
|
global_index.setLinkage(switch (linkage) {
|
||||||
|
.internal => unreachable,
|
||||||
|
.strong => .external,
|
||||||
|
.weak => .extern_weak,
|
||||||
|
.link_once => unreachable,
|
||||||
|
}, &o.builder);
|
||||||
|
global_index.setVisibility(visibility, &o.builder);
|
||||||
|
},
|
||||||
|
.link_once => unreachable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -5023,7 +5046,7 @@ pub const FuncGen = struct {
|
|||||||
|
|
||||||
.vector_store_elem => try self.airVectorStoreElem(inst),
|
.vector_store_elem => try self.airVectorStoreElem(inst),
|
||||||
|
|
||||||
.tlv_dllimport_ptr => try self.airTlvDllimportPtr(inst),
|
.runtime_nav_ptr => try self.airRuntimeNavPtr(inst),
|
||||||
|
|
||||||
.inferred_alloc, .inferred_alloc_comptime => unreachable,
|
.inferred_alloc, .inferred_alloc_comptime => unreachable,
|
||||||
|
|
||||||
@ -8122,7 +8145,7 @@ pub const FuncGen = struct {
|
|||||||
return .none;
|
return .none;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn airTlvDllimportPtr(fg: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
|
fn airRuntimeNavPtr(fg: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
|
||||||
const o = fg.ng.object;
|
const o = fg.ng.object;
|
||||||
const ty_nav = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
|
const ty_nav = fg.air.instructions.items(.data)[@intFromEnum(inst)].ty_nav;
|
||||||
const llvm_ptr_const = try o.lowerNavRefValue(ty_nav.nav);
|
const llvm_ptr_const = try o.lowerNavRefValue(ty_nav.nav);
|
||||||
|
|||||||
@ -308,7 +308,7 @@ pub fn buildLibCxx(comp: *Compilation, prog_node: std.Progress.Node) BuildError!
|
|||||||
assert(comp.libcxx_static_lib == null);
|
assert(comp.libcxx_static_lib == null);
|
||||||
const crt_file = try sub_compilation.toCrtFile();
|
const crt_file = try sub_compilation.toCrtFile();
|
||||||
comp.libcxx_static_lib = crt_file;
|
comp.libcxx_static_lib = crt_file;
|
||||||
comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
|
comp.queueLinkTaskMode(crt_file.full_object_path, &config);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn buildLibCxxAbi(comp: *Compilation, prog_node: std.Progress.Node) BuildError!void {
|
pub 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
|
|||||||
assert(comp.libcxxabi_static_lib == null);
|
assert(comp.libcxxabi_static_lib == null);
|
||||||
const crt_file = try sub_compilation.toCrtFile();
|
const crt_file = try sub_compilation.toCrtFile();
|
||||||
comp.libcxxabi_static_lib = crt_file;
|
comp.libcxxabi_static_lib = crt_file;
|
||||||
comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
|
comp.queueLinkTaskMode(crt_file.full_object_path, &config);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn addCxxArgs(
|
pub fn addCxxArgs(
|
||||||
|
|||||||
@ -325,7 +325,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo
|
|||||||
};
|
};
|
||||||
|
|
||||||
const crt_file = try sub_compilation.toCrtFile();
|
const crt_file = try sub_compilation.toCrtFile();
|
||||||
comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
|
comp.queueLinkTaskMode(crt_file.full_object_path, &config);
|
||||||
assert(comp.tsan_lib == null);
|
assert(comp.tsan_lib == null);
|
||||||
comp.tsan_lib = crt_file;
|
comp.tsan_lib = crt_file;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -195,7 +195,7 @@ pub fn buildStaticLib(comp: *Compilation, prog_node: std.Progress.Node) BuildErr
|
|||||||
};
|
};
|
||||||
|
|
||||||
const crt_file = try sub_compilation.toCrtFile();
|
const crt_file = try sub_compilation.toCrtFile();
|
||||||
comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
|
comp.queueLinkTaskMode(crt_file.full_object_path, &config);
|
||||||
assert(comp.libunwind_static_lib == null);
|
assert(comp.libunwind_static_lib == null);
|
||||||
comp.libunwind_static_lib = crt_file;
|
comp.libunwind_static_lib = crt_file;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -278,7 +278,7 @@ pub fn buildCrtFile(comp: *Compilation, in_crt_file: CrtFile, prog_node: std.Pro
|
|||||||
errdefer comp.gpa.free(basename);
|
errdefer comp.gpa.free(basename);
|
||||||
|
|
||||||
const crt_file = try sub_compilation.toCrtFile();
|
const crt_file = try sub_compilation.toCrtFile();
|
||||||
comp.queueLinkTaskMode(crt_file.full_object_path, output_mode);
|
comp.queueLinkTaskMode(crt_file.full_object_path, &config);
|
||||||
{
|
{
|
||||||
comp.mutex.lock();
|
comp.mutex.lock();
|
||||||
defer comp.mutex.unlock();
|
defer comp.mutex.unlock();
|
||||||
|
|||||||
@ -1051,7 +1051,7 @@ const Entry = struct {
|
|||||||
const ref = zo.getSymbolRef(reloc.target_sym, macho_file);
|
const ref = zo.getSymbolRef(reloc.target_sym, macho_file);
|
||||||
try dwarf.resolveReloc(
|
try dwarf.resolveReloc(
|
||||||
entry_off + reloc.source_off,
|
entry_off + reloc.source_off,
|
||||||
ref.getSymbol(macho_file).?.getAddress(.{}, macho_file),
|
ref.getSymbol(macho_file).?.getAddress(.{}, macho_file) + @as(i64, @intCast(reloc.target_off)),
|
||||||
@intFromEnum(dwarf.address_size),
|
@intFromEnum(dwarf.address_size),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1085,13 +1085,19 @@ const ExternalReloc = struct {
|
|||||||
|
|
||||||
pub const Loc = union(enum) {
|
pub const Loc = union(enum) {
|
||||||
empty,
|
empty,
|
||||||
addr: union(enum) { sym: u32 },
|
addr_reloc: u32,
|
||||||
|
deref: *const Loc,
|
||||||
constu: u64,
|
constu: u64,
|
||||||
consts: i64,
|
consts: i64,
|
||||||
plus: Bin,
|
plus: Bin,
|
||||||
reg: u32,
|
reg: u32,
|
||||||
breg: u32,
|
breg: u32,
|
||||||
push_object_address,
|
push_object_address,
|
||||||
|
call: struct {
|
||||||
|
args: []const Loc = &.{},
|
||||||
|
unit: Unit.Index,
|
||||||
|
entry: Entry.Index,
|
||||||
|
},
|
||||||
form_tls_address: *const Loc,
|
form_tls_address: *const Loc,
|
||||||
implicit_value: []const u8,
|
implicit_value: []const u8,
|
||||||
stack_value: *const Loc,
|
stack_value: *const Loc,
|
||||||
@ -1136,11 +1142,13 @@ pub const Loc = union(enum) {
|
|||||||
const writer = adapter.writer();
|
const writer = adapter.writer();
|
||||||
switch (loc) {
|
switch (loc) {
|
||||||
.empty => {},
|
.empty => {},
|
||||||
.addr => |addr| {
|
.addr_reloc => |sym_index| {
|
||||||
try writer.writeByte(DW.OP.addr);
|
try writer.writeByte(DW.OP.addr);
|
||||||
switch (addr) {
|
try adapter.addrSym(sym_index);
|
||||||
.sym => |sym_index| try adapter.addrSym(sym_index),
|
},
|
||||||
}
|
.deref => |addr| {
|
||||||
|
try addr.write(adapter);
|
||||||
|
try writer.writeByte(DW.OP.deref);
|
||||||
},
|
},
|
||||||
.constu => |constu| if (std.math.cast(u5, constu)) |lit| {
|
.constu => |constu| if (std.math.cast(u5, constu)) |lit| {
|
||||||
try writer.writeByte(@as(u8, DW.OP.lit0) + lit);
|
try writer.writeByte(@as(u8, DW.OP.lit0) + lit);
|
||||||
@ -1225,6 +1233,11 @@ pub const Loc = union(enum) {
|
|||||||
try sleb128(writer, 0);
|
try sleb128(writer, 0);
|
||||||
},
|
},
|
||||||
.push_object_address => try writer.writeByte(DW.OP.push_object_address),
|
.push_object_address => try writer.writeByte(DW.OP.push_object_address),
|
||||||
|
.call => |call| {
|
||||||
|
for (call.args) |arg| try arg.write(adapter);
|
||||||
|
try writer.writeByte(DW.OP.call_ref);
|
||||||
|
try adapter.infoEntry(call.unit, call.entry);
|
||||||
|
},
|
||||||
.form_tls_address => |addr| {
|
.form_tls_address => |addr| {
|
||||||
try addr.write(adapter);
|
try addr.write(adapter);
|
||||||
try writer.writeByte(DW.OP.form_tls_address);
|
try writer.writeByte(DW.OP.form_tls_address);
|
||||||
@ -1385,12 +1398,12 @@ pub const Cfa = union(enum) {
|
|||||||
},
|
},
|
||||||
.def_cfa_expression => |expr| {
|
.def_cfa_expression => |expr| {
|
||||||
try writer.writeByte(DW.CFA.def_cfa_expression);
|
try writer.writeByte(DW.CFA.def_cfa_expression);
|
||||||
try wip_nav.frameExprloc(expr);
|
try wip_nav.frameExprLoc(expr);
|
||||||
},
|
},
|
||||||
.expression => |reg_expr| {
|
.expression => |reg_expr| {
|
||||||
try writer.writeByte(DW.CFA.expression);
|
try writer.writeByte(DW.CFA.expression);
|
||||||
try uleb128(writer, reg_expr.reg);
|
try uleb128(writer, reg_expr.reg);
|
||||||
try wip_nav.frameExprloc(reg_expr.expr);
|
try wip_nav.frameExprLoc(reg_expr.expr);
|
||||||
},
|
},
|
||||||
.val_offset => |reg_off| {
|
.val_offset => |reg_off| {
|
||||||
const factored_off = @divExact(reg_off.off, wip_nav.dwarf.debug_frame.header.data_alignment_factor);
|
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) {
|
|||||||
.val_expression => |reg_expr| {
|
.val_expression => |reg_expr| {
|
||||||
try writer.writeByte(DW.CFA.val_expression);
|
try writer.writeByte(DW.CFA.val_expression);
|
||||||
try uleb128(writer, reg_expr.reg);
|
try uleb128(writer, reg_expr.reg);
|
||||||
try wip_nav.frameExprloc(reg_expr.expr);
|
try wip_nav.frameExprLoc(reg_expr.expr);
|
||||||
},
|
},
|
||||||
.escape => |bytes| try writer.writeAll(bytes),
|
.escape => |bytes| try writer.writeAll(bytes),
|
||||||
}
|
}
|
||||||
@ -1471,7 +1484,7 @@ pub const WipNav = struct {
|
|||||||
});
|
});
|
||||||
try wip_nav.strp(name);
|
try wip_nav.strp(name);
|
||||||
try wip_nav.refType(ty);
|
try wip_nav.refType(ty);
|
||||||
try wip_nav.infoExprloc(loc);
|
try wip_nav.infoExprLoc(loc);
|
||||||
wip_nav.any_children = true;
|
wip_nav.any_children = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1741,7 +1754,7 @@ pub const WipNav = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
fn infoExprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
|
fn infoExprLoc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
|
||||||
var counter: ExprLocCounter = .init(wip_nav.dwarf);
|
var counter: ExprLocCounter = .init(wip_nav.dwarf);
|
||||||
try loc.write(&counter);
|
try loc.write(&counter);
|
||||||
|
|
||||||
@ -1773,7 +1786,7 @@ pub const WipNav = struct {
|
|||||||
try wip_nav.debug_info.appendNTimes(wip_nav.dwarf.gpa, 0, @intFromEnum(wip_nav.dwarf.address_size));
|
try wip_nav.debug_info.appendNTimes(wip_nav.dwarf.gpa, 0, @intFromEnum(wip_nav.dwarf.address_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn frameExprloc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
|
fn frameExprLoc(wip_nav: *WipNav, loc: Loc) UpdateError!void {
|
||||||
var counter: ExprLocCounter = .init(wip_nav.dwarf);
|
var counter: ExprLocCounter = .init(wip_nav.dwarf);
|
||||||
try loc.write(&counter);
|
try loc.write(&counter);
|
||||||
|
|
||||||
@ -2384,7 +2397,8 @@ fn initWipNavInner(
|
|||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
const unit = try dwarf.getUnit(file.mod.?);
|
const mod = file.mod.?;
|
||||||
|
const unit = try dwarf.getUnit(mod);
|
||||||
const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
|
const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
|
||||||
errdefer _ = if (!nav_gop.found_existing) dwarf.navs.pop();
|
errdefer _ = if (!nav_gop.found_existing) dwarf.navs.pop();
|
||||||
if (nav_gop.found_existing) {
|
if (nav_gop.found_existing) {
|
||||||
@ -2425,13 +2439,13 @@ fn initWipNavInner(
|
|||||||
}, &nav, inst_info.file, &decl);
|
}, &nav, inst_info.file, &decl);
|
||||||
try wip_nav.strp(nav.fqn.toSlice(ip));
|
try wip_nav.strp(nav.fqn.toSlice(ip));
|
||||||
const ty: Type = nav_val.typeOf(zcu);
|
const ty: Type = nav_val.typeOf(zcu);
|
||||||
const addr: Loc = .{ .addr = .{ .sym = sym_index } };
|
const addr: Loc = .{ .addr_reloc = sym_index };
|
||||||
const loc: Loc = if (decl.is_threadlocal) .{ .form_tls_address = &addr } else addr;
|
const loc: Loc = if (decl.is_threadlocal) .{ .form_tls_address = &addr } else addr;
|
||||||
switch (decl.kind) {
|
switch (decl.kind) {
|
||||||
.unnamed_test, .@"test", .decltest, .@"comptime", .@"usingnamespace" => unreachable,
|
.unnamed_test, .@"test", .decltest, .@"comptime", .@"usingnamespace" => unreachable,
|
||||||
.@"const" => {
|
.@"const" => {
|
||||||
const const_ty_reloc_index = try wip_nav.refForward();
|
const const_ty_reloc_index = try wip_nav.refForward();
|
||||||
try wip_nav.infoExprloc(loc);
|
try wip_nav.infoExprLoc(loc);
|
||||||
try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
|
try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
|
||||||
ty.abiAlignment(zcu).toByteUnits().?);
|
ty.abiAlignment(zcu).toByteUnits().?);
|
||||||
try diw.writeByte(@intFromBool(decl.linkage != .normal));
|
try diw.writeByte(@intFromBool(decl.linkage != .normal));
|
||||||
@ -2441,7 +2455,7 @@ fn initWipNavInner(
|
|||||||
},
|
},
|
||||||
.@"var" => {
|
.@"var" => {
|
||||||
try wip_nav.refType(ty);
|
try wip_nav.refType(ty);
|
||||||
try wip_nav.infoExprloc(loc);
|
try wip_nav.infoExprLoc(loc);
|
||||||
try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
|
try uleb128(diw, nav.status.fully_resolved.alignment.toByteUnits() orelse
|
||||||
ty.abiAlignment(zcu).toByteUnits().?);
|
ty.abiAlignment(zcu).toByteUnits().?);
|
||||||
try diw.writeByte(@intFromBool(decl.linkage != .normal));
|
try diw.writeByte(@intFromBool(decl.linkage != .normal));
|
||||||
@ -2512,7 +2526,7 @@ fn initWipNavInner(
|
|||||||
try wip_nav.infoAddrSym(sym_index, 0);
|
try wip_nav.infoAddrSym(sym_index, 0);
|
||||||
wip_nav.func_high_pc = @intCast(wip_nav.debug_info.items.len);
|
wip_nav.func_high_pc = @intCast(wip_nav.debug_info.items.len);
|
||||||
try diw.writeInt(u32, 0, dwarf.endian);
|
try diw.writeInt(u32, 0, dwarf.endian);
|
||||||
const target = file.mod.?.resolved_target.result;
|
const target = mod.resolved_target.result;
|
||||||
try uleb128(diw, switch (nav.status.fully_resolved.alignment) {
|
try uleb128(diw, switch (nav.status.fully_resolved.alignment) {
|
||||||
.none => target_info.defaultFunctionAlignment(target),
|
.none => target_info.defaultFunctionAlignment(target),
|
||||||
else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
|
else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
|
||||||
@ -3838,7 +3852,7 @@ fn updateLazyValue(
|
|||||||
byte_offset += base_ptr.byte_offset;
|
byte_offset += base_ptr.byte_offset;
|
||||||
};
|
};
|
||||||
try wip_nav.abbrevCode(.location_comptime_value);
|
try wip_nav.abbrevCode(.location_comptime_value);
|
||||||
try wip_nav.infoExprloc(.{ .implicit_pointer = .{
|
try wip_nav.infoExprLoc(.{ .implicit_pointer = .{
|
||||||
.unit = base_unit,
|
.unit = base_unit,
|
||||||
.entry = base_entry,
|
.entry = base_entry,
|
||||||
.offset = byte_offset,
|
.offset = byte_offset,
|
||||||
@ -4360,7 +4374,7 @@ fn refAbbrevCode(dwarf: *Dwarf, abbrev_code: AbbrevCode) UpdateError!@typeInfo(A
|
|||||||
assert(abbrev_code != .null);
|
assert(abbrev_code != .null);
|
||||||
const entry: Entry.Index = @enumFromInt(@intFromEnum(abbrev_code));
|
const entry: Entry.Index = @enumFromInt(@intFromEnum(abbrev_code));
|
||||||
if (dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).getEntry(entry).len > 0) return @intFromEnum(abbrev_code);
|
if (dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).getEntry(entry).len > 0) return @intFromEnum(abbrev_code);
|
||||||
var debug_abbrev = std.ArrayList(u8).init(dwarf.gpa);
|
var debug_abbrev: std.ArrayList(u8) = .init(dwarf.gpa);
|
||||||
defer debug_abbrev.deinit();
|
defer debug_abbrev.deinit();
|
||||||
const daw = debug_abbrev.writer();
|
const daw = debug_abbrev.writer();
|
||||||
const abbrev = AbbrevCode.abbrevs.get(abbrev_code);
|
const abbrev = AbbrevCode.abbrevs.get(abbrev_code);
|
||||||
@ -4422,7 +4436,7 @@ pub fn flushModule(dwarf: *Dwarf, pt: Zcu.PerThread) FlushError!void {
|
|||||||
mod_info.root_dir_path = try dwarf.debug_line_str.addString(dwarf, root_dir_path);
|
mod_info.root_dir_path = try dwarf.debug_line_str.addString(dwarf, root_dir_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
var header = std.ArrayList(u8).init(dwarf.gpa);
|
var header: std.ArrayList(u8) = .init(dwarf.gpa);
|
||||||
defer header.deinit();
|
defer header.deinit();
|
||||||
if (dwarf.debug_aranges.section.dirty) {
|
if (dwarf.debug_aranges.section.dirty) {
|
||||||
for (dwarf.debug_aranges.section.units.items, 0..) |*unit_ptr, unit_index| {
|
for (dwarf.debug_aranges.section.units.items, 0..) |*unit_ptr, unit_index| {
|
||||||
|
|||||||
@ -959,6 +959,12 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
|
|||||||
self.rela_plt.clearRetainingCapacity();
|
self.rela_plt.clearRetainingCapacity();
|
||||||
|
|
||||||
if (self.zigObjectPtr()) |zo| {
|
if (self.zigObjectPtr()) |zo| {
|
||||||
|
var undefs: std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)) = .init(gpa);
|
||||||
|
defer {
|
||||||
|
for (undefs.values()) |*refs| refs.deinit();
|
||||||
|
undefs.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
var has_reloc_errors = false;
|
var has_reloc_errors = false;
|
||||||
for (zo.atoms_indexes.items) |atom_index| {
|
for (zo.atoms_indexes.items) |atom_index| {
|
||||||
const atom_ptr = zo.atom(atom_index) orelse continue;
|
const atom_ptr = zo.atom(atom_index) orelse continue;
|
||||||
@ -969,7 +975,10 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
|
|||||||
const code = try zo.codeAlloc(self, atom_index);
|
const code = try zo.codeAlloc(self, atom_index);
|
||||||
defer gpa.free(code);
|
defer gpa.free(code);
|
||||||
const file_offset = atom_ptr.offset(self);
|
const file_offset = atom_ptr.offset(self);
|
||||||
atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {
|
(if (shdr.sh_flags & elf.SHF_ALLOC == 0)
|
||||||
|
atom_ptr.resolveRelocsNonAlloc(self, code, &undefs)
|
||||||
|
else
|
||||||
|
atom_ptr.resolveRelocsAlloc(self, code)) catch |err| switch (err) {
|
||||||
error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
|
error.RelocFailure, error.RelaxFailure => has_reloc_errors = true,
|
||||||
error.UnsupportedCpuArch => {
|
error.UnsupportedCpuArch => {
|
||||||
try self.reportUnsupportedCpuArch();
|
try self.reportUnsupportedCpuArch();
|
||||||
@ -980,6 +989,8 @@ fn flushModuleInner(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id) !void {
|
|||||||
try self.pwriteAll(code, file_offset);
|
try self.pwriteAll(code, file_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try self.reportUndefinedSymbols(&undefs);
|
||||||
|
|
||||||
if (has_reloc_errors) return error.LinkFailure;
|
if (has_reloc_errors) return error.LinkFailure;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1392,11 +1403,9 @@ fn scanRelocs(self: *Elf) !void {
|
|||||||
const gpa = self.base.comp.gpa;
|
const gpa = self.base.comp.gpa;
|
||||||
const shared_objects = self.shared_objects.values();
|
const shared_objects = self.shared_objects.values();
|
||||||
|
|
||||||
var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa);
|
var undefs: std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)) = .init(gpa);
|
||||||
defer {
|
defer {
|
||||||
for (undefs.values()) |*refs| {
|
for (undefs.values()) |*refs| refs.deinit();
|
||||||
refs.deinit();
|
|
||||||
}
|
|
||||||
undefs.deinit();
|
undefs.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2702,15 +2711,16 @@ fn initSyntheticSections(self: *Elf) !void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const needs_interp = blk: {
|
const is_exe_or_dyn_lib = switch (comp.config.output_mode) {
|
||||||
// On Ubuntu with musl-gcc, we get a weird combo of options looking like this:
|
.Exe => true,
|
||||||
// -dynamic-linker=<path> -static
|
.Lib => comp.config.link_mode == .dynamic,
|
||||||
// In this case, if we do generate .interp section and segment, we will get
|
.Obj => false,
|
||||||
// a segfault in the dynamic linker trying to load a binary that is static
|
|
||||||
// and doesn't contain .dynamic section.
|
|
||||||
if (self.base.isStatic() and !comp.config.pie) break :blk false;
|
|
||||||
break :blk target.dynamic_linker.get() != null;
|
|
||||||
};
|
};
|
||||||
|
const have_dynamic_linker = comp.config.link_mode == .dynamic and is_exe_or_dyn_lib and !target.dynamic_linker.eql(.none);
|
||||||
|
|
||||||
|
const needs_interp = have_dynamic_linker and
|
||||||
|
(comp.config.link_libc or comp.root_mod.resolved_target.is_explicit_dynamic_linker);
|
||||||
|
|
||||||
if (needs_interp and self.section_indexes.interp == null) {
|
if (needs_interp and self.section_indexes.interp == null) {
|
||||||
self.section_indexes.interp = try self.addSection(.{
|
self.section_indexes.interp = try self.addSection(.{
|
||||||
.name = try self.insertShString(".interp"),
|
.name = try self.insertShString(".interp"),
|
||||||
@ -3707,11 +3717,9 @@ fn allocateSpecialPhdrs(self: *Elf) void {
|
|||||||
fn writeAtoms(self: *Elf) !void {
|
fn writeAtoms(self: *Elf) !void {
|
||||||
const gpa = self.base.comp.gpa;
|
const gpa = self.base.comp.gpa;
|
||||||
|
|
||||||
var undefs = std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)).init(gpa);
|
var undefs: std.AutoArrayHashMap(SymbolResolver.Index, std.ArrayList(Ref)) = .init(gpa);
|
||||||
defer {
|
defer {
|
||||||
for (undefs.values()) |*refs| {
|
for (undefs.values()) |*refs| refs.deinit();
|
||||||
refs.deinit();
|
|
||||||
}
|
|
||||||
undefs.deinit();
|
undefs.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -497,14 +497,14 @@ fn dynAbsRelocAction(symbol: *const Symbol, elf_file: *Elf) RelocAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn outputType(elf_file: *Elf) u2 {
|
fn outputType(elf_file: *Elf) u2 {
|
||||||
const comp = elf_file.base.comp;
|
|
||||||
assert(!elf_file.base.isRelocatable());
|
assert(!elf_file.base.isRelocatable());
|
||||||
return switch (elf_file.base.comp.config.output_mode) {
|
const config = &elf_file.base.comp.config;
|
||||||
|
return switch (config.output_mode) {
|
||||||
.Obj => unreachable,
|
.Obj => unreachable,
|
||||||
.Lib => 0,
|
.Lib => 0,
|
||||||
.Exe => switch (elf_file.getTarget().os.tag) {
|
.Exe => switch (elf_file.getTarget().os.tag) {
|
||||||
.haiku => 0,
|
.haiku => 0,
|
||||||
else => if (comp.config.pie) 1 else 2,
|
else => if (config.pie) 1 else 2,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -657,6 +657,7 @@ pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
|
|||||||
const atom_ptr = self.atom(atom_index) orelse continue;
|
const atom_ptr = self.atom(atom_index) orelse continue;
|
||||||
if (!atom_ptr.alive) continue;
|
if (!atom_ptr.alive) continue;
|
||||||
const shdr = atom_ptr.inputShdr(elf_file);
|
const shdr = atom_ptr.inputShdr(elf_file);
|
||||||
|
if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
|
||||||
if (shdr.sh_type == elf.SHT_NOBITS) continue;
|
if (shdr.sh_type == elf.SHT_NOBITS) continue;
|
||||||
if (atom_ptr.scanRelocsRequiresCode(elf_file)) {
|
if (atom_ptr.scanRelocsRequiresCode(elf_file)) {
|
||||||
// TODO ideally we don't have to fetch the code here.
|
// TODO ideally we don't have to fetch the code here.
|
||||||
|
|||||||
@ -2376,7 +2376,7 @@ pub const FunctionImportId = enum(u32) {
|
|||||||
const zcu = wasm.base.comp.zcu.?;
|
const zcu = wasm.base.comp.zcu.?;
|
||||||
const ip = &zcu.intern_pool;
|
const ip = &zcu.intern_pool;
|
||||||
const ext = ip.getNav(i.ptr(wasm).*).getResolvedExtern(ip).?;
|
const ext = ip.getNav(i.ptr(wasm).*).getResolvedExtern(ip).?;
|
||||||
return !ext.is_weak_linkage and ext.lib_name != .none;
|
return ext.linkage != .weak and ext.lib_name != .none;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,7 +39,7 @@ test {
|
|||||||
_ = Package;
|
_ = Package;
|
||||||
}
|
}
|
||||||
|
|
||||||
const thread_stack_size = 50 << 20;
|
const thread_stack_size = 60 << 20;
|
||||||
|
|
||||||
pub const std_options: std.Options = .{
|
pub const std_options: std.Options = .{
|
||||||
.wasiCwd = wasi_cwd,
|
.wasiCwd = wasi_cwd,
|
||||||
@ -4208,7 +4208,7 @@ fn serve(
|
|||||||
const main_progress_node = std.Progress.start(.{});
|
const main_progress_node = std.Progress.start(.{});
|
||||||
const file_system_inputs = comp.file_system_inputs.?;
|
const file_system_inputs = comp.file_system_inputs.?;
|
||||||
|
|
||||||
const IncrementalDebugServer = if (build_options.enable_debug_extensions)
|
const IncrementalDebugServer = if (build_options.enable_debug_extensions and !builtin.single_threaded)
|
||||||
@import("IncrementalDebugServer.zig")
|
@import("IncrementalDebugServer.zig")
|
||||||
else
|
else
|
||||||
void;
|
void;
|
||||||
|
|||||||
@ -223,6 +223,10 @@ pub fn hasLldSupport(ofmt: std.Target.ObjectFormat) bool {
|
|||||||
/// than or equal to the number of behavior tests as the respective LLVM backend.
|
/// than or equal to the number of behavior tests as the respective LLVM backend.
|
||||||
pub fn selfHostedBackendIsAsRobustAsLlvm(target: std.Target) bool {
|
pub fn selfHostedBackendIsAsRobustAsLlvm(target: std.Target) bool {
|
||||||
if (target.cpu.arch.isSpirV()) return true;
|
if (target.cpu.arch.isSpirV()) return true;
|
||||||
|
if (target.cpu.arch == .x86_64 and target.ptrBitWidth() == 64) return switch (target.ofmt) {
|
||||||
|
.elf, .macho => true,
|
||||||
|
else => false,
|
||||||
|
};
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1722,6 +1722,7 @@ test "signed zeros are represented properly" {
|
|||||||
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
|
||||||
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
|
||||||
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
|
||||||
|
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
|
||||||
|
|
||||||
const S = struct {
|
const S = struct {
|
||||||
fn doTheTest() !void {
|
fn doTheTest() !void {
|
||||||
|
|||||||
@ -1056,3 +1056,12 @@ test "unlabeled break ignores switch" {
|
|||||||
};
|
};
|
||||||
try expect(result == 123);
|
try expect(result == 123);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test "switch on a signed value smaller than the smallest prong value" {
|
||||||
|
var v: i32 = undefined;
|
||||||
|
v = -1;
|
||||||
|
switch (v) {
|
||||||
|
inline 0...10 => return error.TestFailed,
|
||||||
|
else => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -117,9 +117,9 @@ export fn testMutablePointer() void {
|
|||||||
// tmp.zig:37:38: note: imported here
|
// tmp.zig:37:38: note: imported here
|
||||||
// neg_inf.zon:1:1: error: expected type '?u8'
|
// neg_inf.zon:1:1: error: expected type '?u8'
|
||||||
// tmp.zig:57:28: note: imported here
|
// tmp.zig:57:28: note: imported here
|
||||||
// neg_inf.zon:1:1: error: expected type 'tmp.testNonExhaustiveEnum__enum_522'
|
// neg_inf.zon:1:1: error: expected type 'tmp.testNonExhaustiveEnum__enum_525'
|
||||||
// tmp.zig:62:39: note: imported here
|
// tmp.zig:62:39: note: imported here
|
||||||
// neg_inf.zon:1:1: error: expected type 'tmp.testUntaggedUnion__union_524'
|
// neg_inf.zon:1:1: error: expected type 'tmp.testUntaggedUnion__union_527'
|
||||||
// tmp.zig:67:44: note: imported here
|
// tmp.zig:67:44: note: imported here
|
||||||
// neg_inf.zon:1:1: error: expected type 'tmp.testTaggedUnionVoid__union_527'
|
// neg_inf.zon:1:1: error: expected type 'tmp.testTaggedUnionVoid__union_530'
|
||||||
// tmp.zig:72:50: note: imported here
|
// tmp.zig:72:50: note: imported here
|
||||||
|
|||||||
@ -15,6 +15,6 @@ pub export fn entry() void {
|
|||||||
// error
|
// error
|
||||||
//
|
//
|
||||||
// :7:25: error: unable to resolve comptime value
|
// :7:25: error: unable to resolve comptime value
|
||||||
// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_496.C' must be comptime-known
|
// :7:25: note: initializer of comptime-only struct 'tmp.S.foo__anon_499.C' must be comptime-known
|
||||||
// :4:16: note: struct requires comptime because of this field
|
// :4:16: note: struct requires comptime because of this field
|
||||||
// :4:16: note: types are not available at runtime
|
// :4:16: note: types are not available at runtime
|
||||||
|
|||||||
@ -16,5 +16,5 @@ pub export fn entry2() void {
|
|||||||
//
|
//
|
||||||
// :3:6: error: no field or member function named 'copy' in '[]const u8'
|
// :3:6: error: no field or member function named 'copy' in '[]const u8'
|
||||||
// :9:8: error: no field or member function named 'bar' in '@TypeOf(.{})'
|
// :9:8: error: no field or member function named 'bar' in '@TypeOf(.{})'
|
||||||
// :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_500'
|
// :12:18: error: no field or member function named 'bar' in 'tmp.entry2__struct_503'
|
||||||
// :12:6: note: struct declared here
|
// :12:6: note: struct declared here
|
||||||
|
|||||||
@ -6,6 +6,6 @@ export fn foo() void {
|
|||||||
|
|
||||||
// error
|
// error
|
||||||
//
|
//
|
||||||
// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_489'
|
// :4:16: error: expected type 'tmp.T', found 'tmp.foo__struct_492'
|
||||||
// :3:16: note: struct declared here
|
// :3:16: note: struct declared here
|
||||||
// :1:11: note: struct declared here
|
// :1:11: note: struct declared here
|
||||||
|
|||||||
@ -44,9 +44,9 @@ comptime {
|
|||||||
//
|
//
|
||||||
// :5:23: error: expected error union type, found 'comptime_int'
|
// :5:23: error: expected error union type, found 'comptime_int'
|
||||||
// :10:23: error: expected error union type, found '@TypeOf(.{})'
|
// :10:23: error: expected error union type, found '@TypeOf(.{})'
|
||||||
// :15:23: error: expected error union type, found 'tmp.test2__struct_526'
|
// :15:23: error: expected error union type, found 'tmp.test2__struct_529'
|
||||||
// :15:23: note: struct declared here
|
// :15:23: note: struct declared here
|
||||||
// :20:27: error: expected error union type, found 'tmp.test3__struct_528'
|
// :20:27: error: expected error union type, found 'tmp.test3__struct_531'
|
||||||
// :20:27: note: struct declared here
|
// :20:27: note: struct declared here
|
||||||
// :25:23: error: expected error union type, found 'struct { comptime *const [5:0]u8 = "hello" }'
|
// :25:23: error: expected error union type, found 'struct { comptime *const [5:0]u8 = "hello" }'
|
||||||
// :31:13: error: expected error union type, found 'u32'
|
// :31:13: error: expected error union type, found 'u32'
|
||||||
|
|||||||
@ -6,8 +6,9 @@ var buffer: [0x1000000]u64 = [1]u64{0} ** 0x1000000;
|
|||||||
pub fn main() anyerror!void {
|
pub fn main() anyerror!void {
|
||||||
buffer[0x10] = 1;
|
buffer[0x10] = 1;
|
||||||
try std.io.getStdOut().writer().print("{d}, {d}, {d}\n", .{
|
try std.io.getStdOut().writer().print("{d}, {d}, {d}\n", .{
|
||||||
buffer[0],
|
// workaround the dreaded decl_val
|
||||||
buffer[0x10],
|
(&buffer)[0],
|
||||||
buffer[0x1000000 - 1],
|
(&buffer)[0x10],
|
||||||
|
(&buffer)[0x1000000 - 1],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,7 +9,6 @@ pub const Options = struct {
|
|||||||
lldb: ?[]const u8,
|
lldb: ?[]const u8,
|
||||||
optimize_modes: []const std.builtin.OptimizeMode,
|
optimize_modes: []const std.builtin.OptimizeMode,
|
||||||
skip_single_threaded: bool,
|
skip_single_threaded: bool,
|
||||||
skip_non_native: bool,
|
|
||||||
skip_libc: bool,
|
skip_libc: bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -24,6 +24,8 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
|
|||||||
.optimize = optimize,
|
.optimize = optimize,
|
||||||
.link_libc = true,
|
.link_libc = true,
|
||||||
}),
|
}),
|
||||||
|
// extern threadlocals are not implemented in the self-hosted linker
|
||||||
|
.use_llvm = true,
|
||||||
});
|
});
|
||||||
exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &[_][]const u8{"-std=c11"} });
|
exe.root_module.addCSourceFile(.{ .file = b.path("test.c"), .flags = &[_][]const u8{"-std=c11"} });
|
||||||
|
|
||||||
|
|||||||
@ -52,6 +52,8 @@ pub fn build(b: *std.Build) void {
|
|||||||
.unwind_tables = .@"async",
|
.unwind_tables = .@"async",
|
||||||
.omit_frame_pointer = true,
|
.omit_frame_pointer = true,
|
||||||
}),
|
}),
|
||||||
|
// self-hosted lacks omit_frame_pointer support
|
||||||
|
.use_llvm = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const run_cmd = b.addRunArtifact(exe);
|
const run_cmd = b.addRunArtifact(exe);
|
||||||
@ -97,6 +99,8 @@ pub fn build(b: *std.Build) void {
|
|||||||
.unwind_tables = if (target.result.os.tag.isDarwin()) .@"async" else null,
|
.unwind_tables = if (target.result.os.tag.isDarwin()) .@"async" else null,
|
||||||
.omit_frame_pointer = true,
|
.omit_frame_pointer = true,
|
||||||
}),
|
}),
|
||||||
|
// zig objcopy doesn't support incremental binaries
|
||||||
|
.use_llvm = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
exe.linkLibrary(c_shared_lib);
|
exe.linkLibrary(c_shared_lib);
|
||||||
@ -137,6 +141,8 @@ pub fn build(b: *std.Build) void {
|
|||||||
.unwind_tables = null,
|
.unwind_tables = null,
|
||||||
.omit_frame_pointer = false,
|
.omit_frame_pointer = false,
|
||||||
}),
|
}),
|
||||||
|
// self-hosted lacks omit_frame_pointer support
|
||||||
|
.use_llvm = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// This "freestanding" binary is runnable because it invokes the
|
// This "freestanding" binary is runnable because it invokes the
|
||||||
|
|||||||
@ -1113,8 +1113,6 @@ const test_targets = blk: {
|
|||||||
.os_tag = .linux,
|
.os_tag = .linux,
|
||||||
.abi = .none,
|
.abi = .none,
|
||||||
},
|
},
|
||||||
.use_llvm = false,
|
|
||||||
.use_lld = false,
|
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.target = .{
|
.target = .{
|
||||||
@ -1123,8 +1121,6 @@ const test_targets = blk: {
|
|||||||
.os_tag = .linux,
|
.os_tag = .linux,
|
||||||
.abi = .none,
|
.abi = .none,
|
||||||
},
|
},
|
||||||
.use_llvm = false,
|
|
||||||
.use_lld = false,
|
|
||||||
.pic = true,
|
.pic = true,
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
@ -1134,8 +1130,6 @@ const test_targets = blk: {
|
|||||||
.os_tag = .linux,
|
.os_tag = .linux,
|
||||||
.abi = .none,
|
.abi = .none,
|
||||||
},
|
},
|
||||||
.use_llvm = false,
|
|
||||||
.use_lld = false,
|
|
||||||
.strip = true,
|
.strip = true,
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
@ -1144,6 +1138,8 @@ const test_targets = blk: {
|
|||||||
.os_tag = .linux,
|
.os_tag = .linux,
|
||||||
.abi = .none,
|
.abi = .none,
|
||||||
},
|
},
|
||||||
|
.use_llvm = true,
|
||||||
|
.use_lld = true,
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.target = .{
|
.target = .{
|
||||||
@ -1602,7 +1598,9 @@ const c_abi_targets = blk: {
|
|||||||
break :blk [_]CAbiTarget{
|
break :blk [_]CAbiTarget{
|
||||||
// Native Targets
|
// Native Targets
|
||||||
|
|
||||||
.{},
|
.{
|
||||||
|
.use_llvm = true,
|
||||||
|
},
|
||||||
|
|
||||||
// Linux Targets
|
// Linux Targets
|
||||||
|
|
||||||
@ -1841,7 +1839,6 @@ const c_abi_targets = blk: {
|
|||||||
.abi = .musl,
|
.abi = .musl,
|
||||||
},
|
},
|
||||||
.use_llvm = false,
|
.use_llvm = false,
|
||||||
.use_lld = false,
|
|
||||||
.c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
|
.c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
@ -1852,7 +1849,6 @@ const c_abi_targets = blk: {
|
|||||||
.abi = .musl,
|
.abi = .musl,
|
||||||
},
|
},
|
||||||
.use_llvm = false,
|
.use_llvm = false,
|
||||||
.use_lld = false,
|
|
||||||
.strip = true,
|
.strip = true,
|
||||||
.c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
|
.c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
|
||||||
},
|
},
|
||||||
@ -1864,7 +1860,6 @@ const c_abi_targets = blk: {
|
|||||||
.abi = .musl,
|
.abi = .musl,
|
||||||
},
|
},
|
||||||
.use_llvm = false,
|
.use_llvm = false,
|
||||||
.use_lld = false,
|
|
||||||
.pic = true,
|
.pic = true,
|
||||||
.c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
|
.c_defines = &.{"ZIG_BACKEND_STAGE2_X86_64"},
|
||||||
},
|
},
|
||||||
@ -1874,6 +1869,7 @@ const c_abi_targets = blk: {
|
|||||||
.os_tag = .linux,
|
.os_tag = .linux,
|
||||||
.abi = .musl,
|
.abi = .musl,
|
||||||
},
|
},
|
||||||
|
.use_llvm = true,
|
||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.target = .{
|
.target = .{
|
||||||
@ -1881,6 +1877,7 @@ const c_abi_targets = blk: {
|
|||||||
.os_tag = .linux,
|
.os_tag = .linux,
|
||||||
.abi = .muslx32,
|
.abi = .muslx32,
|
||||||
},
|
},
|
||||||
|
.use_llvm = true,
|
||||||
},
|
},
|
||||||
|
|
||||||
// WASI Targets
|
// WASI Targets
|
||||||
@ -2276,8 +2273,13 @@ const ModuleTestOptions = struct {
|
|||||||
include_paths: []const []const u8,
|
include_paths: []const []const u8,
|
||||||
skip_single_threaded: bool,
|
skip_single_threaded: bool,
|
||||||
skip_non_native: bool,
|
skip_non_native: bool,
|
||||||
|
skip_freebsd: bool,
|
||||||
|
skip_netbsd: bool,
|
||||||
|
skip_windows: bool,
|
||||||
|
skip_macos: bool,
|
||||||
|
skip_linux: bool,
|
||||||
|
skip_llvm: bool,
|
||||||
skip_libc: bool,
|
skip_libc: bool,
|
||||||
use_llvm: ?bool = null,
|
|
||||||
max_rss: usize = 0,
|
max_rss: usize = 0,
|
||||||
no_builtin: bool = false,
|
no_builtin: bool = false,
|
||||||
build_options: ?*std.Build.Step.Options = null,
|
build_options: ?*std.Build.Step.Options = null,
|
||||||
@ -2298,6 +2300,15 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
|
|||||||
if (options.skip_non_native and !test_target.target.isNative())
|
if (options.skip_non_native and !test_target.target.isNative())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (options.skip_freebsd and test_target.target.os_tag == .freebsd) continue;
|
||||||
|
if (options.skip_netbsd and test_target.target.os_tag == .netbsd) continue;
|
||||||
|
if (options.skip_windows and test_target.target.os_tag == .windows) continue;
|
||||||
|
if (options.skip_macos and test_target.target.os_tag == .macos) continue;
|
||||||
|
if (options.skip_linux and test_target.target.os_tag == .linux) continue;
|
||||||
|
|
||||||
|
const would_use_llvm = wouldUseLlvm(test_target.use_llvm, test_target.target, test_target.optimize_mode);
|
||||||
|
if (options.skip_llvm and would_use_llvm) continue;
|
||||||
|
|
||||||
const resolved_target = b.resolveTargetQuery(test_target.target);
|
const resolved_target = b.resolveTargetQuery(test_target.target);
|
||||||
const target = resolved_target.result;
|
const target = resolved_target.result;
|
||||||
const triple_txt = target.zigTriple(b.allocator) catch @panic("OOM");
|
const triple_txt = target.zigTriple(b.allocator) catch @panic("OOM");
|
||||||
@ -2318,10 +2329,6 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step {
|
|||||||
if (options.skip_single_threaded and test_target.single_threaded == true)
|
if (options.skip_single_threaded and test_target.single_threaded == true)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (options.use_llvm) |use_llvm| {
|
|
||||||
if (test_target.use_llvm != use_llvm) continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO get compiler-rt tests passing for self-hosted backends.
|
// TODO get compiler-rt tests passing for self-hosted backends.
|
||||||
if ((target.cpu.arch != .x86_64 or target.ofmt != .elf) and
|
if ((target.cpu.arch != .x86_64 or target.ofmt != .elf) and
|
||||||
test_target.use_llvm == false and mem.eql(u8, options.name, "compiler-rt"))
|
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 {
|
|||||||
return step;
|
return step;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn wouldUseLlvm(use_llvm: ?bool, query: std.Target.Query, optimize_mode: OptimizeMode) bool {
|
||||||
|
if (use_llvm) |x| return x;
|
||||||
|
if (query.ofmt == .c) return false;
|
||||||
|
switch (optimize_mode) {
|
||||||
|
.Debug => {},
|
||||||
|
else => return true,
|
||||||
|
}
|
||||||
|
const cpu_arch = query.cpu_arch orelse builtin.cpu.arch;
|
||||||
|
switch (cpu_arch) {
|
||||||
|
.x86_64 => if (std.Target.ptrBitWidth_arch_abi(cpu_arch, query.abi orelse .none) != 64) return true,
|
||||||
|
.spirv, .spirv32, .spirv64 => return false,
|
||||||
|
else => return true,
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const CAbiTestOptions = struct {
|
const CAbiTestOptions = struct {
|
||||||
test_target_filters: []const []const u8,
|
test_target_filters: []const []const u8,
|
||||||
skip_non_native: bool,
|
skip_non_native: bool,
|
||||||
|
skip_freebsd: bool,
|
||||||
|
skip_netbsd: bool,
|
||||||
|
skip_windows: bool,
|
||||||
|
skip_macos: bool,
|
||||||
|
skip_linux: bool,
|
||||||
|
skip_llvm: bool,
|
||||||
skip_release: bool,
|
skip_release: bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2517,6 +2546,14 @@ pub fn addCAbiTests(b: *std.Build, options: CAbiTestOptions) *Step {
|
|||||||
|
|
||||||
for (c_abi_targets) |c_abi_target| {
|
for (c_abi_targets) |c_abi_target| {
|
||||||
if (options.skip_non_native and !c_abi_target.target.isNative()) continue;
|
if (options.skip_non_native and !c_abi_target.target.isNative()) continue;
|
||||||
|
if (options.skip_freebsd and c_abi_target.target.os_tag == .freebsd) continue;
|
||||||
|
if (options.skip_netbsd and c_abi_target.target.os_tag == .netbsd) continue;
|
||||||
|
if (options.skip_windows and c_abi_target.target.os_tag == .windows) continue;
|
||||||
|
if (options.skip_macos and c_abi_target.target.os_tag == .macos) continue;
|
||||||
|
if (options.skip_linux and c_abi_target.target.os_tag == .linux) continue;
|
||||||
|
|
||||||
|
const would_use_llvm = wouldUseLlvm(c_abi_target.use_llvm, c_abi_target.target, .Debug);
|
||||||
|
if (options.skip_llvm and would_use_llvm) continue;
|
||||||
|
|
||||||
const resolved_target = b.resolveTargetQuery(c_abi_target.target);
|
const resolved_target = b.resolveTargetQuery(c_abi_target.target);
|
||||||
const target = resolved_target.result;
|
const target = resolved_target.result;
|
||||||
|
|||||||
@ -168,6 +168,15 @@ fn printOutput(
|
|||||||
try build_args.appendSlice(&[_][]const u8{ "-target", triple });
|
try build_args.appendSlice(&[_][]const u8{ "-target", triple });
|
||||||
try shell_out.print("-target {s} ", .{triple});
|
try shell_out.print("-target {s} ", .{triple});
|
||||||
}
|
}
|
||||||
|
if (code.use_llvm) |use_llvm| {
|
||||||
|
if (use_llvm) {
|
||||||
|
try build_args.append("-fllvm");
|
||||||
|
try shell_out.print("-fllvm", .{});
|
||||||
|
} else {
|
||||||
|
try build_args.append("-fno-llvm");
|
||||||
|
try shell_out.print("-fno-llvm", .{});
|
||||||
|
}
|
||||||
|
}
|
||||||
if (code.verbose_cimport) {
|
if (code.verbose_cimport) {
|
||||||
try build_args.append("--verbose-cimport");
|
try build_args.append("--verbose-cimport");
|
||||||
try shell_out.print("--verbose-cimport ", .{});
|
try shell_out.print("--verbose-cimport ", .{});
|
||||||
@ -224,7 +233,6 @@ fn printOutput(
|
|||||||
break :code_block;
|
break :code_block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const target_query = try std.Target.Query.parse(.{
|
const target_query = try std.Target.Query.parse(.{
|
||||||
.arch_os_abi = code.target_str orelse "native",
|
.arch_os_abi = code.target_str orelse "native",
|
||||||
});
|
});
|
||||||
@ -319,6 +327,16 @@ fn printOutput(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (code.use_llvm) |use_llvm| {
|
||||||
|
if (use_llvm) {
|
||||||
|
try test_args.append("-fllvm");
|
||||||
|
try shell_out.print("-fllvm", .{});
|
||||||
|
} else {
|
||||||
|
try test_args.append("-fno-llvm");
|
||||||
|
try shell_out.print("-fno-llvm", .{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const result = run(arena, &env_map, tmp_dir_path, test_args.items) catch
|
const result = run(arena, &env_map, tmp_dir_path, test_args.items) catch
|
||||||
fatal("test failed", .{});
|
fatal("test failed", .{});
|
||||||
const escaped_stderr = try escapeHtml(arena, result.stderr);
|
const escaped_stderr = try escapeHtml(arena, result.stderr);
|
||||||
@ -469,6 +487,15 @@ fn printOutput(
|
|||||||
try build_args.appendSlice(&[_][]const u8{ "-target", triple });
|
try build_args.appendSlice(&[_][]const u8{ "-target", triple });
|
||||||
try shell_out.print("-target {s} ", .{triple});
|
try shell_out.print("-target {s} ", .{triple});
|
||||||
}
|
}
|
||||||
|
if (code.use_llvm) |use_llvm| {
|
||||||
|
if (use_llvm) {
|
||||||
|
try build_args.append("-fllvm");
|
||||||
|
try shell_out.print("-fllvm", .{});
|
||||||
|
} else {
|
||||||
|
try build_args.append("-fno-llvm");
|
||||||
|
try shell_out.print("-fno-llvm", .{});
|
||||||
|
}
|
||||||
|
}
|
||||||
for (code.additional_options) |option| {
|
for (code.additional_options) |option| {
|
||||||
try build_args.append(option);
|
try build_args.append(option);
|
||||||
try shell_out.print("{s} ", .{option});
|
try shell_out.print("{s} ", .{option});
|
||||||
@ -538,6 +565,15 @@ fn printOutput(
|
|||||||
try test_args.appendSlice(&[_][]const u8{ "-target", triple });
|
try test_args.appendSlice(&[_][]const u8{ "-target", triple });
|
||||||
try shell_out.print("-target {s} ", .{triple});
|
try shell_out.print("-target {s} ", .{triple});
|
||||||
}
|
}
|
||||||
|
if (code.use_llvm) |use_llvm| {
|
||||||
|
if (use_llvm) {
|
||||||
|
try test_args.append("-fllvm");
|
||||||
|
try shell_out.print("-fllvm", .{});
|
||||||
|
} else {
|
||||||
|
try test_args.append("-fno-llvm");
|
||||||
|
try shell_out.print("-fno-llvm", .{});
|
||||||
|
}
|
||||||
|
}
|
||||||
if (code.link_mode) |link_mode| {
|
if (code.link_mode) |link_mode| {
|
||||||
switch (link_mode) {
|
switch (link_mode) {
|
||||||
.static => {
|
.static => {
|
||||||
@ -827,6 +863,7 @@ const Code = struct {
|
|||||||
verbose_cimport: bool,
|
verbose_cimport: bool,
|
||||||
just_check_syntax: bool,
|
just_check_syntax: bool,
|
||||||
additional_options: []const []const u8,
|
additional_options: []const []const u8,
|
||||||
|
use_llvm: ?bool,
|
||||||
|
|
||||||
const Id = union(enum) {
|
const Id = union(enum) {
|
||||||
@"test",
|
@"test",
|
||||||
@ -886,6 +923,7 @@ fn parseManifest(arena: Allocator, source_bytes: []const u8) !Code {
|
|||||||
var link_libc = false;
|
var link_libc = false;
|
||||||
var disable_cache = false;
|
var disable_cache = false;
|
||||||
var verbose_cimport = false;
|
var verbose_cimport = false;
|
||||||
|
var use_llvm: ?bool = null;
|
||||||
|
|
||||||
while (it.next()) |prefixed_line| {
|
while (it.next()) |prefixed_line| {
|
||||||
const line = skipPrefix(prefixed_line);
|
const line = skipPrefix(prefixed_line);
|
||||||
@ -901,6 +939,10 @@ fn parseManifest(arena: Allocator, source_bytes: []const u8) !Code {
|
|||||||
try additional_options.append(arena, line["additional_option=".len..]);
|
try additional_options.append(arena, line["additional_option=".len..]);
|
||||||
} else if (mem.startsWith(u8, line, "target=")) {
|
} else if (mem.startsWith(u8, line, "target=")) {
|
||||||
target_str = line["target=".len..];
|
target_str = line["target=".len..];
|
||||||
|
} else if (mem.eql(u8, line, "llvm=true")) {
|
||||||
|
use_llvm = true;
|
||||||
|
} else if (mem.eql(u8, line, "llvm=false")) {
|
||||||
|
use_llvm = false;
|
||||||
} else if (mem.eql(u8, line, "link_libc")) {
|
} else if (mem.eql(u8, line, "link_libc")) {
|
||||||
link_libc = true;
|
link_libc = true;
|
||||||
} else if (mem.eql(u8, line, "disable_cache")) {
|
} else if (mem.eql(u8, line, "disable_cache")) {
|
||||||
@ -923,6 +965,7 @@ fn parseManifest(arena: Allocator, source_bytes: []const u8) !Code {
|
|||||||
.disable_cache = disable_cache,
|
.disable_cache = disable_cache,
|
||||||
.verbose_cimport = verbose_cimport,
|
.verbose_cimport = verbose_cimport,
|
||||||
.just_check_syntax = just_check_syntax,
|
.just_check_syntax = just_check_syntax,
|
||||||
|
.use_llvm = use_llvm,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user