|  | 
|  | 1 | +#![feature(extended_varargs_abi_support)] | 
|  | 2 | +//@ run-pass | 
|  | 3 | +//@ only-arm | 
|  | 4 | +//@ ignore-thumb (this test uses arm assembly) | 
|  | 5 | +//@ only-eabihf (the assembly below requires float hardware support) | 
|  | 6 | + | 
|  | 7 | +// Check that multiple c-variadic calling conventions can be used in the same program. | 
|  | 8 | +// | 
|  | 9 | +// Clang and gcc reject defining functions with a non-default calling convention and a variable | 
|  | 10 | +// argument list, so C programs that use multiple c-variadic calling conventions are unlikely | 
|  | 11 | +// to come up. Here we validate that our codegen backends do in fact generate correct code. | 
|  | 12 | + | 
|  | 13 | +extern "C" { | 
|  | 14 | +    fn variadic_c(_: f64, _: ...) -> f64; | 
|  | 15 | +} | 
|  | 16 | + | 
|  | 17 | +extern "aapcs" { | 
|  | 18 | +    fn variadic_aapcs(_: f64, _: ...) -> f64; | 
|  | 19 | +} | 
|  | 20 | + | 
|  | 21 | +fn main() { | 
|  | 22 | +    unsafe { | 
|  | 23 | +        assert_eq!(variadic_c(1.0, 2.0, 3.0), 1.0 + 2.0 + 3.0); | 
|  | 24 | +        assert_eq!(variadic_aapcs(1.0, 2.0, 3.0), 1.0 + 2.0 + 3.0); | 
|  | 25 | +    } | 
|  | 26 | +} | 
|  | 27 | + | 
|  | 28 | +// This assembly was generated using https://godbolt.org/z/xcW6a1Tj5, and corresponds to the | 
|  | 29 | +// following code compiled for the `armv7-unknown-linux-gnueabihf` target: | 
|  | 30 | +// | 
|  | 31 | +// ```rust | 
|  | 32 | +// #![feature(c_variadic)] | 
|  | 33 | +// | 
|  | 34 | +// #[unsafe(no_mangle)] | 
|  | 35 | +// unsafe extern "C" fn variadic(a: f64, mut args: ...) -> f64 { | 
|  | 36 | +//     let b = args.arg::<f64>(); | 
|  | 37 | +//     let c = args.arg::<f64>(); | 
|  | 38 | +// | 
|  | 39 | +//     a + b + c | 
|  | 40 | +// } | 
|  | 41 | +// ``` | 
|  | 42 | +// | 
|  | 43 | +// This function uses floats (and passes one normal float argument) because the aapcs and C calling | 
|  | 44 | +// conventions differ in how floats are passed, e.g. https://godbolt.org/z/sz799f51x. However, for | 
|  | 45 | +// c-variadic functions, both ABIs actually behave the same, based on: | 
|  | 46 | +// | 
|  | 47 | +// https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst#65parameter-passing | 
|  | 48 | +// | 
|  | 49 | +// > A variadic function is always marshaled as for the base standard. | 
|  | 50 | +// | 
|  | 51 | +// https://github.com/ARM-software/abi-aa/blob/main/aapcs32/aapcs32.rst#7the-standard-variants | 
|  | 52 | +// | 
|  | 53 | +// > This section applies only to non-variadic functions. For a variadic function the base standard | 
|  | 54 | +// > is always used both for argument passing and result return. | 
|  | 55 | +core::arch::global_asm!( | 
|  | 56 | +    r#" | 
|  | 57 | +{variadic_c}: | 
|  | 58 | +{variadic_aapcs}: | 
|  | 59 | +        sub     sp, sp, #12 | 
|  | 60 | +        stmib   sp, {{r2, r3}} | 
|  | 61 | +        vmov    d0, r0, r1 | 
|  | 62 | +        add     r0, sp, #4 | 
|  | 63 | +        vldr    d1, [sp, #4] | 
|  | 64 | +        add     r0, r0, #15 | 
|  | 65 | +        bic     r0, r0, #7 | 
|  | 66 | +        vadd.f64        d0, d0, d1 | 
|  | 67 | +        add     r1, r0, #8 | 
|  | 68 | +        str     r1, [sp] | 
|  | 69 | +        vldr    d1, [r0] | 
|  | 70 | +        vadd.f64        d0, d0, d1 | 
|  | 71 | +        vmov    r0, r1, d0 | 
|  | 72 | +        add     sp, sp, #12 | 
|  | 73 | +        bx      lr | 
|  | 74 | +    "#, | 
|  | 75 | +    variadic_c = sym variadic_c, | 
|  | 76 | +    variadic_aapcs = sym variadic_aapcs, | 
|  | 77 | +); | 
0 commit comments