authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-10-20 08:50:19+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-10-20 10:05:11+02:00
log694c848c3e48176fb81941f0186d53100211e64c
treeb0b72040fc67003d1331948edc9f9546766385f7
parentde6afdc52428632c9a13b5ef14d4ba6719a2d55b
signature Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

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.

4 files changed, 141 insertions(+), 2 deletions(-)

lib/compiler_rt.zig+2
...@@ -164,6 +164,8 @@ comptime {...@@ -164,6 +164,8 @@ comptime {
164 symbol(&strlen, "strlen");164 symbol(&strlen, "strlen");
165 }165 }
166166
167 _ = @import("compiler_rt/fmv.zig");
168
167 // Temporarily used for uefi until https://github.com/ziglang/zig/issues/21630 is addressed.169 // Temporarily used for uefi until https://github.com/ziglang/zig/issues/21630 is addressed.
168 if (!builtin.link_libc and (builtin.os.tag == .windows or builtin.os.tag == .uefi) and (builtin.abi == .none or builtin.abi == .msvc)) {170 if (!builtin.link_libc and (builtin.os.tag == .windows or builtin.os.tag == .uefi) and (builtin.abi == .none or builtin.abi == .msvc)) {
169 symbol(&_fltused, "_fltused");171 symbol(&_fltused, "_fltused");
lib/compiler_rt/aarch64_outline_atomics.zig+1-1
...@@ -9,7 +9,7 @@ const always_has_lse = builtin.cpu.has(.aarch64, .lse);...@@ -9,7 +9,7 @@ const always_has_lse = builtin.cpu.has(.aarch64, .lse);
9/// It is intentionally not exported in order to make the machine code that9/// It is intentionally not exported in order to make the machine code that
10/// uses it a statically predicted direct branch rather than using the PLT,10/// uses it a statically predicted direct branch rather than using the PLT,
11/// which ARM is concerned would have too much overhead.11/// which ARM is concerned would have too much overhead.
12var __aarch64_have_lse_atomics: u8 = @intFromBool(always_has_lse);12pub var __aarch64_have_lse_atomics: u8 = @intFromBool(always_has_lse);
1313
14fn __aarch64_cas1_relax() align(16) callconv(.naked) void {14fn __aarch64_cas1_relax() align(16) callconv(.naked) void {
15 @setRuntimeSafety(false);15 @setRuntimeSafety(false);
lib/compiler_rt/fmv.zig created+137
...@@ -0,0 +1,137 @@
1const builtin = @import("builtin");
2const std = @import("std");
3
4const compiler_rt = @import("../compiler_rt.zig");
5const symbol = compiler_rt.symbol;
6
7comptime {
8 // This is just a conservative stub for now, to make sure that code that
9 // uses function multiversioning will link correctly, albeit with the
10 // slowest variant of a function.
11
12 if (builtin.target.cpu.arch.isAarch64()) _ = aarch64;
13 if (builtin.target.cpu.arch.isLoongarch()) _ = loongarch;
14 if (builtin.target.cpu.arch.isRiscv()) _ = riscv;
15 if (builtin.target.cpu.arch.isX86()) _ = x86;
16}
17
18const aarch64 = struct {
19 comptime {
20 symbol(&__aarch64_cpu_features, "__aarch64_cpu_features");
21 symbol(&@import("aarch64_outline_atomics.zig").__aarch64_have_lse_atomics, "__aarch64_have_lse_atomics");
22 symbol(&__init_cpu_features_resolver, "__init_cpu_features_resolver");
23 }
24
25 var __aarch64_cpu_features: extern struct {
26 features: c_ulonglong,
27 } = .{
28 .features = 0,
29 };
30
31 const __init_cpu_features_resolver = switch (builtin.target.os.tag) {
32 .fuchsia,
33 .driverkit,
34 .ios,
35 .maccatalyst,
36 .macos,
37 .tvos,
38 .visionos,
39 .watchos,
40 => struct {
41 fn __init_cpu_features_resolver() callconv(.c) void {}
42 },
43 else => struct {
44 fn __init_cpu_features_resolver(hwcap: c_ulong, arg: *const extern struct {
45 _size: c_ulong,
46 _hwcap: c_ulong,
47 _hwcap2: c_ulong,
48 _hwcap3: c_ulong,
49 _hwcap4: c_ulong,
50 }) callconv(.c) void {
51 _ = hwcap;
52 _ = arg;
53 }
54 },
55 }.__init_cpu_features_resolver;
56};
57
58const loongarch = struct {
59 comptime {
60 symbol(&__loongarch_feature_bits, "__loongarch_feature_bits");
61 symbol(&__init_loongarch_features_resolver, "__init_loongarch_features_resolver");
62 }
63
64 var __loongarch_feature_bits: extern struct {
65 features: c_ulonglong,
66 } = .{
67 .features = 0,
68 };
69
70 var __riscv_cpu_model: extern struct {
71 mvendorid: c_uint,
72 marchid: c_ulonglong,
73 mimpid: c_ulonglong,
74 } = .{
75 .mvendorid = 0,
76 .marchid = 0,
77 .mimpid = 0,
78 };
79
80 fn __init_loongarch_features_resolver() callconv(.c) void {}
81};
82
83const riscv = struct {
84 comptime {
85 symbol(&__riscv_feature_bits, "__riscv_feature_bits");
86 symbol(&__riscv_cpu_model, "__riscv_cpu_model");
87 symbol(&__init_riscv_feature_bits, "__init_riscv_feature_bits");
88 }
89
90 var __riscv_feature_bits: extern struct {
91 length: c_uint,
92 features: [2]c_ulonglong,
93 } = .{
94 .length = 2,
95 .features = @splat(0),
96 };
97
98 var __riscv_cpu_model: extern struct {
99 mvendorid: c_uint,
100 marchid: c_ulonglong,
101 mimpid: c_ulonglong,
102 } = .{
103 .mvendorid = 0,
104 .marchid = 0,
105 .mimpid = 0,
106 };
107
108 fn __init_riscv_feature_bits(args: ?*anyopaque) callconv(.c) void {
109 _ = args;
110 }
111};
112
113const x86 = struct {
114 comptime {
115 symbol(&__cpu_model, "__cpu_model");
116 symbol(&__cpu_features2, "__cpu_features2");
117 symbol(&__cpu_indicator_init, "__cpu_indicator_init");
118 }
119
120 var __cpu_model: extern struct {
121 __cpu_vendor: c_uint,
122 __cpu_type: c_uint,
123 __cpu_subtype: c_uint,
124 __cpu_features: [1]c_uint,
125 } = .{
126 .__cpu_vendor = 0,
127 .__cpu_type = 0,
128 .__cpu_subtype = 0,
129 .__cpu_features = @splat(0),
130 };
131
132 var __cpu_features2: [4]c_uint = @splat(0);
133
134 fn __cpu_indicator_init() callconv(.c) c_int {
135 return 0;
136 }
137};
tools/gen_outline_atomics.zig+1-1
...@@ -32,7 +32,7 @@ pub fn main(init: std.process.Init) !void {...@@ -32,7 +32,7 @@ pub fn main(init: std.process.Init) !void {
32 \\/// It is intentionally not exported in order to make the machine code that32 \\/// It is intentionally not exported in order to make the machine code that
33 \\/// uses it a statically predicted direct branch rather than using the PLT,33 \\/// uses it a statically predicted direct branch rather than using the PLT,
34 \\/// which ARM is concerned would have too much overhead.34 \\/// which ARM is concerned would have too much overhead.
35 \\var __aarch64_have_lse_atomics: u8 = @intFromBool(always_has_lse);35 \\pub var __aarch64_have_lse_atomics: u8 = @intFromBool(always_has_lse);
36 \\36 \\
37 \\37 \\
38 );38 );