From 099361c14699cc28eb3fcefd1adf3bfd509883a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Tue, 20 Oct 2026 08:50:19 +0200 Subject: [PATCH] compiler_rt: define a stub for the function multiversioning ABI To make sure that we can link code that uses FMV, even if for now we just conservatively use the slowest variant of a function. --- lib/compiler_rt.zig | 1 + lib/compiler_rt/aarch64_outline_atomics.zig | 2 +- lib/compiler_rt/fmv.zig | 137 ++++++++++++++++++++ tools/gen_outline_atomics.zig | 2 +- 4 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 lib/compiler_rt/fmv.zig diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig index b37807f8d5f05bb6eb07533965fc2cdd8a98db18..5ee5e7854c534c285ae7d6f2b73c0acbe2f68cf8 100644 --- a/lib/compiler_rt.zig +++ b/lib/compiler_rt.zig @@ -166,6 +166,7 @@ comptime { } _ = @import("compiler_rt/elf.zig"); + _ = @import("compiler_rt/fmv.zig"); // Temporarily used for uefi until https://github.com/ziglang/zig/issues/21630 is addressed. if (!builtin.link_libc and (builtin.os.tag == .windows or builtin.os.tag == .uefi) and (builtin.abi == .none or builtin.abi == .msvc)) { diff --git a/lib/compiler_rt/aarch64_outline_atomics.zig b/lib/compiler_rt/aarch64_outline_atomics.zig index c03306cd1a1cd07e0a450f66c67b985f41a1e0d3..c7ec9fd7aa20fc0c22a6a6df42a2382b31114291 100644 --- a/lib/compiler_rt/aarch64_outline_atomics.zig +++ b/lib/compiler_rt/aarch64_outline_atomics.zig @@ -9,7 +9,7 @@ const always_has_lse = builtin.cpu.has(.aarch64, .lse); /// It is intentionally not exported in order to make the machine code that /// uses it a statically predicted direct branch rather than using the PLT, /// which ARM is concerned would have too much overhead. -var __aarch64_have_lse_atomics: u8 = @intFromBool(always_has_lse); +pub var __aarch64_have_lse_atomics: u8 = @intFromBool(always_has_lse); fn __aarch64_cas1_relax() align(16) callconv(.naked) void { @setRuntimeSafety(false); diff --git a/lib/compiler_rt/fmv.zig b/lib/compiler_rt/fmv.zig new file mode 100644 index 0000000000000000000000000000000000000000..184fe7046a34b75d2c9079e8bb9da2e43b0c240d --- /dev/null +++ b/lib/compiler_rt/fmv.zig @@ -0,0 +1,137 @@ +const builtin = @import("builtin"); +const std = @import("std"); + +const compiler_rt = @import("../compiler_rt.zig"); +const symbol = compiler_rt.symbol; + +comptime { + // This is just a conservative stub for now, to make sure that code that + // uses function multiversioning will link correctly, albeit with the + // slowest variant of a function. + + if (builtin.target.cpu.arch.isAarch64()) _ = aarch64; + if (builtin.target.cpu.arch.isLoongarch()) _ = loongarch; + if (builtin.target.cpu.arch.isRiscv()) _ = riscv; + if (builtin.target.cpu.arch.isX86()) _ = x86; +} + +const aarch64 = struct { + comptime { + symbol(&__aarch64_cpu_features, "__aarch64_cpu_features"); + symbol(&@import("aarch64_outline_atomics.zig").__aarch64_have_lse_atomics, "__aarch64_have_lse_atomics"); + symbol(&__init_cpu_features_resolver, "__init_cpu_features_resolver"); + } + + var __aarch64_cpu_features: extern struct { + features: c_ulonglong, + } = .{ + .features = 0, + }; + + const __init_cpu_features_resolver = switch (builtin.target.os.tag) { + .fuchsia, + .driverkit, + .ios, + .maccatalyst, + .macos, + .tvos, + .visionos, + .watchos, + => struct { + fn __init_cpu_features_resolver() callconv(.c) void {} + }, + else => struct { + fn __init_cpu_features_resolver(hwcap: c_ulong, arg: *const extern struct { + _size: c_ulong, + _hwcap: c_ulong, + _hwcap2: c_ulong, + _hwcap3: c_ulong, + _hwcap4: c_ulong, + }) callconv(.c) void { + _ = hwcap; + _ = arg; + } + }, + }.__init_cpu_features_resolver; +}; + +const loongarch = struct { + comptime { + symbol(&__loongarch_feature_bits, "__loongarch_feature_bits"); + symbol(&__init_loongarch_features_resolver, "__init_loongarch_features_resolver"); + } + + var __loongarch_feature_bits: extern struct { + features: c_ulonglong, + } = .{ + .features = 0, + }; + + var __riscv_cpu_model: extern struct { + mvendorid: c_uint, + marchid: c_ulonglong, + mimpid: c_ulonglong, + } = .{ + .mvendorid = 0, + .marchid = 0, + .mimpid = 0, + }; + + fn __init_loongarch_features_resolver() callconv(.c) void {} +}; + +const riscv = struct { + comptime { + symbol(&__riscv_feature_bits, "__riscv_feature_bits"); + symbol(&__riscv_cpu_model, "__riscv_cpu_model"); + symbol(&__init_riscv_feature_bits, "__init_riscv_feature_bits"); + } + + var __riscv_feature_bits: extern struct { + length: c_uint, + features: [2]c_ulonglong, + } = .{ + .length = 2, + .features = @splat(0), + }; + + var __riscv_cpu_model: extern struct { + mvendorid: c_uint, + marchid: c_ulonglong, + mimpid: c_ulonglong, + } = .{ + .mvendorid = 0, + .marchid = 0, + .mimpid = 0, + }; + + fn __init_riscv_feature_bits(args: ?*anyopaque) callconv(.c) void { + _ = args; + } +}; + +const x86 = struct { + comptime { + symbol(&__cpu_model, "__cpu_model"); + symbol(&__cpu_features2, "__cpu_features2"); + symbol(&__cpu_indicator_init, "__cpu_indicator_init"); + } + + var __cpu_model: extern struct { + __cpu_vendor: c_uint, + __cpu_type: c_uint, + __cpu_subtype: c_uint, + __cpu_features: [1]c_uint, + } = .{ + .__cpu_vendor = 0, + .__cpu_type = 0, + .__cpu_subtype = 0, + .__cpu_features = @splat(0), + }; + + var __cpu_features2: [4]c_uint = @splat(0); + + fn __cpu_indicator_init() callconv(.c) c_int { + return 0; + } +}; diff --git a/tools/gen_outline_atomics.zig b/tools/gen_outline_atomics.zig index cbeff5ea76406a7756c1a25c342f9a0c31e412f3..ebbd77a927c3b98611aa1dedd5b72e169cd1dc02 100644 --- a/tools/gen_outline_atomics.zig +++ b/tools/gen_outline_atomics.zig @@ -32,7 +32,7 @@ pub fn main(init: std.process.Init) !void { \\/// It is intentionally not exported in order to make the machine code that \\/// uses it a statically predicted direct branch rather than using the PLT, \\/// which ARM is concerned would have too much overhead. - \\var __aarch64_have_lse_atomics: u8 = @intFromBool(always_has_lse); + \\pub var __aarch64_have_lse_atomics: u8 = @intFromBool(always_has_lse); \\ \\ ); -- 2.54.0