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