Skip to content

Commit 5440cce

Browse files
committed
c-variadic: multiple ABIs in the same program for arm
1 parent 86ef320 commit 5440cce

File tree

3 files changed

+78
-0
lines changed

3 files changed

+78
-0
lines changed

src/tools/compiletest/src/directives.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
964964
"only-bpf",
965965
"only-cdb",
966966
"only-dist",
967+
"only-eabihf",
967968
"only-elf",
968969
"only-emscripten",
969970
"only-gnu",
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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

Comments
 (0)