authorgravatar for omerfirmak@gmail.comÖmer Faruk IRMAK <omerfirmak@gmail.com> 2026-07-26 11:16:51+03:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-07-29 03:13:48+02:00
logbb296ab9b9752893eb362ed951c4ce344214eb96
treedbf68b07b7bd48f7822d79ceb86def073e111e9f
parentbdb1e9c9cf97520e41c8aff94553d5140a79dac7

Add and lower preserve_none call convention for x86_64 & aarch64

std declarations, llvm lowering, c_abi test, compiler warning test Co-authored-by: yarn <aethnem@gmail.com>

10 files changed, 66 insertions(+), 0 deletions(-)

lib/std/Target.zig+2
......@@ -1793,6 +1793,7 @@ pub const Cpu = struct {
17931793 .x86_64_regcall_v4_win,
17941794 .x86_64_vectorcall,
17951795 .x86_64_interrupt,
1796 .x86_64_preserve_none,
17961797 => &.{.x86_64},
17971798
17981799 .x86_sysv,
......@@ -1819,6 +1820,7 @@ pub const Cpu = struct {
18191820 .aarch64_aapcs_win,
18201821 .aarch64_vfabi,
18211822 .aarch64_vfabi_sve,
1823 .aarch64_preserve_none,
18221824 => &.{ .aarch64, .aarch64_be },
18231825
18241826 .alpha_osf,
lib/std/lang.zig+2
......@@ -210,6 +210,7 @@ pub const CallingConvention = union(enum(u8)) {
210210 x86_64_regcall_v4_win: CommonOptions,
211211 x86_64_vectorcall: CommonOptions,
212212 x86_64_interrupt: CommonOptions,
213 x86_64_preserve_none: CommonOptions,
213214
214215 // Calling conventions for the `x86` architecture.
215216 x86_sysv: X86RegparmOptions,
......@@ -237,6 +238,7 @@ pub const CallingConvention = union(enum(u8)) {
237238 aarch64_aapcs_win: CommonOptions,
238239 aarch64_vfabi: CommonOptions,
239240 aarch64_vfabi_sve: CommonOptions,
241 aarch64_preserve_none: CommonOptions,
240242
241243 /// The standard `alpha` calling convention.
242244 alpha_osf: CommonOptions,
lib/std/zig/llvm/Builder.zig+2
......@@ -2749,6 +2749,7 @@ pub const CallConv = enum(u10) {
27492749 tailcc,
27502750 cfguard_checkcc,
27512751 swifttailcc,
2752 preserve_nonecc,
27522753
27532754 x86_stdcallcc = 64,
27542755 x86_fastcallcc,
......@@ -2817,6 +2818,7 @@ pub const CallConv = enum(u10) {
28172818 .tailcc,
28182819 .cfguard_checkcc,
28192820 .swifttailcc,
2821 .preserve_nonecc,
28202822 .x86_stdcallcc,
28212823 .x86_fastcallcc,
28222824 .arm_apcscc,
src/Zcu.zig+2
......@@ -4602,6 +4602,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)
46024602 .x86_64_regcall_v3_sysv,
46034603 .x86_64_regcall_v4_win,
46044604 .x86_64_interrupt,
4605 .x86_64_preserve_none,
46054606 .x86_fastcall,
46064607 .x86_thiscall,
46074608 .x86_vectorcall,
......@@ -4610,6 +4611,7 @@ pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum)
46104611 .x86_interrupt,
46114612 .aarch64_vfabi,
46124613 .aarch64_vfabi_sve,
4614 .aarch64_preserve_none,
46134615 .arm_aapcs,
46144616 .csky_interrupt,
46154617 .riscv64_lp64_v,
src/codegen/c/type.zig+6
......@@ -62,6 +62,8 @@ pub const CType = union(enum) {
6262
6363 regcall,
6464
65 preserve_none,
66
6567 aarch64_vector_pcs,
6668 aarch64_sve_pcs,
6769
......@@ -138,6 +140,10 @@ pub const CType = union(enum) {
138140 .x86_regcall_v4_win,
139141 => .regcall,
140142
143 .x86_64_preserve_none,
144 .aarch64_preserve_none,
145 => .preserve_none,
146
141147 .aarch64_vfabi => .aarch64_vector_pcs,
142148 .aarch64_vfabi_sve => .aarch64_sve_pcs,
143149
src/codegen/llvm.zig+2
......@@ -4558,6 +4558,7 @@ pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const
45584558 null,
45594559 .x86_64_vectorcall => .x86_vectorcallcc,
45604560 .x86_64_interrupt => .x86_intrcc,
4561 .x86_64_preserve_none => .preserve_nonecc,
45614562 .x86_stdcall => .x86_stdcallcc,
45624563 .x86_fastcall => .x86_fastcallcc,
45634564 .x86_thiscall => .x86_thiscallcc,
......@@ -4573,6 +4574,7 @@ pub fn toLlvmCallConvTag(cc_tag: std.lang.CallingConvention.Tag, target: *const
45734574 .x86_interrupt => .x86_intrcc,
45744575 .aarch64_vfabi => .aarch64_vector_pcs,
45754576 .aarch64_vfabi_sve => .aarch64_sve_vector_pcs,
4577 .aarch64_preserve_none => .preserve_nonecc,
45764578 .arm_aapcs => .arm_aapcscc,
45774579 .arm_aapcs_vfp => .arm_aapcs_vfpcc,
45784580 .riscv64_lp64_v => .riscv_vectorcallcc,
src/link/Dwarf.zig+2
......@@ -4152,6 +4152,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
41524152 .x86_64_regcall_v4_win => .LLVM_X86RegCall,
41534153 .x86_64_vectorcall => .LLVM_vectorcall,
41544154 .x86_sysv, .x86_win, .x86_mingw => .normal,
4155 .x86_64_preserve_none => .LLVM_PreserveNone,
41554156 .x86_stdcall => .BORLAND_stdcall,
41564157 .x86_fastcall => .BORLAND_msfastcall,
41574158 .x86_thiscall => .BORLAND_thiscall,
......@@ -4165,6 +4166,7 @@ fn updateConstInner(dwarf: *Dwarf, pt: Zcu.PerThread, debug_const_index: link.Co
41654166 .aarch64_aapcs_win => .normal,
41664167 .aarch64_vfabi => .LLVM_AAPCS,
41674168 .aarch64_vfabi_sve => .LLVM_AAPCS,
4169 .aarch64_preserve_none => .LLVM_PreserveNone,
41684170
41694171 .arm_aapcs => .LLVM_AAPCS,
41704172 .arm_aapcs_vfp => .LLVM_AAPCS_VFP,
test/c_abi/cfuncs.c+10
......@@ -16488,6 +16488,16 @@ struct ByRef __attribute__((sysv_abi)) c_explict_sys_v(struct ByRef in) {
1648816488}
1648916489#endif
1649016490
16491#if defined __x86_64__ || defined __aarch64__
16492int __attribute__((preserve_none)) c_preserve_none(int x) {
16493 return x + 1;
16494}
16495int __attribute__((preserve_none)) zig_preserve_none(int);
16496void c_preserve_none_check(void) {
16497 assert_or_panic(zig_preserve_none(41) == 42);
16498}
16499#endif
16500
1649116501struct byval_tail_callsite_attr_Point {
1649216502 double x;
1649316503 double y;
test/c_abi/main.zig+22
......@@ -17798,3 +17798,25 @@ test "win64 varargs" {
1779817798 @as(Opv, .{}),
1779917799 );
1780017800}
17801
17802const preserve_none_cc: ?std.lang.CallingConvention = if (builtin.zig_backend != .stage2_llvm)
17803 null
17804else switch (builtin.cpu.arch) {
17805 .x86_64 => .{ .x86_64_preserve_none = .{} },
17806 .aarch64, .aarch64_be => .{ .aarch64_preserve_none = .{} },
17807 else => null,
17808};
17809
17810export fn zig_preserve_none(x: i32) callconv(preserve_none_cc orelse .c) i32 {
17811 return x + 1;
17812}
17813
17814test "preserve_none calling convention" {
17815 if (preserve_none_cc == null) return error.SkipZigTest;
17816 const static = struct {
17817 extern fn c_preserve_none(x: i32) callconv(preserve_none_cc.?) i32;
17818 extern fn c_preserve_none_check() void;
17819 };
17820 try expect(static.c_preserve_none(41) == 42);
17821 static.c_preserve_none_check();
17822}
test/cases/compile_errors/callconv_preserve_none_on_unsupported_platform.zig created+16
......@@ -0,0 +1,16 @@
1const F1 = fn () callconv(.{ .x86_64_preserve_none = .{} }) void;
2const F2 = fn () callconv(.{ .aarch64_preserve_none = .{} }) 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=riscv64-linux-none
14//
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'