| //@ run-pass | |
| //@ only-x86_64 | |
| #![feature(c_variadic_naked_functions)] | |
| // Check that multiple c-variadic calling conventions can be used in the same program. | |
| // | |
| // Clang and gcc reject defining functions with a non-default calling convention and a variable | |
| // argument list, so C programs that use multiple c-variadic calling conventions are unlikely | |
| // to come up. Here we validate that our codegen backends do in fact generate correct code. | |
| fn main() { | |
| unsafe { | |
| assert_eq!(variadic_win64(1, 2, 3), 1 + 2 + 3); | |
| assert_eq!(variadic_sysv64(1, 2, 3), 1 + 2 + 3); | |
| } | |
| } | |
| // This assembly was generated using https://godbolt.org/z/dbTGanoh6, and corresponds to the | |
| // following code compiled for the `x86_64-unknown-linux-gnu` and `x86_64-pc-windows-gnu` | |
| // targets, respectively: | |
| // | |
| // ```rust | |
| // #[unsafe(no_mangle)] | |
| // unsafe extern "C" fn variadic(a: u32, mut args: ...) -> u32 { | |
| // let b = args.next_arg::<u32>(); | |
| // let c = args.next_arg::<u32>(); | |
| // | |
| // a + b + c | |
| // } | |
| // ``` | |
| #[unsafe(naked)] | |
| unsafe extern "sysv64" fn variadic_sysv64(_: u32, _: ...) -> u32 { | |
| core::arch::naked_asm!( | |
| r#" | |
| sub rsp, 88 | |
| test al, al | |
| je .LBB0_7 | |
| movaps xmmword ptr [rsp - 48], xmm0 | |
| movaps xmmword ptr [rsp - 32], xmm1 | |
| movaps xmmword ptr [rsp - 16], xmm2 | |
| movaps xmmword ptr [rsp], xmm3 | |
| movaps xmmword ptr [rsp + 16], xmm4 | |
| movaps xmmword ptr [rsp + 32], xmm5 | |
| movaps xmmword ptr [rsp + 48], xmm6 | |
| movaps xmmword ptr [rsp + 64], xmm7 | |
| .LBB0_7: | |
| mov qword ptr [rsp - 88], rsi | |
| mov qword ptr [rsp - 80], rdx | |
| mov qword ptr [rsp - 72], rcx | |
| mov qword ptr [rsp - 64], r8 | |
| mov qword ptr [rsp - 56], r9 | |
| movabs rax, 206158430216 | |
| mov qword ptr [rsp - 120], rax | |
| lea rax, [rsp + 96] | |
| mov qword ptr [rsp - 112], rax | |
| lea rax, [rsp - 96] | |
| mov qword ptr [rsp - 104], rax | |
| mov edx, 8 | |
| cmp rdx, 41 | |
| jae .LBB0_1 | |
| mov rax, qword ptr [rsp - 104] | |
| mov ecx, 8 | |
| add rcx, 8 | |
| mov dword ptr [rsp - 120], ecx | |
| mov eax, dword ptr [rax + rdx] | |
| cmp edx, 32 | |
| ja .LBB0_2 | |
| add rcx, qword ptr [rsp - 104] | |
| add edx, 16 | |
| mov dword ptr [rsp - 120], edx | |
| add eax, edi | |
| add eax, dword ptr [rcx] | |
| add rsp, 88 | |
| ret | |
| .LBB0_1: | |
| mov rax, qword ptr [rsp - 112] | |
| lea rcx, [rax + 8] | |
| mov qword ptr [rsp - 112], rcx | |
| mov eax, dword ptr [rax] | |
| .LBB0_2: | |
| mov rcx, qword ptr [rsp - 112] | |
| lea rdx, [rcx + 8] | |
| mov qword ptr [rsp - 112], rdx | |
| add eax, edi | |
| add eax, dword ptr [rcx] | |
| add rsp, 88 | |
| ret | |
| "#, | |
| ) | |
| } | |
| #[unsafe(naked)] | |
| unsafe extern "win64" fn variadic_win64(_: u32, _: ...) -> u32 { | |
| core::arch::naked_asm!( | |
| r#" | |
| push rax | |
| mov qword ptr [rsp + 40], r9 | |
| mov qword ptr [rsp + 24], rdx | |
| mov qword ptr [rsp + 32], r8 | |
| lea rax, [rsp + 40] | |
| mov qword ptr [rsp], rax | |
| lea eax, [rdx + rcx] | |
| add eax, r8d | |
| pop rcx | |
| ret | |
| "#, | |
| ) | |
| } |