From 05a877a9a11c401c42d6c0935641a010394f3fb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 14 Dec 2024 04:28:21 +0100 Subject: [PATCH 01/10] compiler-rt: More accurately export Windows Arm functions. --- lib/compiler_rt/arm.zig | 8 ++++---- lib/compiler_rt/common.zig | 6 +++++- lib/compiler_rt/fixdfdi.zig | 6 +----- lib/compiler_rt/fixsfdi.zig | 6 +----- lib/compiler_rt/fixunsdfdi.zig | 6 +----- lib/compiler_rt/fixunssfdi.zig | 6 +----- lib/compiler_rt/floatdidf.zig | 6 +----- lib/compiler_rt/floatdisf.zig | 6 +----- lib/compiler_rt/floatundidf.zig | 6 +----- lib/compiler_rt/floatundisf.zig | 6 +----- 10 files changed, 17 insertions(+), 45 deletions(-) diff --git a/lib/compiler_rt/arm.zig b/lib/compiler_rt/arm.zig index b71829688aab..252c26ae6b92 100644 --- a/lib/compiler_rt/arm.zig +++ b/lib/compiler_rt/arm.zig @@ -15,11 +15,11 @@ comptime { @export(&__aeabi_unwind_cpp_pr1, .{ .name = "__aeabi_unwind_cpp_pr1", .linkage = common.linkage, .visibility = common.visibility }); @export(&__aeabi_unwind_cpp_pr2, .{ .name = "__aeabi_unwind_cpp_pr2", .linkage = common.linkage, .visibility = common.visibility }); - @export(&__aeabi_ldivmod, .{ .name = if (target.isMinGW()) "__rt_sdiv64" else "__aeabi_ldivmod", .linkage = common.linkage, .visibility = common.visibility }); - @export(&__aeabi_uldivmod, .{ .name = if (target.isMinGW()) "__rt_udiv64" else "__aeabi_uldivmod", .linkage = common.linkage, .visibility = common.visibility }); + @export(&__aeabi_ldivmod, .{ .name = if (common.want_windows_arm_abi) "__rt_sdiv64" else "__aeabi_ldivmod", .linkage = common.linkage, .visibility = common.visibility }); + @export(&__aeabi_uldivmod, .{ .name = if (common.want_windows_arm_abi) "__rt_udiv64" else "__aeabi_uldivmod", .linkage = common.linkage, .visibility = common.visibility }); - @export(&__aeabi_idivmod, .{ .name = if (target.isMinGW()) "__rt_sdiv" else "__aeabi_idivmod", .linkage = common.linkage, .visibility = common.visibility }); - @export(&__aeabi_uidivmod, .{ .name = if (target.isMinGW()) "__rt_udiv" else "__aeabi_uidivmod", .linkage = common.linkage, .visibility = common.visibility }); + @export(&__aeabi_idivmod, .{ .name = if (common.want_windows_arm_abi) "__rt_sdiv" else "__aeabi_idivmod", .linkage = common.linkage, .visibility = common.visibility }); + @export(&__aeabi_uidivmod, .{ .name = if (common.want_windows_arm_abi) "__rt_udiv" else "__aeabi_uidivmod", .linkage = common.linkage, .visibility = common.visibility }); @export(&__aeabi_memcpy, .{ .name = "__aeabi_memcpy", .linkage = common.linkage, .visibility = common.visibility }); @export(&__aeabi_memcpy4, .{ .name = "__aeabi_memcpy4", .linkage = common.linkage, .visibility = common.visibility }); diff --git a/lib/compiler_rt/common.zig b/lib/compiler_rt/common.zig index 7b3586412003..d85c05ba84ea 100644 --- a/lib/compiler_rt/common.zig +++ b/lib/compiler_rt/common.zig @@ -9,11 +9,13 @@ else if (ofmt_c) .strong else .weak; + /// Determines the symbol's visibility to other objects. /// For WebAssembly this allows the symbol to be resolved to other modules, but will not /// export it to the host runtime. pub const visibility: std.builtin.SymbolVisibility = if (builtin.target.isWasm() and linkage != .internal) .hidden else .default; + pub const want_aeabi = switch (builtin.abi) { .eabi, .eabihf, @@ -29,7 +31,9 @@ pub const want_aeabi = switch (builtin.abi) { }, else => false, }; -pub const want_mingw_arm_abi = builtin.cpu.arch.isArm() and builtin.target.isMinGW(); + +/// These functions are provided by libc when targeting MSVC, but not MinGW. +pub const want_windows_arm_abi = builtin.cpu.arch.isArm() and builtin.os.tag == .windows and (builtin.abi.isGnu() or !builtin.link_libc); pub const want_ppc_abi = builtin.cpu.arch.isPowerPC(); diff --git a/lib/compiler_rt/fixdfdi.zig b/lib/compiler_rt/fixdfdi.zig index b9bc5797b9cb..044bc6abe17c 100644 --- a/lib/compiler_rt/fixdfdi.zig +++ b/lib/compiler_rt/fixdfdi.zig @@ -8,11 +8,7 @@ comptime { if (common.want_aeabi) { @export(&__aeabi_d2lz, .{ .name = "__aeabi_d2lz", .linkage = common.linkage, .visibility = common.visibility }); } else { - @export(&__fixdfdi, .{ .name = "__fixdfdi", .linkage = common.linkage, .visibility = common.visibility }); - - if (common.want_mingw_arm_abi) { - @export(&__fixdfdi, .{ .name = "__dtoi64", .linkage = common.linkage, .visibility = common.visibility }); - } + @export(&__fixdfdi, .{ .name = if (common.want_windows_arm_abi) "__dtoi64" else "__fixdfdi", .linkage = common.linkage, .visibility = common.visibility }); } } diff --git a/lib/compiler_rt/fixsfdi.zig b/lib/compiler_rt/fixsfdi.zig index 192614bd7975..bd6ba9276d45 100644 --- a/lib/compiler_rt/fixsfdi.zig +++ b/lib/compiler_rt/fixsfdi.zig @@ -8,11 +8,7 @@ comptime { if (common.want_aeabi) { @export(&__aeabi_f2lz, .{ .name = "__aeabi_f2lz", .linkage = common.linkage, .visibility = common.visibility }); } else { - @export(&__fixsfdi, .{ .name = "__fixsfdi", .linkage = common.linkage, .visibility = common.visibility }); - - if (common.want_mingw_arm_abi) { - @export(&__fixsfdi, .{ .name = "__stoi64", .linkage = common.linkage, .visibility = common.visibility }); - } + @export(&__fixsfdi, .{ .name = if (common.want_windows_arm_abi) "__stoi64" else "__fixsfdi", .linkage = common.linkage, .visibility = common.visibility }); } } diff --git a/lib/compiler_rt/fixunsdfdi.zig b/lib/compiler_rt/fixunsdfdi.zig index 86a4fa9de117..b39b0538fbc2 100644 --- a/lib/compiler_rt/fixunsdfdi.zig +++ b/lib/compiler_rt/fixunsdfdi.zig @@ -8,11 +8,7 @@ comptime { if (common.want_aeabi) { @export(&__aeabi_d2ulz, .{ .name = "__aeabi_d2ulz", .linkage = common.linkage, .visibility = common.visibility }); } else { - @export(&__fixunsdfdi, .{ .name = "__fixunsdfdi", .linkage = common.linkage, .visibility = common.visibility }); - - if (common.want_mingw_arm_abi) { - @export(&__fixunsdfdi, .{ .name = "__dtou64", .linkage = common.linkage, .visibility = common.visibility }); - } + @export(&__fixunsdfdi, .{ .name = if (common.want_windows_arm_abi) "__dtou64" else "__fixunsdfdi", .linkage = common.linkage, .visibility = common.visibility }); } } diff --git a/lib/compiler_rt/fixunssfdi.zig b/lib/compiler_rt/fixunssfdi.zig index 81d1c77f06d1..7f65c6c64db2 100644 --- a/lib/compiler_rt/fixunssfdi.zig +++ b/lib/compiler_rt/fixunssfdi.zig @@ -8,11 +8,7 @@ comptime { if (common.want_aeabi) { @export(&__aeabi_f2ulz, .{ .name = "__aeabi_f2ulz", .linkage = common.linkage, .visibility = common.visibility }); } else { - @export(&__fixunssfdi, .{ .name = "__fixunssfdi", .linkage = common.linkage, .visibility = common.visibility }); - - if (common.want_mingw_arm_abi) { - @export(&__fixunssfdi, .{ .name = "__stou64", .linkage = common.linkage, .visibility = common.visibility }); - } + @export(&__fixunssfdi, .{ .name = if (common.want_windows_arm_abi) "__stou64" else "__fixunssfdi", .linkage = common.linkage, .visibility = common.visibility }); } } diff --git a/lib/compiler_rt/floatdidf.zig b/lib/compiler_rt/floatdidf.zig index fc145e836de7..2396624dc378 100644 --- a/lib/compiler_rt/floatdidf.zig +++ b/lib/compiler_rt/floatdidf.zig @@ -8,11 +8,7 @@ comptime { if (common.want_aeabi) { @export(&__aeabi_l2d, .{ .name = "__aeabi_l2d", .linkage = common.linkage, .visibility = common.visibility }); } else { - @export(&__floatdidf, .{ .name = "__floatdidf", .linkage = common.linkage, .visibility = common.visibility }); - - if (common.want_mingw_arm_abi) { - @export(&__floatdidf, .{ .name = "__i64tod", .linkage = common.linkage, .visibility = common.visibility }); - } + @export(&__floatdidf, .{ .name = if (common.want_windows_arm_abi) "__i64tod" else "__floatdidf", .linkage = common.linkage, .visibility = common.visibility }); } } diff --git a/lib/compiler_rt/floatdisf.zig b/lib/compiler_rt/floatdisf.zig index d1c9515f9a3e..1cc159ccaa3b 100644 --- a/lib/compiler_rt/floatdisf.zig +++ b/lib/compiler_rt/floatdisf.zig @@ -8,11 +8,7 @@ comptime { if (common.want_aeabi) { @export(&__aeabi_l2f, .{ .name = "__aeabi_l2f", .linkage = common.linkage, .visibility = common.visibility }); } else { - @export(&__floatdisf, .{ .name = "__floatdisf", .linkage = common.linkage, .visibility = common.visibility }); - - if (common.want_mingw_arm_abi) { - @export(&__floatdisf, .{ .name = "__i64tos", .linkage = common.linkage, .visibility = common.visibility }); - } + @export(&__floatdisf, .{ .name = if (common.want_windows_arm_abi) "__i64tos" else "__floatdisf", .linkage = common.linkage, .visibility = common.visibility }); } } diff --git a/lib/compiler_rt/floatundidf.zig b/lib/compiler_rt/floatundidf.zig index 3448f0cf2047..159b6abd1ae9 100644 --- a/lib/compiler_rt/floatundidf.zig +++ b/lib/compiler_rt/floatundidf.zig @@ -8,11 +8,7 @@ comptime { if (common.want_aeabi) { @export(&__aeabi_ul2d, .{ .name = "__aeabi_ul2d", .linkage = common.linkage, .visibility = common.visibility }); } else { - @export(&__floatundidf, .{ .name = "__floatundidf", .linkage = common.linkage, .visibility = common.visibility }); - - if (common.want_mingw_arm_abi) { - @export(&__floatundidf, .{ .name = "__u64tod", .linkage = common.linkage, .visibility = common.visibility }); - } + @export(&__floatundidf, .{ .name = if (common.want_windows_arm_abi) "__u64tod" else "__floatundidf", .linkage = common.linkage, .visibility = common.visibility }); } } diff --git a/lib/compiler_rt/floatundisf.zig b/lib/compiler_rt/floatundisf.zig index 9054982b5409..caecbd0cd831 100644 --- a/lib/compiler_rt/floatundisf.zig +++ b/lib/compiler_rt/floatundisf.zig @@ -8,11 +8,7 @@ comptime { if (common.want_aeabi) { @export(&__aeabi_ul2f, .{ .name = "__aeabi_ul2f", .linkage = common.linkage, .visibility = common.visibility }); } else { - @export(&__floatundisf, .{ .name = "__floatundisf", .linkage = common.linkage, .visibility = common.visibility }); - - if (common.want_mingw_arm_abi) { - @export(&__floatundisf, .{ .name = "__u64tos", .linkage = common.linkage, .visibility = common.visibility }); - } + @export(&__floatundisf, .{ .name = if (common.want_windows_arm_abi) "__u64tos" else "__floatundisf", .linkage = common.linkage, .visibility = common.visibility }); } } From 35da1e1e8ffe5201bfe3ff1f5a9a40b73121916c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 14 Dec 2024 12:15:50 +0100 Subject: [PATCH 02/10] compiler-rt: Don't export __a(u)ll(div,rem) if linking libc. libc provides these when targeting MSVC. --- lib/compiler_rt/aulldiv.zig | 2 +- lib/compiler_rt/aullrem.zig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/compiler_rt/aulldiv.zig b/lib/compiler_rt/aulldiv.zig index 6d822b7b86fa..8a7baaad3e7c 100644 --- a/lib/compiler_rt/aulldiv.zig +++ b/lib/compiler_rt/aulldiv.zig @@ -8,7 +8,7 @@ const common = @import("common.zig"); pub const panic = common.panic; comptime { - if (arch == .x86 and os == .windows and (abi == .msvc or abi == .itanium) and builtin.zig_backend != .stage2_c) { + if (arch == .x86 and os == .windows and (abi == .msvc or abi == .itanium) and !builtin.link_libc) { // Don't let LLVM apply the stdcall name mangling on those MSVC builtins @export(&_alldiv, .{ .name = "\x01__alldiv", .linkage = common.linkage, .visibility = common.visibility }); @export(&_aulldiv, .{ .name = "\x01__aulldiv", .linkage = common.linkage, .visibility = common.visibility }); diff --git a/lib/compiler_rt/aullrem.zig b/lib/compiler_rt/aullrem.zig index 5c4d0588f786..182ad4e1de23 100644 --- a/lib/compiler_rt/aullrem.zig +++ b/lib/compiler_rt/aullrem.zig @@ -8,7 +8,7 @@ const common = @import("common.zig"); pub const panic = common.panic; comptime { - if (arch == .x86 and os == .windows and (abi == .msvc or abi == .itanium) and builtin.zig_backend != .stage2_c) { + if (arch == .x86 and os == .windows and (abi == .msvc or abi == .itanium) and !builtin.link_libc) { // Don't let LLVM apply the stdcall name mangling on those MSVC builtins @export(&_allrem, .{ .name = "\x01__allrem", .linkage = common.linkage, .visibility = common.visibility }); @export(&_aullrem, .{ .name = "\x01__aullrem", .linkage = common.linkage, .visibility = common.visibility }); From 673544b783fb81d5fd970e132e0d78f234498603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 14 Dec 2024 04:28:46 +0100 Subject: [PATCH 03/10] compiler-rt: Pass called functions into inline asm so the compiler sees the usage. --- lib/compiler_rt/arm.zig | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/lib/compiler_rt/arm.zig b/lib/compiler_rt/arm.zig index 252c26ae6b92..0cc268f18964 100644 --- a/lib/compiler_rt/arm.zig +++ b/lib/compiler_rt/arm.zig @@ -136,11 +136,14 @@ pub fn __aeabi_uidivmod() callconv(.Naked) void { \\ push {lr} \\ sub sp, #4 \\ mov r2, sp - \\ bl __udivmodsi4 + \\ bl %[__udivmodsi4] \\ ldr r1, [sp] \\ add sp, #4 \\ pop {pc} - ::: "memory"); + : + : [__udivmodsi4] "X" (&__udivmodsi4), + : "memory" + ); unreachable; } @@ -152,12 +155,15 @@ pub fn __aeabi_uldivmod() callconv(.Naked) void { \\ sub sp, #16 \\ add r4, sp, #8 \\ str r4, [sp] - \\ bl __udivmoddi4 + \\ bl %[__udivmoddi4] \\ ldr r2, [sp, #8] \\ ldr r3, [sp, #12] \\ add sp, #16 \\ pop {r4, pc} - ::: "memory"); + : + : [__udivmoddi4] "X" (&__udivmoddi4), + : "memory" + ); unreachable; } @@ -168,11 +174,14 @@ pub fn __aeabi_idivmod() callconv(.Naked) void { \\ push {lr} \\ sub sp, #4 \\ mov r2, sp - \\ bl __divmodsi4 + \\ bl %[__divmodsi4] \\ ldr r1, [sp] \\ add sp, #4 \\ pop {pc} - ::: "memory"); + : + : [__divmodsi4] "X" (&__divmodsi4), + : "memory" + ); unreachable; } @@ -184,12 +193,15 @@ pub fn __aeabi_ldivmod() callconv(.Naked) void { \\ sub sp, #16 \\ add r4, sp, #8 \\ str r4, [sp] - \\ bl __divmoddi4 + \\ bl %[__divmoddi4] \\ ldr r2, [sp, #8] \\ ldr r3, [sp, #12] \\ add sp, #16 \\ pop {r4, pc} - ::: "memory"); + : + : [__divmoddi4] "X" (&__divmoddi4), + : "memory" + ); unreachable; } From b95081209a83be39b52b3f304387f75cfab22e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 24 Jan 2025 04:01:18 +0100 Subject: [PATCH 04/10] compiler: Explicitly specify loongarch ABI when talking to LLVM. Necessary because of: https://github.com/llvm/llvm-project/commit/dc665fa5f5b8b572479ceac6bf32e0174de65f1e --- src/target.zig | 55 +++++++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 23 deletions(-) diff --git a/src/target.zig b/src/target.zig index 99e0fd1faa08..b7e1c73ef124 100644 --- a/src/target.zig +++ b/src/target.zig @@ -500,33 +500,42 @@ pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 { // Once our self-hosted linker can handle both ABIs, this hack should go away. if (target.cpu.arch == .powerpc64) return "elfv2"; - switch (target.cpu.arch) { - .riscv64 => { + return switch (target.cpu.arch) { + // TODO: `muslsf` and `muslf32` in LLVM 20. + .loongarch64 => switch (target.abi) { + .gnusf => "lp64s", + .gnuf32 => "lp64f", + else => "lp64d", + }, + .loongarch32 => switch (target.abi) { + .gnusf => "ilp32s", + .gnuf32 => "ilp32f", + else => "ilp32d", + }, + .riscv64 => b: { const featureSetHas = std.Target.riscv.featureSetHas; - if (featureSetHas(target.cpu.features, .e)) { - return "lp64e"; - } else if (featureSetHas(target.cpu.features, .d)) { - return "lp64d"; - } else if (featureSetHas(target.cpu.features, .f)) { - return "lp64f"; - } else { - return "lp64"; - } + break :b if (featureSetHas(target.cpu.features, .e)) + "lp64e" + else if (featureSetHas(target.cpu.features, .d)) + "lp64d" + else if (featureSetHas(target.cpu.features, .f)) + "lp64f" + else + "lp64"; }, - .riscv32 => { + .riscv32 => b: { const featureSetHas = std.Target.riscv.featureSetHas; - if (featureSetHas(target.cpu.features, .e)) { - return "ilp32e"; - } else if (featureSetHas(target.cpu.features, .d)) { - return "ilp32d"; - } else if (featureSetHas(target.cpu.features, .f)) { - return "ilp32f"; - } else { - return "ilp32"; - } + break :b if (featureSetHas(target.cpu.features, .e)) + "ilp32e" + else if (featureSetHas(target.cpu.features, .d)) + "ilp32d" + else if (featureSetHas(target.cpu.features, .f)) + "ilp32f" + else + "ilp32"; }, - else => return null, - } + else => null, + }; } /// This function returns 1 if function alignment is not observable or settable. Note that this From cd8c92fc40993d307e891be27bfd86574c2ce85d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 24 Jan 2025 04:27:00 +0100 Subject: [PATCH 05/10] compiler: Explicitly specify ABI for arm, mips, and powerpc when talking to LLVM. See 652c5151429e279f70396ee601416c87a70c1bec. Better to avoid relying on default LLVM behavior going forward. --- src/target.zig | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/target.zig b/src/target.zig index b7e1c73ef124..546d10b0bcfd 100644 --- a/src/target.zig +++ b/src/target.zig @@ -482,16 +482,6 @@ pub fn arePointersLogical(target: std.Target, as: AddressSpace) bool { } pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 { - // This special-casing should be removed with LLVM 20. - switch (target.cpu.arch) { - .mips, .mipsel => return "o32", - .mips64, .mips64el => return switch (target.abi) { - .gnuabin32, .muslabin32 => "n32", - else => "n64", - }, - else => {}, - } - // LLD does not support ELFv1. Rather than having LLVM produce ELFv1 code and then linking it // into a broken ELFv2 binary, just force LLVM to use ELFv2 as well. This will break when glibc // is linked as glibc only supports ELFv2 for little endian, but there's nothing we can do about @@ -501,6 +491,7 @@ pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 { if (target.cpu.arch == .powerpc64) return "elfv2"; return switch (target.cpu.arch) { + .arm, .armeb, .thumb, .thumbeb => "aapcs", // TODO: `muslsf` and `muslf32` in LLVM 20. .loongarch64 => switch (target.abi) { .gnusf => "lp64s", @@ -512,6 +503,20 @@ pub fn llvmMachineAbi(target: std.Target) ?[:0]const u8 { .gnuf32 => "ilp32f", else => "ilp32d", }, + .mips, .mipsel => "o32", + .mips64, .mips64el => switch (target.abi) { + .gnuabin32, .muslabin32 => "n32", + else => "n64", + }, + .powerpc64 => switch (target.os.tag) { + .freebsd => if (target.os.version_range.semver.isAtLeast(.{ .major = 13, .minor = 0, .patch = 0 }) orelse false) + "elfv2" + else + "elfv1", + .openbsd => "elfv2", + else => if (target.abi.isMusl()) "elfv2" else "elfv1", + }, + .powerpc64le => "elfv2", .riscv64 => b: { const featureSetHas = std.Target.riscv.featureSetHas; break :b if (featureSetHas(target.cpu.features, .e)) From afe2fed34dd960afb44f88cfe6ce088e1817cb5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 16 Dec 2024 06:07:02 +0100 Subject: [PATCH 06/10] link: Set machine and float ABI when invoking ld.lld and lld-link. If this isn't done, LTO can completely miscompile the input bitcode modules for certain targets where we need to explicitly set these ABIs (because LLVM's defaults are bad). --- src/link/Coff.zig | 7 +++++++ src/link/Elf.zig | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 9bd3bd76e92c..3b239246ca54 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1876,6 +1876,13 @@ fn linkWithLLD(coff: *Coff, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: if (comp.version) |version| { try argv.append(try allocPrint(arena, "-VERSION:{}.{}", .{ version.major, version.minor })); } + + if (target_util.llvmMachineAbi(target)) |mabi| { + try argv.append(try allocPrint(arena, "-MLLVM:-target-abi={s}", .{mabi})); + } + + try argv.append(try allocPrint(arena, "-MLLVM:-float-abi={s}", .{if (target.abi.floatAbi() == .hard) "hard" else "soft"})); + if (comp.config.lto != .none) { switch (optimize_mode) { .Debug => {}, diff --git a/src/link/Elf.zig b/src/link/Elf.zig index ea2fa56a5d9a..edd45f65ee8b 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -1700,6 +1700,18 @@ fn linkWithLLD(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_node: s try argv.append(try std.fmt.allocPrint(arena, "--sysroot={s}", .{sysroot})); } + if (target_util.llvmMachineAbi(target)) |mabi| { + try argv.appendSlice(&.{ + "-mllvm", + try std.fmt.allocPrint(arena, "-target-abi={s}", .{mabi}), + }); + } + + try argv.appendSlice(&.{ + "-mllvm", + try std.fmt.allocPrint(arena, "-float-abi={s}", .{if (target.abi.floatAbi() == .hard) "hard" else "soft"}), + }); + if (comp.config.lto != .none) { switch (comp.root_mod.optimize_mode) { .Debug => {}, From 1e8b82f6b4852211b76a54da14fc8cf0351ada09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 25 Jan 2025 14:47:14 +0100 Subject: [PATCH 07/10] compiler: Rework LTO settings for some Zig-provided libraries. * compiler-rt and mingw32 have both run into LLD bugs, and LLVM disables LTO for its compiler-rt, so disable LTO for these. * While we haven't run into any bugs in it, LLVM disables LTO for its libtsan, so follow suit just to be safe. * Allow LTO for libfuzzer as LLVM does. --- src/Compilation.zig | 19 +++++++++++++++---- src/libtsan.zig | 2 ++ src/mingw.zig | 2 ++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 1a056c1c04a4..4a57fdcc9d0d 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -3695,15 +3695,19 @@ fn performAllTheWorkInner( // In case it failed last time, try again. `clearMiscFailures` was already // called at the start of `update`. if (comp.queued_jobs.compiler_rt_lib and comp.compiler_rt_lib == null) { - comp.link_task_wait_group.spawnManager(buildRt, .{ comp, "compiler_rt.zig", .compiler_rt, .Lib, &comp.compiler_rt_lib, main_progress_node }); + // LLVM disables LTO for its compiler-rt and we've had various issues with LTO of our + // compiler-rt due to LLD bugs as well, e.g.: + // + // https://github.com/llvm/llvm-project/issues/43698#issuecomment-2542660611 + comp.link_task_wait_group.spawnManager(buildRt, .{ comp, "compiler_rt.zig", .compiler_rt, .Lib, false, &comp.compiler_rt_lib, main_progress_node }); } if (comp.queued_jobs.compiler_rt_obj and comp.compiler_rt_obj == null) { - comp.link_task_wait_group.spawnManager(buildRt, .{ comp, "compiler_rt.zig", .compiler_rt, .Obj, &comp.compiler_rt_obj, main_progress_node }); + comp.link_task_wait_group.spawnManager(buildRt, .{ comp, "compiler_rt.zig", .compiler_rt, .Obj, false, &comp.compiler_rt_obj, main_progress_node }); } if (comp.queued_jobs.fuzzer_lib and comp.fuzzer_lib == null) { - comp.link_task_wait_group.spawnManager(buildRt, .{ comp, "fuzzer.zig", .libfuzzer, .Lib, &comp.fuzzer_lib, main_progress_node }); + comp.link_task_wait_group.spawnManager(buildRt, .{ comp, "fuzzer.zig", .libfuzzer, .Lib, true, &comp.fuzzer_lib, main_progress_node }); } if (comp.queued_jobs.glibc_shared_objects) { @@ -4635,12 +4639,14 @@ fn buildRt( root_source_name: []const u8, misc_task: MiscTask, output_mode: std.builtin.OutputMode, + allow_lto: bool, out: *?CrtFile, prog_node: std.Progress.Node, ) void { comp.buildOutputFromZig( root_source_name, output_mode, + allow_lto, out, misc_task, prog_node, @@ -4748,6 +4754,7 @@ fn buildZigLibc(comp: *Compilation, prog_node: std.Progress.Node) void { comp.buildOutputFromZig( "c.zig", .Lib, + true, &comp.libc_static_lib, .zig_libc, prog_node, @@ -6453,6 +6460,7 @@ fn buildOutputFromZig( comp: *Compilation, src_basename: []const u8, output_mode: std.builtin.OutputMode, + allow_lto: bool, out: *?CrtFile, misc_task_tag: MiscTask, prog_node: std.Progress.Node, @@ -6481,6 +6489,7 @@ fn buildOutputFromZig( .root_strip = strip, .link_libc = comp.config.link_libc, .any_unwind_tables = comp.root_mod.unwind_tables != .none, + .lto = if (allow_lto) comp.config.lto else .none, }); const root_mod = try Package.Module.create(arena, .{ @@ -6581,6 +6590,8 @@ pub const CrtFileOptions = struct { unwind_tables: ?std.builtin.UnwindTables = null, pic: ?bool = null, no_builtin: ?bool = null, + + allow_lto: bool = true, }; pub fn build_crt_file( @@ -6619,7 +6630,7 @@ pub fn build_crt_file( .link_libc = false, .any_unwind_tables = options.unwind_tables != .none, .lto = switch (output_mode) { - .Lib => comp.config.lto, + .Lib => if (options.allow_lto) comp.config.lto else .none, .Obj, .Exe => .none, }, }); diff --git a/src/libtsan.zig b/src/libtsan.zig index 8b2427df1ba2..d5fffd2b6c41 100644 --- a/src/libtsan.zig +++ b/src/libtsan.zig @@ -65,6 +65,8 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo .root_strip = strip, .link_libc = true, .link_libcpp = link_libcpp, + // LLVM disables LTO for its libtsan. + .lto = .none, }) catch |err| { comp.setMiscFailure( .libtsan, diff --git a/src/mingw.zig b/src/mingw.zig index 47aff05133af..17c0a49b11ef 100644 --- a/src/mingw.zig +++ b/src/mingw.zig @@ -175,6 +175,8 @@ pub fn buildCrtFile(comp: *Compilation, crt_file: CrtFile, prog_node: std.Progre return comp.build_crt_file("mingw32", .Lib, .@"mingw-w64 mingw32.lib", prog_node, c_source_files.items, .{ .unwind_tables = unwind_tables, + // https://github.com/llvm/llvm-project/issues/43698#issuecomment-2542660611 + .allow_lto = false, }); }, } From 46a1a158617da904fa381b8fcba8d975c30e4e0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 25 Jan 2025 14:58:04 +0100 Subject: [PATCH 08/10] Compilation: Remove the _tls_index hack for MinGW. No longer needed since we disable LTO for mingw32. --- src/Compilation.zig | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/Compilation.zig b/src/Compilation.zig index 4a57fdcc9d0d..75b7f5e6021b 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1881,18 +1881,6 @@ pub fn create(gpa: Allocator, arena: Allocator, options: CreateOptions) !*Compil comp.remaining_prelink_tasks += 1; } - if (target.isMinGW() and comp.config.any_non_single_threaded) { - // LLD might drop some symbols as unused during LTO and GCing, therefore, - // we force mark them for resolution here. - - const tls_index_sym = switch (target.cpu.arch) { - .x86 => "__tls_index", - else => "_tls_index", - }; - - try comp.force_undefined_symbols.put(comp.gpa, tls_index_sym, {}); - } - if (comp.include_compiler_rt and capable_of_building_compiler_rt) { if (is_exe_or_dyn_lib) { log.debug("queuing a job to build compiler_rt_lib", .{}); From 9f116d38b8fcc71570f6aed6707ed769b22ceea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 25 Jan 2025 14:53:25 +0100 Subject: [PATCH 09/10] libtsan: Build with unwind tables like upstream. --- src/libtsan.zig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libtsan.zig b/src/libtsan.zig index d5fffd2b6c41..cd28b8694a55 100644 --- a/src/libtsan.zig +++ b/src/libtsan.zig @@ -53,6 +53,8 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo const optimize_mode = comp.compilerRtOptMode(); const strip = comp.compilerRtStrip(); const link_libcpp = target.isDarwin(); + const unwind_tables: std.builtin.UnwindTables = + if (target.cpu.arch == .x86 and target.os.tag == .windows) .none else .@"async"; const config = Compilation.Config.resolve(.{ .output_mode = output_mode, @@ -65,6 +67,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo .root_strip = strip, .link_libc = true, .link_libcpp = link_libcpp, + .any_unwind_tables = unwind_tables != .none, // LLVM disables LTO for its libtsan. .lto = .none, }) catch |err| { @@ -97,6 +100,7 @@ pub fn buildTsan(comp: *Compilation, prog_node: std.Progress.Node) BuildError!vo .red_zone = comp.root_mod.red_zone, .omit_frame_pointer = optimize_mode != .Debug and !target.os.tag.isDarwin(), .valgrind = false, + .unwind_tables = unwind_tables, .optimize_mode = optimize_mode, .structured_cfg = comp.root_mod.structured_cfg, .pic = true, From b60e39fe8f50783509e3cfe7a3888e1611b063c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 14 Dec 2024 06:07:01 +0100 Subject: [PATCH 10/10] Compilation: Disable LTO by default. LLD has too many LTO bugs, and we're dropping the LLD dependency soon anyway. --- src/Compilation/Config.zig | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/Compilation/Config.zig b/src/Compilation/Config.zig index 41a80772033f..ee175cce1161 100644 --- a/src/Compilation/Config.zig +++ b/src/Compilation/Config.zig @@ -295,27 +295,8 @@ pub fn resolve(options: Options) ResolveError!Config { } if (options.lto) |x| break :b x; - if (!options.any_c_source_files) break :b .none; - - // https://github.com/llvm/llvm-project/pull/116537 - switch (target.abi) { - .gnuabin32, - .gnuilp32, - .gnux32, - .ilp32, - .muslabin32, - .muslx32, - => break :b .none, - else => {}, - } - break :b switch (options.output_mode) { - .Lib, .Obj => .none, - .Exe => switch (root_optimize_mode) { - .Debug => .none, - .ReleaseSafe, .ReleaseFast, .ReleaseSmall => .full, - }, - }; + break :b .none; }; const link_libcpp = b: {