xref: /llvm-project/clang/test/CodeGen/AArch64/soft-float-abi-errors.c (revision 207e5ccceec8d3cc3f32723e78f2a142bc61b07d)
1*207e5cccSFangrui Song // REQUIRES: aarch64-registered-target
2*207e5cccSFangrui Song 
3*207e5cccSFangrui Song // RUN: %clang_cc1 -triple aarch64 -target-feature +fp-armv8 -S -o /dev/null -target-abi aapcs -verify=fp-hard %s
4*207e5cccSFangrui Song // RUN: %clang_cc1 -triple aarch64 -target-feature -fp-armv8 -S -o /dev/null -target-abi aapcs-soft -verify=nofp-soft %s
5*207e5cccSFangrui Song // RUN: %clang_cc1 -triple aarch64 -target-feature -fp-armv8 -S -o /dev/null -target-abi aapcs -verify=nofp-hard %s
6*207e5cccSFangrui Song // RUN: %clang_cc1 -triple aarch64 -target-feature -fp-armv8 -o /dev/null -target-abi aapcs -O1 -verify=nofp-hard,nofp-hard-opt -emit-llvm %s
7*207e5cccSFangrui Song // No run line needed for soft-float ABI with an FPU because that is rejected by the driver
8*207e5cccSFangrui Song 
9*207e5cccSFangrui Song // With the hard-float ABI and a target with an FPU, FP arguments are passed in
10*207e5cccSFangrui Song // FP registers, no diagnostics needed.
11*207e5cccSFangrui Song // fp-hard-no-diagnostics
12*207e5cccSFangrui Song 
13*207e5cccSFangrui Song // With the soft-float ABI, FP arguments are passed in integer registers, no
14*207e5cccSFangrui Song // diagnostics needed.
15*207e5cccSFangrui Song // nofp-soft-no-diagnostics
16*207e5cccSFangrui Song 
17*207e5cccSFangrui Song // With the hard-float ABI but no FPU, FP arguments cannot be passed in an
18*207e5cccSFangrui Song // ABI-compatible way, so we report errors for these cases:
19*207e5cccSFangrui Song 
20*207e5cccSFangrui Song struct HFA {
21*207e5cccSFangrui Song   float x, y;
22*207e5cccSFangrui Song };
23*207e5cccSFangrui Song 
24*207e5cccSFangrui Song struct non_HFA {
25*207e5cccSFangrui Song   float x;
26*207e5cccSFangrui Song   int y;
27*207e5cccSFangrui Song };
28*207e5cccSFangrui Song 
29*207e5cccSFangrui Song // Floating-point arguments are returns are rejected
30*207e5cccSFangrui Song void test_fp16_arg(__fp16 a) {}
31*207e5cccSFangrui Song // nofp-hard-error@-1 {{'a' requires '__fp16' type support, but ABI 'aapcs' does not support it}}
32*207e5cccSFangrui Song __fp16 test_fp16_ret(void) { return 3.141; }
33*207e5cccSFangrui Song // nofp-hard-error@-1 {{'test_fp16_ret' requires '__fp16' type support, but ABI 'aapcs' does not support it}}
34*207e5cccSFangrui Song void test_float_arg(float a) {}
35*207e5cccSFangrui Song // nofp-hard-error@-1 {{'a' requires 'float' type support, but ABI 'aapcs' does not support it}}
36*207e5cccSFangrui Song float test_float_ret(void) { return 3.141f; }
37*207e5cccSFangrui Song // nofp-hard-error@-1 {{'test_float_ret' requires 'float' type support, but ABI 'aapcs' does not support it}}
38*207e5cccSFangrui Song void test_double_arg(double a) {}
39*207e5cccSFangrui Song // nofp-hard-error@-1 {{'a' requires 'double' type support, but ABI 'aapcs' does not support it}}
40*207e5cccSFangrui Song double test_double_ret(void) { return 3.141; }
41*207e5cccSFangrui Song // nofp-hard-error@-1 {{'test_double_ret' requires 'double' type support, but ABI 'aapcs' does not support it}}
42*207e5cccSFangrui Song void test_long_double_arg(long double a) {}
43*207e5cccSFangrui Song // nofp-hard-error@-1 {{'a' requires 'long double' type support, but ABI 'aapcs' does not support it}}
44*207e5cccSFangrui Song long double test_long_double_ret(void) { return 3.141L; }
45*207e5cccSFangrui Song // nofp-hard-error@-1 {{'test_long_double_ret' requires 'long double' type support, but ABI 'aapcs' does not support it}}
46*207e5cccSFangrui Song 
47*207e5cccSFangrui Song // HFAs would be passed in floating-point registers, so are rejected.
48*207e5cccSFangrui Song void test_hfa_arg(struct HFA a) {}
49*207e5cccSFangrui Song // nofp-hard-error@-1 {{'a' requires 'struct HFA' type support, but ABI 'aapcs' does not support it}}
50*207e5cccSFangrui Song struct HFA test_hfa_ret(void) { return (struct HFA){}; }
51*207e5cccSFangrui Song // nofp-hard-error@-1 {{'test_hfa_ret' requires 'struct HFA' type support, but ABI 'aapcs' does not support it}}
52*207e5cccSFangrui Song 
53*207e5cccSFangrui Song // Note: vector types cannot be created at all for targets without an FPU, so
54*207e5cccSFangrui Song // it is not possible to create a function which passes/returns them when using
55*207e5cccSFangrui Song // either the default or soft-float ABI. This is tested elsewhere.
56*207e5cccSFangrui Song 
57*207e5cccSFangrui Song // This struct contains a floating-point type, but is not an HFA, so can be
58*207e5cccSFangrui Song // passed/returned without affecting the ABI.
59*207e5cccSFangrui Song struct non_HFA test_non_hfa_ret(void) { return (struct non_HFA){}; }
60*207e5cccSFangrui Song void test_non_hfa_arg(struct non_HFA a) {}
61*207e5cccSFangrui Song 
62*207e5cccSFangrui Song // This inline function does not get code-generated because there is no use of
63*207e5cccSFangrui Song // it in this file, so we we don't emit an error for it, matching GCC's
64*207e5cccSFangrui Song // behaviour.
65*207e5cccSFangrui Song inline void test_float_arg_inline(float a) {}
66*207e5cccSFangrui Song 
67*207e5cccSFangrui Song // This inline function is used, so we emit the error if we generate code for
68*207e5cccSFangrui Song // it. The code isn't generated at -O0, so no error is emitted there.
69*207e5cccSFangrui Song inline void test_float_arg_inline_used(float a) {}
70*207e5cccSFangrui Song // nofp-hard-opt-error@-1 {{'a' requires 'float' type support, but ABI 'aapcs' does not support it}}
71*207e5cccSFangrui Song void use_inline() { test_float_arg_inline_used(1.0f); }
72*207e5cccSFangrui Song // nofp-hard-error@-1 {{'test_float_arg_inline_used' requires 'float' type support, but ABI 'aapcs' does not support it}}
73*207e5cccSFangrui Song 
74*207e5cccSFangrui Song // The always_inline attribute causes an inline function to always be
75*207e5cccSFangrui Song // code-genned, even at -O0, so we always emit the error.
76*207e5cccSFangrui Song __attribute((always_inline))
77*207e5cccSFangrui Song inline void test_float_arg_always_inline_used(float a) {}
78*207e5cccSFangrui Song // nofp-hard-error@-1 {{'a' requires 'float' type support, but ABI 'aapcs' does not support it}}
79*207e5cccSFangrui Song void use_always_inline() { test_float_arg_always_inline_used(1.0f); }
80*207e5cccSFangrui Song // nofp-hard-error@-1 {{'test_float_arg_always_inline_used' requires 'float' type support, but ABI 'aapcs' does not support it}}
81*207e5cccSFangrui Song 
82*207e5cccSFangrui Song // Floating-point expressions, global variables and local variables do not
83*207e5cccSFangrui Song // affect the ABI, so are allowed. GCC does reject some uses of floating point
84*207e5cccSFangrui Song // types like this, but it does so after optimisation, which we can't
85*207e5cccSFangrui Song // accurately match in clang.
86*207e5cccSFangrui Song int test_expr_float(int a) { return a + 1.0f; }
87*207e5cccSFangrui Song int test_expr_double(int a) { return a + 1.0; }
88*207e5cccSFangrui Song 
89*207e5cccSFangrui Song float global_float = 2.0f * 3.5f;
90*207e5cccSFangrui Song float global_double = 2.0 * 3.5;
91*207e5cccSFangrui Song 
92*207e5cccSFangrui Song int test_var_float(int a) {
93*207e5cccSFangrui Song   float f = a;
94*207e5cccSFangrui Song   f *= 6.0;
95*207e5cccSFangrui Song   return (int)f;
96*207e5cccSFangrui Song }
97*207e5cccSFangrui Song int test_var_double(int a) {
98*207e5cccSFangrui Song   double d = a;
99*207e5cccSFangrui Song   d *= 6.0;
100*207e5cccSFangrui Song   return (int)d;
101*207e5cccSFangrui Song }
102*207e5cccSFangrui Song 
103*207e5cccSFangrui Song extern void extern_float_arg(float);
104*207e5cccSFangrui Song extern float extern_float_ret(void);
105*207e5cccSFangrui Song void call_extern_float_arg() { extern_float_arg(1.0f); }
106*207e5cccSFangrui Song // nofp-hard-error@-1 {{'extern_float_arg' requires 'float' type support, but ABI 'aapcs' does not support it}}
107*207e5cccSFangrui Song void call_extern_float_ret() { extern_float_ret(); }
108*207e5cccSFangrui Song // nofp-hard-error@-1 {{'extern_float_ret' requires 'float' type support, but ABI 'aapcs' does not support it}}
109*207e5cccSFangrui Song 
110*207e5cccSFangrui Song // Definitions of variadic functions, and calls to them which only use integer
111*207e5cccSFangrui Song // argument registers, are both fine.
112*207e5cccSFangrui Song void variadic(int, ...);
113*207e5cccSFangrui Song void call_variadic_int() { variadic(0, 1); }
114*207e5cccSFangrui Song 
115*207e5cccSFangrui Song // Calls to variadic functions with floating-point arguments are an error,
116*207e5cccSFangrui Song // since this would require floating-point registers.
117*207e5cccSFangrui Song void call_variadic_double() { variadic(0, 1.0); }
118*207e5cccSFangrui Song // nofp-hard-error@-1 {{'variadic' requires 'double' type support, but ABI 'aapcs' does not support it}}
119*207e5cccSFangrui Song 
120*207e5cccSFangrui Song // Calls through function pointers are also diagnosed.
121*207e5cccSFangrui Song void (*fptr)(float);
122*207e5cccSFangrui Song void call_indirect() { fptr(1.0f); }
123*207e5cccSFangrui Song // nofp-hard-error@-1 {{'call_indirect' requires 'float' type support, but ABI 'aapcs' does not support it}}
124