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 {...@@ -1850,6 +1850,7 @@ pub const Cpu = struct {
1850 .x86_64_vectorcall,1850 .x86_64_vectorcall,
1851 .x86_64_interrupt,1851 .x86_64_interrupt,
1852 .x86_64_preserve_none,1852 .x86_64_preserve_none,
1853 .x86_64_preserve_most,
1853 => &.{.x86_64},1854 => &.{.x86_64},
18541855
1855 .x86_sysv,1856 .x86_sysv,
...@@ -1877,6 +1878,7 @@ pub const Cpu = struct {...@@ -1877,6 +1878,7 @@ pub const Cpu = struct {
1877 .aarch64_vfabi,1878 .aarch64_vfabi,
1878 .aarch64_vfabi_sve,1879 .aarch64_vfabi_sve,
1879 .aarch64_preserve_none,1880 .aarch64_preserve_none,
1881 .aarch64_preserve_most,
1880 => &.{ .aarch64, .aarch64_be },1882 => &.{ .aarch64, .aarch64_be },
18811883
1882 .alpha_osf,1884 .alpha_osf,
...@@ -1899,11 +1901,13 @@ pub const Cpu = struct {...@@ -1899,11 +1901,13 @@ pub const Cpu = struct {
1899 .riscv64_lp64,1901 .riscv64_lp64,
1900 .riscv64_lp64_v,1902 .riscv64_lp64_v,
1901 .riscv64_interrupt,1903 .riscv64_interrupt,
1904 .riscv64_preserve_most,
1902 => &.{ .riscv64, .riscv64be },1905 => &.{ .riscv64, .riscv64be },
19031906
1904 .riscv32_ilp32,1907 .riscv32_ilp32,
1905 .riscv32_ilp32_v,1908 .riscv32_ilp32_v,
1906 .riscv32_interrupt,1909 .riscv32_interrupt,
1910 .riscv32_preserve_most,
1907 => &.{ .riscv32, .riscv32be },1911 => &.{ .riscv32, .riscv32be },
19081912
1909 .sparc64_sysv,1913 .sparc64_sysv,
...@@ -1962,10 +1966,12 @@ pub const Cpu = struct {...@@ -1962,10 +1966,12 @@ pub const Cpu = struct {
19621966
1963 .loongarch64_lp64,1967 .loongarch64_lp64,
1964 .loongarch64_preserve_none,1968 .loongarch64_preserve_none,
1969 .loongarch64_preserve_most,
1965 => &.{.loongarch64},1970 => &.{.loongarch64},
19661971
1967 .loongarch32_ilp32,1972 .loongarch32_ilp32,
1968 .loongarch32_preserve_none,1973 .loongarch32_preserve_none,
1974 .loongarch32_preserve_most,
1969 => &.{.loongarch32},1975 => &.{.loongarch32},
19701976
1971 .m68k_sysv,1977 .m68k_sysv,
lib/std/lang.zig+6
...@@ -209,6 +209,7 @@ pub const CallingConvention = union(enum(u8)) {...@@ -209,6 +209,7 @@ pub const CallingConvention = union(enum(u8)) {
209 x86_64_vectorcall: CommonOptions,209 x86_64_vectorcall: CommonOptions,
210 x86_64_interrupt: CommonOptions,210 x86_64_interrupt: CommonOptions,
211 x86_64_preserve_none: CommonOptions,211 x86_64_preserve_none: CommonOptions,
212 x86_64_preserve_most: CommonOptions,
212213
213 // Calling conventions for the `x86` architecture.214 // Calling conventions for the `x86` architecture.
214 x86_sysv: X86RegparmOptions,215 x86_sysv: X86RegparmOptions,
...@@ -237,6 +238,7 @@ pub const CallingConvention = union(enum(u8)) {...@@ -237,6 +238,7 @@ pub const CallingConvention = union(enum(u8)) {
237 aarch64_vfabi: CommonOptions,238 aarch64_vfabi: CommonOptions,
238 aarch64_vfabi_sve: CommonOptions,239 aarch64_vfabi_sve: CommonOptions,
239 aarch64_preserve_none: CommonOptions,240 aarch64_preserve_none: CommonOptions,
241 aarch64_preserve_most: CommonOptions,
240242
241 /// The standard `alpha` calling convention.243 /// The standard `alpha` calling convention.
242 alpha_osf: CommonOptions,244 alpha_osf: CommonOptions,
...@@ -261,11 +263,13 @@ pub const CallingConvention = union(enum(u8)) {...@@ -261,11 +263,13 @@ pub const CallingConvention = union(enum(u8)) {
261 riscv64_lp64: CommonOptions,263 riscv64_lp64: CommonOptions,
262 riscv64_lp64_v: CommonOptions,264 riscv64_lp64_v: CommonOptions,
263 riscv64_interrupt: RiscvInterruptOptions,265 riscv64_interrupt: RiscvInterruptOptions,
266 riscv64_preserve_most: CommonOptions,
264267
265 // Calling conventions for the `riscv32` architecture.268 // Calling conventions for the `riscv32` architecture.
266 riscv32_ilp32: CommonOptions,269 riscv32_ilp32: CommonOptions,
267 riscv32_ilp32_v: CommonOptions,270 riscv32_ilp32_v: CommonOptions,
268 riscv32_interrupt: RiscvInterruptOptions,271 riscv32_interrupt: RiscvInterruptOptions,
272 riscv32_preserve_most: CommonOptions,
269273
270 // Calling conventions for the `sparc64` architecture.274 // Calling conventions for the `sparc64` architecture.
271 sparc64_sysv: CommonOptions,275 sparc64_sysv: CommonOptions,
...@@ -323,10 +327,12 @@ pub const CallingConvention = union(enum(u8)) {...@@ -323,10 +327,12 @@ pub const CallingConvention = union(enum(u8)) {
323 /// The standard `loongarch64` calling convention.327 /// The standard `loongarch64` calling convention.
324 loongarch64_lp64: CommonOptions,328 loongarch64_lp64: CommonOptions,
325 loongarch64_preserve_none: CommonOptions,329 loongarch64_preserve_none: CommonOptions,
330 loongarch64_preserve_most: CommonOptions,
326331
327 /// The standard `loongarch32` calling convention.332 /// The standard `loongarch32` calling convention.
328 loongarch32_ilp32: CommonOptions,333 loongarch32_ilp32: CommonOptions,
329 loongarch32_preserve_none: CommonOptions,334 loongarch32_preserve_none: CommonOptions,
335 loongarch32_preserve_most: CommonOptions,
330336
331 // Calling conventions for the `m68k` architecture.337 // Calling conventions for the `m68k` architecture.
332 m68k_sysv: CommonOptions,338 m68k_sysv: CommonOptions,
src/Zcu.zig+6
...@@ -4683,6 +4683,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)...@@ -4683,6 +4683,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)
4683 .x86_64_regcall_v4_win,4683 .x86_64_regcall_v4_win,
4684 .x86_64_interrupt,4684 .x86_64_interrupt,
4685 .x86_64_preserve_none,4685 .x86_64_preserve_none,
4686 .x86_64_preserve_most,
4686 .x86_fastcall,4687 .x86_fastcall,
4687 .x86_thiscall,4688 .x86_thiscall,
4688 .x86_vectorcall,4689 .x86_vectorcall,
...@@ -4692,6 +4693,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)...@@ -4692,6 +4693,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)
4692 .aarch64_vfabi,4693 .aarch64_vfabi,
4693 .aarch64_vfabi_sve,4694 .aarch64_vfabi_sve,
4694 .aarch64_preserve_none,4695 .aarch64_preserve_none,
4696 .aarch64_preserve_most,
4695 .arm_aapcs,4697 .arm_aapcs,
4696 .csky_interrupt,4698 .csky_interrupt,
4697 .riscv64_lp64_v,4699 .riscv64_lp64_v,
...@@ -4713,6 +4715,10 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)...@@ -4713,6 +4715,10 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)
4713 .ez80_tiflags,4715 .ez80_tiflags,
4714 .loongarch32_preserve_none,4716 .loongarch32_preserve_none,
4715 .loongarch64_preserve_none,4717 .loongarch64_preserve_none,
4718 .riscv32_preserve_most,
4719 .riscv64_preserve_most,
4720 .loongarch32_preserve_most,
4721 .loongarch64_preserve_most,
4716 .naked,4722 .naked,
4717 => true, // incoming stack alignment supported4723 => true, // incoming stack alignment supported
47184724
src/codegen/c/type.zig+9
...@@ -63,6 +63,7 @@ pub const CType = union(enum) {...@@ -63,6 +63,7 @@ pub const CType = union(enum) {
63 regcall,63 regcall,
6464
65 preserve_none,65 preserve_none,
66 preserve_most,
6667
67 aarch64_vector_pcs,68 aarch64_vector_pcs,
68 aarch64_sve_pcs,69 aarch64_sve_pcs,
...@@ -146,6 +147,14 @@ pub const CType = union(enum) {...@@ -146,6 +147,14 @@ pub const CType = union(enum) {
146 .loongarch64_preserve_none,147 .loongarch64_preserve_none,
147 => .preserve_none,148 => .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
149 .aarch64_vfabi => .aarch64_vector_pcs,158 .aarch64_vfabi => .aarch64_vector_pcs,
150 .aarch64_vfabi_sve => .aarch64_sve_pcs,159 .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...@@ -4304,6 +4304,7 @@ pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const
4304 .x86_64_vectorcall => .x86_vectorcallcc,4304 .x86_64_vectorcall => .x86_vectorcallcc,
4305 .x86_64_interrupt => .x86_intrcc,4305 .x86_64_interrupt => .x86_intrcc,
4306 .x86_64_preserve_none => .preserve_nonecc,4306 .x86_64_preserve_none => .preserve_nonecc,
4307 .x86_64_preserve_most => .preserve_mostcc,
4307 .x86_stdcall => .x86_stdcallcc,4308 .x86_stdcall => .x86_stdcallcc,
4308 .x86_fastcall => .x86_fastcallcc,4309 .x86_fastcall => .x86_fastcallcc,
4309 .x86_thiscall => .x86_thiscallcc,4310 .x86_thiscall => .x86_thiscallcc,
...@@ -4320,6 +4321,7 @@ pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const...@@ -4320,6 +4321,7 @@ pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const
4320 .aarch64_vfabi => .aarch64_vector_pcs,4321 .aarch64_vfabi => .aarch64_vector_pcs,
4321 .aarch64_vfabi_sve => .aarch64_sve_vector_pcs,4322 .aarch64_vfabi_sve => .aarch64_sve_vector_pcs,
4322 .aarch64_preserve_none => .preserve_nonecc,4323 .aarch64_preserve_none => .preserve_nonecc,
4324 .aarch64_preserve_most => .preserve_mostcc,
4323 .arm_aapcs => .arm_aapcscc,4325 .arm_aapcs => .arm_aapcscc,
4324 .arm_aapcs_vfp => .arm_aapcs_vfpcc,4326 .arm_aapcs_vfp => .arm_aapcs_vfpcc,
4325 .riscv64_lp64_v => .riscv_vectorcallcc,4327 .riscv64_lp64_v => .riscv_vectorcallcc,
...@@ -4336,6 +4338,10 @@ pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const...@@ -4336,6 +4338,10 @@ pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const
4336 .nvptx_kernel => .ptx_kernel,4338 .nvptx_kernel => .ptx_kernel,
4337 .loongarch32_preserve_none => .preserve_nonecc,4339 .loongarch32_preserve_none => .preserve_nonecc,
4338 .loongarch64_preserve_none => .preserve_nonecc,4340 .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
4340 // Calling conventions which LLVM uses function attributes for.4346 // Calling conventions which LLVM uses function attributes for.
4341 .riscv64_interrupt,4347 .riscv64_interrupt,
src/link/Dwarf.zig+7
...@@ -4167,6 +4167,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co...@@ -4167,6 +4167,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
4167 .x86_64_vectorcall => .LLVM_vectorcall,4167 .x86_64_vectorcall => .LLVM_vectorcall,
4168 .x86_sysv, .x86_win, .x86_mingw => .normal,4168 .x86_sysv, .x86_win, .x86_mingw => .normal,
4169 .x86_64_preserve_none => .LLVM_PreserveNone,4169 .x86_64_preserve_none => .LLVM_PreserveNone,
4170 .x86_64_preserve_most => .LLVM_PreserveMost,
4170 .x86_stdcall => .BORLAND_stdcall,4171 .x86_stdcall => .BORLAND_stdcall,
4171 .x86_fastcall => .BORLAND_msfastcall,4172 .x86_fastcall => .BORLAND_msfastcall,
4172 .x86_thiscall => .BORLAND_thiscall,4173 .x86_thiscall => .BORLAND_thiscall,
...@@ -4181,6 +4182,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co...@@ -4181,6 +4182,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
4181 .aarch64_vfabi => .LLVM_AAPCS,4182 .aarch64_vfabi => .LLVM_AAPCS,
4182 .aarch64_vfabi_sve => .LLVM_AAPCS,4183 .aarch64_vfabi_sve => .LLVM_AAPCS,
4183 .aarch64_preserve_none => .LLVM_PreserveNone,4184 .aarch64_preserve_none => .LLVM_PreserveNone,
4185 .aarch64_preserve_most => .LLVM_PreserveMost,
41844186
4185 .arm_aapcs => .LLVM_AAPCS,4187 .arm_aapcs => .LLVM_AAPCS,
4186 .arm_aapcs_vfp => .LLVM_AAPCS_VFP,4188 .arm_aapcs_vfp => .LLVM_AAPCS_VFP,
...@@ -4192,6 +4194,11 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co...@@ -4192,6 +4194,11 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
4192 .loongarch32_preserve_none => .LLVM_PreserveNone,4194 .loongarch32_preserve_none => .LLVM_PreserveNone,
4193 .loongarch64_preserve_none => .LLVM_PreserveNone,4195 .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
4195 .m68k_rtd => .LLVM_M68kRTD,4202 .m68k_rtd => .LLVM_M68kRTD,
41964203
4197 .sh_renesas => .GNU_renesas_sh,4204 .sh_renesas => .GNU_renesas_sh,
src/link/Dwarf2.zig+2
...@@ -3276,6 +3276,7 @@ fn updateConstInner(...@@ -3276,6 +3276,7 @@ fn updateConstInner(
3276 .x86_64_vectorcall => .LLVM_vectorcall,3276 .x86_64_vectorcall => .LLVM_vectorcall,
3277 .x86_sysv, .x86_win, .x86_mingw => .normal,3277 .x86_sysv, .x86_win, .x86_mingw => .normal,
3278 .x86_64_preserve_none => .LLVM_PreserveNone,3278 .x86_64_preserve_none => .LLVM_PreserveNone,
3279 .x86_64_preserve_most => .LLVM_PreserveMost,
3279 .x86_stdcall => .BORLAND_stdcall,3280 .x86_stdcall => .BORLAND_stdcall,
3280 .x86_fastcall => .BORLAND_msfastcall,3281 .x86_fastcall => .BORLAND_msfastcall,
3281 .x86_thiscall => .BORLAND_thiscall,3282 .x86_thiscall => .BORLAND_thiscall,
...@@ -3290,6 +3291,7 @@ fn updateConstInner(...@@ -3290,6 +3291,7 @@ fn updateConstInner(
3290 .aarch64_vfabi => .LLVM_AAPCS,3291 .aarch64_vfabi => .LLVM_AAPCS,
3291 .aarch64_vfabi_sve => .LLVM_AAPCS,3292 .aarch64_vfabi_sve => .LLVM_AAPCS,
3292 .aarch64_preserve_none => .LLVM_PreserveNone,3293 .aarch64_preserve_none => .LLVM_PreserveNone,
3294 .aarch64_preserve_most => .LLVM_PreserveMost,
32933295
3294 .arm_aapcs => .LLVM_AAPCS,3296 .arm_aapcs => .LLVM_AAPCS,
3295 .arm_aapcs_vfp => .LLVM_AAPCS_VFP,3297 .arm_aapcs_vfp => .LLVM_AAPCS_VFP,
test/c_abi/cfuncs.c+10
...@@ -16700,6 +16700,16 @@ void c_preserve_none_check(void) {...@@ -16700,6 +16700,16 @@ void c_preserve_none_check(void) {
16700}16700}
16701#endif16701#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
16703struct byval_tail_callsite_attr_Point {16713struct byval_tail_callsite_attr_Point {
16704 double x;16714 double x;
16705 double y;16715 double y;
test/c_abi/main.zig+27
...@@ -18162,3 +18162,30 @@ test "preserve_none calling convention" {...@@ -18162,3 +18162,30 @@ test "preserve_none calling convention" {
18162 try expect(static.c_preserve_none(41) == 42);18162 try expect(static.c_preserve_none(41) == 42);
18163 static.c_preserve_none_check();18163 static.c_preserve_none_check();
18164}18164}
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 {...@@ -10,7 +10,7 @@ export fn entry2() void {
10}10}
1111
12// error12// error
13// target=riscv64-linux-none13// target=wasm32-freestanding
14//14//
15// :1:28: error: calling convention 'x86_64_preserve_none' only available on architectures 'x86_64'15// :1:28: error: calling convention 'x86_64_preserve_none' only available on architectures 'x86_64'
16// :2:28: error: calling convention 'aarch64_preserve_none' only available on architectures 'aarch64', 'aarch64_be'16// :2:28: error: calling convention 'aarch64_preserve_none' only available on architectures 'aarch64', 'aarch64_be'