authorgravatar for gfischman@gmail.comGuy Fischman <gfischman@gmail.com> 2026-10-07 20:52:12+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-10-12 10:49:23+02:00
log070276d8f16667233e9d3a450a4e8d6db9183958
tree64ccaaaa5a547d9e47e25378bb44716650803f48
parentccdb1afa6ef81e1390623377a672efabaad45ba7

compiler: add x86_64, aarch64, riscv, and loongarch preserve_most calling convention support


11 files changed, 96 insertions(+), 1 deletions(-)

lib/std/Target.zig+6
......@@ -1850,6 +1850,7 @@ pub const Cpu = struct {
18501850 .x86_64_vectorcall,
18511851 .x86_64_interrupt,
18521852 .x86_64_preserve_none,
1853 .x86_64_preserve_most,
18531854 => &.{.x86_64},
18541855
18551856 .x86_sysv,
......@@ -1877,6 +1878,7 @@ pub const Cpu = struct {
18771878 .aarch64_vfabi,
18781879 .aarch64_vfabi_sve,
18791880 .aarch64_preserve_none,
1881 .aarch64_preserve_most,
18801882 => &.{ .aarch64, .aarch64_be },
18811883
18821884 .alpha_osf,
......@@ -1899,11 +1901,13 @@ pub const Cpu = struct {
18991901 .riscv64_lp64,
19001902 .riscv64_lp64_v,
19011903 .riscv64_interrupt,
1904 .riscv64_preserve_most,
19021905 => &.{ .riscv64, .riscv64be },
19031906
19041907 .riscv32_ilp32,
19051908 .riscv32_ilp32_v,
19061909 .riscv32_interrupt,
1910 .riscv32_preserve_most,
19071911 => &.{ .riscv32, .riscv32be },
19081912
19091913 .sparc64_sysv,
......@@ -1962,10 +1966,12 @@ pub const Cpu = struct {
19621966
19631967 .loongarch64_lp64,
19641968 .loongarch64_preserve_none,
1969 .loongarch64_preserve_most,
19651970 => &.{.loongarch64},
19661971
19671972 .loongarch32_ilp32,
19681973 .loongarch32_preserve_none,
1974 .loongarch32_preserve_most,
19691975 => &.{.loongarch32},
19701976
19711977 .m68k_sysv,
lib/std/lang.zig+6
......@@ -209,6 +209,7 @@ pub const CallingConvention = union(enum(u8)) {
209209 x86_64_vectorcall: CommonOptions,
210210 x86_64_interrupt: CommonOptions,
211211 x86_64_preserve_none: CommonOptions,
212 x86_64_preserve_most: CommonOptions,
212213
213214 // Calling conventions for the `x86` architecture.
214215 x86_sysv: X86RegparmOptions,
......@@ -237,6 +238,7 @@ pub const CallingConvention = union(enum(u8)) {
237238 aarch64_vfabi: CommonOptions,
238239 aarch64_vfabi_sve: CommonOptions,
239240 aarch64_preserve_none: CommonOptions,
241 aarch64_preserve_most: CommonOptions,
240242
241243 /// The standard `alpha` calling convention.
242244 alpha_osf: CommonOptions,
......@@ -261,11 +263,13 @@ pub const CallingConvention = union(enum(u8)) {
261263 riscv64_lp64: CommonOptions,
262264 riscv64_lp64_v: CommonOptions,
263265 riscv64_interrupt: RiscvInterruptOptions,
266 riscv64_preserve_most: CommonOptions,
264267
265268 // Calling conventions for the `riscv32` architecture.
266269 riscv32_ilp32: CommonOptions,
267270 riscv32_ilp32_v: CommonOptions,
268271 riscv32_interrupt: RiscvInterruptOptions,
272 riscv32_preserve_most: CommonOptions,
269273
270274 // Calling conventions for the `sparc64` architecture.
271275 sparc64_sysv: CommonOptions,
......@@ -323,10 +327,12 @@ pub const CallingConvention = union(enum(u8)) {
323327 /// The standard `loongarch64` calling convention.
324328 loongarch64_lp64: CommonOptions,
325329 loongarch64_preserve_none: CommonOptions,
330 loongarch64_preserve_most: CommonOptions,
326331
327332 /// The standard `loongarch32` calling convention.
328333 loongarch32_ilp32: CommonOptions,
329334 loongarch32_preserve_none: CommonOptions,
335 loongarch32_preserve_most: CommonOptions,
330336
331337 // Calling conventions for the `m68k` architecture.
332338 m68k_sysv: CommonOptions,
src/Zcu.zig+6
......@@ -4683,6 +4683,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)
46834683 .x86_64_regcall_v4_win,
46844684 .x86_64_interrupt,
46854685 .x86_64_preserve_none,
4686 .x86_64_preserve_most,
46864687 .x86_fastcall,
46874688 .x86_thiscall,
46884689 .x86_vectorcall,
......@@ -4692,6 +4693,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)
46924693 .aarch64_vfabi,
46934694 .aarch64_vfabi_sve,
46944695 .aarch64_preserve_none,
4696 .aarch64_preserve_most,
46954697 .arm_aapcs,
46964698 .csky_interrupt,
46974699 .riscv64_lp64_v,
......@@ -4713,6 +4715,10 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)
47134715 .ez80_tiflags,
47144716 .loongarch32_preserve_none,
47154717 .loongarch64_preserve_none,
4718 .riscv32_preserve_most,
4719 .riscv64_preserve_most,
4720 .loongarch32_preserve_most,
4721 .loongarch64_preserve_most,
47164722 .naked,
47174723 => true, // incoming stack alignment supported
47184724
src/codegen/c/type.zig+9
......@@ -63,6 +63,7 @@ pub const CType = union(enum) {
6363 regcall,
6464
6565 preserve_none,
66 preserve_most,
6667
6768 aarch64_vector_pcs,
6869 aarch64_sve_pcs,
......@@ -146,6 +147,14 @@ pub const CType = union(enum) {
146147 .loongarch64_preserve_none,
147148 => .preserve_none,
148149
150 .x86_64_preserve_most,
151 .aarch64_preserve_most,
152 .riscv32_preserve_most,
153 .riscv64_preserve_most,
154 .loongarch32_preserve_most,
155 .loongarch64_preserve_most,
156 => .preserve_most,
157
149158 .aarch64_vfabi => .aarch64_vector_pcs,
150159 .aarch64_vfabi_sve => .aarch64_sve_pcs,
151160
src/codegen/llvm.zig+6
......@@ -4304,6 +4304,7 @@ pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const
43044304 .x86_64_vectorcall => .x86_vectorcallcc,
43054305 .x86_64_interrupt => .x86_intrcc,
43064306 .x86_64_preserve_none => .preserve_nonecc,
4307 .x86_64_preserve_most => .preserve_mostcc,
43074308 .x86_stdcall => .x86_stdcallcc,
43084309 .x86_fastcall => .x86_fastcallcc,
43094310 .x86_thiscall => .x86_thiscallcc,
......@@ -4320,6 +4321,7 @@ pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const
43204321 .aarch64_vfabi => .aarch64_vector_pcs,
43214322 .aarch64_vfabi_sve => .aarch64_sve_vector_pcs,
43224323 .aarch64_preserve_none => .preserve_nonecc,
4324 .aarch64_preserve_most => .preserve_mostcc,
43234325 .arm_aapcs => .arm_aapcscc,
43244326 .arm_aapcs_vfp => .arm_aapcs_vfpcc,
43254327 .riscv64_lp64_v => .riscv_vectorcallcc,
......@@ -4336,6 +4338,10 @@ pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const
43364338 .nvptx_kernel => .ptx_kernel,
43374339 .loongarch32_preserve_none => .preserve_nonecc,
43384340 .loongarch64_preserve_none => .preserve_nonecc,
4341 .riscv32_preserve_most => .preserve_mostcc,
4342 .riscv64_preserve_most => .preserve_mostcc,
4343 .loongarch32_preserve_most => .preserve_mostcc,
4344 .loongarch64_preserve_most => .preserve_mostcc,
43394345
43404346 // Calling conventions which LLVM uses function attributes for.
43414347 .riscv64_interrupt,
src/link/Dwarf.zig+7
......@@ -4167,6 +4167,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
41674167 .x86_64_vectorcall => .LLVM_vectorcall,
41684168 .x86_sysv, .x86_win, .x86_mingw => .normal,
41694169 .x86_64_preserve_none => .LLVM_PreserveNone,
4170 .x86_64_preserve_most => .LLVM_PreserveMost,
41704171 .x86_stdcall => .BORLAND_stdcall,
41714172 .x86_fastcall => .BORLAND_msfastcall,
41724173 .x86_thiscall => .BORLAND_thiscall,
......@@ -4181,6 +4182,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
41814182 .aarch64_vfabi => .LLVM_AAPCS,
41824183 .aarch64_vfabi_sve => .LLVM_AAPCS,
41834184 .aarch64_preserve_none => .LLVM_PreserveNone,
4185 .aarch64_preserve_most => .LLVM_PreserveMost,
41844186
41854187 .arm_aapcs => .LLVM_AAPCS,
41864188 .arm_aapcs_vfp => .LLVM_AAPCS_VFP,
......@@ -4192,6 +4194,11 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
41924194 .loongarch32_preserve_none => .LLVM_PreserveNone,
41934195 .loongarch64_preserve_none => .LLVM_PreserveNone,
41944196
4197 .riscv32_preserve_most => .LLVM_PreserveMost,
4198 .riscv64_preserve_most => .LLVM_PreserveMost,
4199 .loongarch32_preserve_most => .LLVM_PreserveMost,
4200 .loongarch64_preserve_most => .LLVM_PreserveMost,
4201
41954202 .m68k_rtd => .LLVM_M68kRTD,
41964203
41974204 .sh_renesas => .GNU_renesas_sh,
src/link/Dwarf2.zig+2
......@@ -3276,6 +3276,7 @@ fn updateConstInner(
32763276 .x86_64_vectorcall => .LLVM_vectorcall,
32773277 .x86_sysv, .x86_win, .x86_mingw => .normal,
32783278 .x86_64_preserve_none => .LLVM_PreserveNone,
3279 .x86_64_preserve_most => .LLVM_PreserveMost,
32793280 .x86_stdcall => .BORLAND_stdcall,
32803281 .x86_fastcall => .BORLAND_msfastcall,
32813282 .x86_thiscall => .BORLAND_thiscall,
......@@ -3290,6 +3291,7 @@ fn updateConstInner(
32903291 .aarch64_vfabi => .LLVM_AAPCS,
32913292 .aarch64_vfabi_sve => .LLVM_AAPCS,
32923293 .aarch64_preserve_none => .LLVM_PreserveNone,
3294 .aarch64_preserve_most => .LLVM_PreserveMost,
32933295
32943296 .arm_aapcs => .LLVM_AAPCS,
32953297 .arm_aapcs_vfp => .LLVM_AAPCS_VFP,
test/c_abi/cfuncs.c+10
......@@ -16700,6 +16700,16 @@ void c_preserve_none_check(void) {
1670016700}
1670116701#endif
1670216702
16703#if defined __x86_64__ || defined __aarch64__ || defined __riscv || defined __loongarch__
16704int __attribute__((preserve_most)) c_preserve_most(int x) {
16705 return x + 1;
16706}
16707int __attribute__((preserve_most)) zig_preserve_most(int);
16708void c_preserve_most_check(void) {
16709 assert_or_panic(zig_preserve_most(41) == 42);
16710}
16711#endif
16712
1670316713struct byval_tail_callsite_attr_Point {
1670416714 double x;
1670516715 double y;
test/c_abi/main.zig+27
......@@ -18162,3 +18162,30 @@ test "preserve_none calling convention" {
1816218162 try expect(static.c_preserve_none(41) == 42);
1816318163 static.c_preserve_none_check();
1816418164}
18165
18166const preserve_most_cc: ?std.lang.CallingConvention = if (builtin.zig_backend != .stage2_llvm)
18167 null
18168else switch (builtin.cpu.arch) {
18169 .x86_64 => .{ .x86_64_preserve_most = .{} },
18170 .aarch64, .aarch64_be => .{ .aarch64_preserve_most = .{} },
18171 // Supported in LLVM but not yet wired up in Clang.
18172 // .riscv32, .riscv32be => .{ .riscv32_preserve_most = .{} },
18173 // .riscv64, .riscv64be => .{ .riscv64_preserve_most = .{} },
18174 // .loongarch32 => .{ .loongarch32_preserve_most = .{} },
18175 // .loongarch64 => .{ .loongarch64_preserve_most = .{} },
18176 else => null,
18177};
18178
18179export fn zig_preserve_most(x: i32) callconv(preserve_most_cc orelse .c) i32 {
18180 return x + 1;
18181}
18182
18183test "preserve_most calling convention" {
18184 if (preserve_most_cc == null) return error.SkipZigTest;
18185 const static = struct {
18186 extern fn c_preserve_most(x: i32) callconv(preserve_most_cc.?) i32;
18187 extern fn c_preserve_most_check() void;
18188 };
18189 try expect(static.c_preserve_most(41) == 42);
18190 static.c_preserve_most_check();
18191}
test/cases/compile_errors/callconv_preserve_most_on_unsupported_platform.zig created+16
......@@ -0,0 +1,16 @@
1const F1 = fn () callconv(.{ .x86_64_preserve_most = .{} }) void;
2const F2 = fn () callconv(.{ .aarch64_preserve_most = .{} }) void;
3export fn entry1() void {
4 const a: F1 = undefined;
5 _ = a;
6}
7export fn entry2() void {
8 const a: F2 = undefined;
9 _ = a;
10}
11
12// error
13// target=wasm32-freestanding
14//
15// :1:28: error: calling convention 'x86_64_preserve_most' only available on architectures 'x86_64'
16// :2:28: error: calling convention 'aarch64_preserve_most' only available on architectures 'aarch64', 'aarch64_be'
test/cases/compile_errors/callconv_preserve_none_on_unsupported_platform.zig+1-1
......@@ -10,7 +10,7 @@ export fn entry2() void {
1010}
1111
1212// error
13// target=riscv64-linux-none
13// target=wasm32-freestanding
1414//
1515// :1:28: error: calling convention 'x86_64_preserve_none' only available on architectures 'x86_64'
1616// :2:28: error: calling convention 'aarch64_preserve_none' only available on architectures 'aarch64', 'aarch64_be'