The ACLE defines a new scalar type, __mfp8. This is an opaque 8bit types that can only be used by fp8 intrinsics. Additionally, the mfloat8_t type is made available in arm_neon.h and arm_sve.h as an alias of the same.
This implementation uses an INTEGER_TYPE, with precision 8 to represent __mfp8. Conversions to int and other types are disabled via the TARGET_INVALID_CONVERSION hook. Additionally, operations that are typically available to integer types are disabled via TARGET_INVALID_UNARY_OP and TARGET_INVALID_BINARY_OP hooks. gcc/ChangeLog: * config/aarch64/aarch64-builtins.cc (aarch64_mfp8_type_node): Add node for __mfp8 type. (aarch64_mfp8_ptr_type_node): Add node for __mfp8 pointer type. (aarch64_init_fp8_types): New function to initialise fp8 types and register with language backends. * config/aarch64/aarch64.cc (aarch64_invalid_conversion): Add function implementing TARGET_INVALID_CONVERSION hook that blocks conversion to and from __mfp8 type. (aarch64_invalid_unary_op): Add function implementing TARGET_UNARY_OP hook that blocks operations on __mfp8 other than &. (aarch64_invalid_binary_op): Extend TARGET_BINARY_OP hook to disallow operations on __mfp8 type. (TARGET_INVALID_CONVERSION): Add define. (TARGET_INVALID_UNARY_OP): Likewise. * config/aarch64/aarch64.h (aarch64_mfp8_type_node): Add node for __mfp8 type. (aarch64_mfp8_ptr_type_node): Add node for __mfp8 pointer type. * config/aarch64/arm_neon.h (mfloat8_t): Add typedef. * config/aarch64/arm_sve.h (mfloat8_t): Likewise. gcc/testsuite/ChangeLog: * gcc.target/aarch64/fp8_scalar_1.c: New tests in C. * gcc.target/aarch64/fp8_scalar_typecheck_1.c: Likewise. * gcc.target/aarch64/fp8_scalar_typecheck_2.C: New tests in C++. --- Hi, Is this ok for master? I do not have commit rights yet, if ok, can someone commit it on my behalf? Regression tested with aarch64-unknown-linux-gnu. Thanks, Claudio Bantaloukas gcc/config/aarch64/aarch64-builtins.cc | 23 ++ gcc/config/aarch64/aarch64.cc | 60 +++ gcc/config/aarch64/aarch64.h | 5 + gcc/config/aarch64/arm_neon.h | 2 + gcc/config/aarch64/arm_sve.h | 1 + .../gcc.target/aarch64/fp8_scalar_1.c | 108 ++++++ .../aarch64/fp8_scalar_typecheck_1.c | 329 ++++++++++++++++ .../aarch64/fp8_scalar_typecheck_2.C | 354 ++++++++++++++++++ 8 files changed, 882 insertions(+) create mode 100644 gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c create mode 100644 gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c create mode 100644 gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_2.C
diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc index 30669f8aa18..22d60df396f 100644 --- a/gcc/config/aarch64/aarch64-builtins.cc +++ b/gcc/config/aarch64/aarch64-builtins.cc @@ -961,6 +961,11 @@ static GTY(()) tree aarch64_simd_intOI_type_node = NULL_TREE; static GTY(()) tree aarch64_simd_intCI_type_node = NULL_TREE; static GTY(()) tree aarch64_simd_intXI_type_node = NULL_TREE; +/* The user-visible __mfp8 type, and a pointer to that type. Used + across the back-end. */ +tree aarch64_mfp8_type_node = NULL_TREE; +tree aarch64_mfp8_ptr_type_node = NULL_TREE; + /* The user-visible __fp16 type, and a pointer to that type. Used across the back-end. */ tree aarch64_fp16_type_node = NULL_TREE; @@ -1721,6 +1726,22 @@ aarch64_init_builtin_rsqrt (void) } } +static void +aarch64_init_fp8_types (void) +{ + aarch64_mfp8_type_node = make_node (INTEGER_TYPE); + TYPE_PRECISION (aarch64_mfp8_type_node) = 8; + TYPE_MIN_VALUE (aarch64_mfp8_type_node) + = TYPE_MIN_VALUE (unsigned_char_type_node); + TYPE_MAX_VALUE (aarch64_mfp8_type_node) + = TYPE_MAX_VALUE (unsigned_char_type_node); + layout_type (aarch64_mfp8_type_node); + SET_TYPE_MODE (aarch64_mfp8_type_node, QImode); + + lang_hooks.types.register_builtin_type (aarch64_mfp8_type_node, "__mfp8"); + aarch64_mfp8_ptr_type_node = build_pointer_type (aarch64_mfp8_type_node); +} + /* Initialize the backend types that support the user-visible __fp16 type, also initialize a pointer to that type, to be used when forming HFAs. */ @@ -2128,6 +2149,8 @@ aarch64_general_init_builtins (void) { aarch64_init_fpsr_fpcr_builtins (); + aarch64_init_fp8_types (); + aarch64_init_fp16_types (); aarch64_init_bf16_types (); diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 9810f2c0390..e774b95e430 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -22450,6 +22450,35 @@ aarch64_mangle_type (const_tree type) return NULL; } +/* Implement TARGET_INVALID_CONVERSION. + +Return the diagnostic message when it is invalid to convert from fromtype to +totype, or NULL if validity should be determined by the front end. */ + +static const char * +aarch64_invalid_conversion (const_tree fromtype, const_tree totype) +{ + /* Do not allow conversions to/from FP8. */ + bool fromtype_is_fp8 + = ((fromtype) && (TYPE_MODE (fromtype) == QImode) + && (TYPE_MAIN_VARIANT (fromtype) == aarch64_mfp8_type_node)); + bool totype_is_fp8 + = ((totype) + && (TYPE_MODE (totype) == QImode + && TYPE_MAIN_VARIANT (totype) == aarch64_mfp8_type_node)); + + /* But do allow conversions between volatile and const __mfp8 */ + if (fromtype_is_fp8 && totype_is_fp8) + return NULL; + + if (fromtype_is_fp8) + return N_ ("invalid conversion from type %<mfloat8_t%>"); + if (totype_is_fp8) + return N_ ("invalid conversion to type %<mfloat8_t%>"); + /* Conversion allowed. */ + return NULL; +} + /* Implement TARGET_VERIFY_TYPE_CONTEXT. */ static bool @@ -28967,6 +28996,24 @@ aarch64_stack_protect_guard (void) return NULL_TREE; } +/* Implement TARGET_INVALID_UNARY_OP. + + Return the diagnostic message string if the unary operation OP is + not permitted on TYPE, NULL otherwise. */ + +static const char * +aarch64_invalid_unary_op (int op, const_tree type) +{ + /* Reject all single-operand operations on __mfp8 except for &. */ + if ((TYPE_MODE (type) == QImode) + && (TYPE_MAIN_VARIANT (type) == aarch64_mfp8_type_node) + && (op != ADDR_EXPR)) + return N_ ("operation not permitted on type %<mfloat8_t%>"); + + /* Operation allowed. */ + return NULL; +} + /* Return the diagnostic message string if the binary operation OP is not permitted on TYPE1 and TYPE2, NULL otherwise. */ @@ -28982,6 +29029,13 @@ aarch64_invalid_binary_op (int op ATTRIBUTE_UNUSED, const_tree type1, != aarch64_sve::builtin_type_p (type2))) return N_("cannot combine GNU and SVE vectors in a binary operation"); + /* Reject all 2-operand operations on __mfp8. */ + if (((TYPE_MODE (type1) == QImode) + && (TYPE_MAIN_VARIANT (type1) == aarch64_mfp8_type_node)) + || ((TYPE_MODE (type2) == QImode) + && (TYPE_MAIN_VARIANT (type2) == aarch64_mfp8_type_node))) + return N_ ("operation not permitted on type %<mfloat8_t%>"); + /* Operation allowed. */ return NULL; } @@ -30699,6 +30753,12 @@ aarch64_libgcc_floating_mode_supported_p #undef TARGET_MANGLE_TYPE #define TARGET_MANGLE_TYPE aarch64_mangle_type +#undef TARGET_INVALID_CONVERSION +#define TARGET_INVALID_CONVERSION aarch64_invalid_conversion + +#undef TARGET_INVALID_UNARY_OP +#define TARGET_INVALID_UNARY_OP aarch64_invalid_unary_op + #undef TARGET_INVALID_BINARY_OP #define TARGET_INVALID_BINARY_OP aarch64_invalid_binary_op diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index 2dfb999bea5..7ef82ce3587 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -1447,6 +1447,11 @@ extern const char *aarch64_rewrite_mcpu (int argc, const char **argv); #define ASM_OUTPUT_POOL_EPILOGUE aarch64_asm_output_pool_epilogue +/* This type is the user-visible __mfp8, and a pointer to that type. We + need it in many places in the backend. Defined in aarch64-builtins.cc. */ +extern GTY(()) tree aarch64_mfp8_type_node; +extern GTY(()) tree aarch64_mfp8_ptr_type_node; + /* This type is the user-visible __fp16, and a pointer to that type. We need it in many places in the backend. Defined in aarch64-builtins.cc. */ extern GTY(()) tree aarch64_fp16_type_node; diff --git a/gcc/config/aarch64/arm_neon.h b/gcc/config/aarch64/arm_neon.h index e376685489d..0092314cf75 100644 --- a/gcc/config/aarch64/arm_neon.h +++ b/gcc/config/aarch64/arm_neon.h @@ -72,6 +72,8 @@ typedef __Poly16_t poly16_t; typedef __Poly64_t poly64_t; typedef __Poly128_t poly128_t; +typedef __mfp8 mfloat8_t; + typedef __fp16 float16_t; typedef float float32_t; typedef double float64_t; diff --git a/gcc/config/aarch64/arm_sve.h b/gcc/config/aarch64/arm_sve.h index aa0bd9909f9..61c440fef56 100644 --- a/gcc/config/aarch64/arm_sve.h +++ b/gcc/config/aarch64/arm_sve.h @@ -29,6 +29,7 @@ #include <arm_private_fp8.h> #include <arm_bf16.h> +typedef __mfp8 mfloat8_t; typedef __fp16 float16_t; typedef float float32_t; typedef double float64_t; diff --git a/gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c new file mode 100644 index 00000000000..6925653e33c --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_1.c @@ -0,0 +1,108 @@ +/* Test the fp8 ACLE intrinsics family. */ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=armv9.4-a+fp8" } */ +/* { dg-final { check-function-bodies "**" "" "" } } */ + +#include <arm_neon.h> + +/* +**stacktest1: +** sub sp, sp, #16 +** sxtb w0, w0 +** strb w0, \[sp, 15\] +** ldrb w0, \[sp, 15\] +** add sp, sp, 16 +** ret +*/ +mfloat8_t +stacktest1 (mfloat8_t __a) +{ + volatile mfloat8_t b = __a; + return b; +} + +/* +**fp8_mov_ww: +** dup b1, v2.b\[0\] +** ret +*/ +void +fp8_mov_ww (void) +{ + register mfloat8_t x asm ("h2"); + register mfloat8_t y asm ("h1"); + asm volatile ("" : "=w"(x)); + y = x; + asm volatile ("" ::"w"(y)); +} + +/* +**fp8_mov_rw: +** dup v1.8b, w1 +** ret +*/ +void +fp8_mov_rw (void) +{ + register mfloat8_t x asm ("w1"); + register mfloat8_t y asm ("h1"); + asm volatile ("" : "=r"(x)); + y = x; + asm volatile ("" ::"w"(y)); +} + +/* +**fp8_mov_wr: +** umov w1, v1.b\[0\] +** ret +*/ +void +fp8_mov_wr (void) +{ + register mfloat8_t x asm ("h1"); + register mfloat8_t y asm ("w1"); + asm volatile ("" : "=w"(x)); + y = x; + asm volatile ("" ::"r"(y)); +} + +/* +**fp8_mov_rr: +** mov w1, w2 +** ret +*/ +void +fp8_mov_rr (void) +{ + register mfloat8_t x asm ("w2"); + register mfloat8_t y asm ("w1"); + asm volatile ("" : "=r"(x)); + y = x; + asm volatile ("" ::"r"(y)); +} + +/* +**fp8_mov_rm: +** strb w2, \[x0\] +** ret +*/ +void +fp8_mov_rm (mfloat8_t *ptr) +{ + register mfloat8_t x asm ("w2"); + asm volatile ("" : "=r"(x)); + *ptr = x; +} + +/* +**fp8_mov_mr: +** ldrb w2, \[x0\] +** ret +*/ +void +fp8_mov_mr (mfloat8_t *ptr) +{ + register mfloat8_t y asm ("w2"); + y = *ptr; + asm volatile ("" ::"r"(y)); +} diff --git a/gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c new file mode 100644 index 00000000000..122dc5aa2b5 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_1.c @@ -0,0 +1,329 @@ +/* Test that there is no conversion between ints and mfloat8_t. */ +/* { dg-do assemble } */ +/* { dg-options "-O1 -march=armv9.4-a+fp8" } */ + +#include <arm_neon.h> +#include <stdint.h> + +mfloat8_t glob_fp8; + +int is_an_int; +uint8_t is_a_uint8; +int8_t is_an_int8; +short is_a_short_int; +float is_a_float; +double is_a_double; + +uint8_t *uint8_ptr; + +mfloat8_t +invalid_from_fp8 (uint16_t __a) +{ + mfloat8_t b = __a; // { dg-error "invalid conversion to type 'mfloat8_t'" } + return b; +} + +uint16_t +invalid_to_fp8 (mfloat8_t __a) +{ + uint16_t b = __a; // { dg-error "invalid conversion from type 'mfloat8_t'" } + return b; +} + +mfloat8_t +foo1 (void) +{ + return (mfloat8_t)0x1234; // { dg-error {invalid conversion to type 'mfloat8_t'} } +} +mfloat8_t +foo2 (void) +{ + return (mfloat8_t)(short)0x1234; // { dg-error {invalid conversion to type 'mfloat8_t'} } +} + +mfloat8_t +footest (mfloat8_t scalar0) +{ + + /* Initialisation */ + + mfloat8_t scalar1_1; + mfloat8_t scalar1_2 = glob_fp8; + mfloat8_t scalar1_3 = 0; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar1_4 + = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar1_5 + = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar1_6 + = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar1_8 + = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar1_9 + = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar1_10 + = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar1_11 + = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + + int initi_1_1 + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + float initi_1_2 + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + short initi_1_4 + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + double initi_1_5 + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + uint8_t initi_1_6 + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + int8_t initi_1_7 + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + + mfloat8_t scalar2_1 = {}; + mfloat8_t scalar2_2 = { glob_fp8 }; + mfloat8_t scalar2_3 + = { 0 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar2_4 + = { 0.1 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar2_5 + = { is_a_float }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar2_6 + = { is_an_int }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar2_8 = { + is_a_double + }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar2_9 = { + is_a_short_int + }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar2_10 + = { is_a_uint8 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar2_11 + = { is_an_int8 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + + int initi_2_1 + = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + float initi_2_2 + = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + short initi_2_4 + = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + double initi_2_5 + = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + uint8_t initi_2_6 + = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + int8_t initi_2_7 + = { glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + + /* Assignments. */ + + glob_fp8 = glob_fp8; + glob_fp8 = 0; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + glob_fp8 = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + glob_fp8 + = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + glob_fp8 = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + glob_fp8 + = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + glob_fp8 + = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + glob_fp8 + = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + glob_fp8 + = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + + is_an_int + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + is_a_float + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + is_a_double + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + is_a_short_int + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + is_a_uint8 + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + is_an_int8 + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + + /* Casting. */ + + (void)glob_fp8; + (mfloat8_t) glob_fp8; + + (int)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + (float)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + (double)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + (short)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + (uint8_t)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + (int8_t)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + + (mfloat8_t) is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + (mfloat8_t) is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + (mfloat8_t) is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + (mfloat8_t) + is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + (mfloat8_t) is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + (mfloat8_t) is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + + /* Compound literals. */ + + (mfloat8_t){}; + (mfloat8_t){ glob_fp8 }; + (mfloat8_t){ 0 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + (mfloat8_t){ 0.1 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + (mfloat8_t){ + is_a_float + }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + (mfloat8_t){ + is_an_int + }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + (mfloat8_t){ + is_a_double + }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + (mfloat8_t){ + is_a_short_int + }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + (mfloat8_t){ + is_a_uint8 + }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + (mfloat8_t){ + is_an_int8 + }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + + (int){ glob_fp8 }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + (float){ + glob_fp8 + }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + (double){ + glob_fp8 + }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + (short){ + glob_fp8 + }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + (uint8_t){ + glob_fp8 + }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + (int8_t){ + glob_fp8 + }; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + + /* Arrays and Structs. */ + + typedef mfloat8_t array_type[2]; + extern mfloat8_t extern_array[]; + + mfloat8_t array[2]; + mfloat8_t zero_length_array[0]; + mfloat8_t empty_init_array[] = {}; + typedef mfloat8_t some_other_type[is_an_int]; + + struct struct1 + { + mfloat8_t a; + }; + + union union1 + { + mfloat8_t a; + }; + + /* Addressing and dereferencing. */ + + mfloat8_t *fp8_ptr = &scalar0; + scalar0 = *fp8_ptr; + + /* Pointer assignment. */ + + mfloat8_t *fp8_ptr2 = fp8_ptr; + mfloat8_t *fp8_ptr3 = array; + + /* Pointer arithmetic. */ + + ++fp8_ptr; + --fp8_ptr; + fp8_ptr++; + fp8_ptr--; + fp8_ptr += 1; + fp8_ptr -= 1; + fp8_ptr - fp8_ptr2; + fp8_ptr = &fp8_ptr3[0]; + fp8_ptr = &fp8_ptr3[1]; + + /* Simple comparison. */ + scalar0 > glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + glob_fp8 + == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 > is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + is_a_float + == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 > 0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + 0 == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 > 0.1; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + 0.1 == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 + > is_an_int; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + is_an_int + == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + + /* Pointer comparison. */ + + fp8_ptr == &scalar0; + fp8_ptr != &scalar0; + fp8_ptr < &scalar0; + fp8_ptr <= &scalar0; + fp8_ptr > &scalar0; + fp8_ptr >= &scalar0; + fp8_ptr == fp8_ptr2; + fp8_ptr != fp8_ptr2; + fp8_ptr < fp8_ptr2; + fp8_ptr <= fp8_ptr2; + fp8_ptr > fp8_ptr2; + fp8_ptr >= fp8_ptr2; + + /* Conditional expressions. */ + + 0 ? scalar0 : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + 0 ? scalar0 + : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + 0 ? is_a_float + : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + 0 ? scalar0 : 0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + 0 ? 0 : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + 0 ? 0.1 : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + 0 ? scalar0 : 0.1; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + 0 ? fp8_ptr : fp8_ptr2; + 0 ? fp8_ptr : uint8_ptr; /* { dg-error {pointer type mismatch in conditional expression} } */ + 0 ? uint8_ptr : fp8_ptr; /* { dg-error {pointer type mismatch in conditional expression} } */ + + scalar0 ? scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 ? is_a_float /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 ? scalar0 : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 ? is_a_float : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + + /* Unary operators. */ + + +scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + -scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + ~scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + !scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + *scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + __real scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + __imag scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + ++scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + --scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + scalar0++; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + scalar0--; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + + /* Binary arithmetic operations. */ + + scalar0 = glob_fp8 + scalar1_2; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 = glob_fp8 + *fp8_ptr; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 = glob_fp8 + + 0.1; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 + = glob_fp8 + 0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 + = glob_fp8 + + is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + + return scalar0; +} diff --git a/gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_2.C b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_2.C new file mode 100644 index 00000000000..f0a3c756c84 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/fp8_scalar_typecheck_2.C @@ -0,0 +1,354 @@ +/* Test that mfloat8_t is only usable with intrinsics, thus not convertible. */ +/* { dg-do assemble } */ +/* { dg-options "-O1 -march=armv9.4-a+fp8 -Wno-narrowing" } */ + +#include <arm_neon.h> +#include <stdint.h> + +mfloat8_t glob_fp8; + +int is_an_int; +uint8_t is_a_uint8; +int8_t is_an_int8; +short is_a_short_int; +float is_a_float; +double is_a_double; + +uint8_t *uint8_ptr; + +mfloat8_t +invalid_from_fp8 (uint16_t __a) +{ + mfloat8_t b = __a; /* { dg-error "invalid conversion to type 'mfloat8_t'" } */ + return b; +} + +uint16_t +invalid_to_fp8 (mfloat8_t __a) +{ + uint16_t b = __a; /*{ dg-error "invalid conversion from type 'mfloat8_t'" } */ + return b; +} + +mfloat8_t +foo1 (void) +{ + return (mfloat8_t)0x1234; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ +} + +mfloat8_t +foo2 (void) +{ + return (mfloat8_t)(short)0x1234; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ +} + +mfloat8_t +footest (mfloat8_t scalar0) +{ + + /* Initialisation */ + + mfloat8_t scalar1_1; + mfloat8_t scalar1_2 = glob_fp8; + mfloat8_t scalar1_3 + = 0; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar1_4 + = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar1_5 + = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar1_6 + = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar1_8 + = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar1_9 = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar1_10 + = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar1_11 + = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + + int initi_1_1 + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + float initi_1_2 + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + short initi_1_4 + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + double initi_1_5 + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + uint8_t initi_1_6 + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + int8_t initi_1_7 + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + + mfloat8_t scalar2_1 = {}; + mfloat8_t scalar2_2 = { glob_fp8 }; + mfloat8_t scalar2_3 + = { 0 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar2_4 + = { 0.1 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + mfloat8_t scalar2_5 = { + is_a_float /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + }; + mfloat8_t scalar2_6 = { + is_an_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + }; + mfloat8_t scalar2_8 = { + is_a_double /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + }; + mfloat8_t scalar2_9 = { + is_a_short_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + }; + mfloat8_t scalar2_10 = { + is_a_uint8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + }; + mfloat8_t scalar2_11 = { + is_an_int8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + }; + + int initi_2_1 = { + glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + }; + float initi_2_2 = { + glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + }; + short initi_2_4 = { + glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + }; + double initi_2_5 = { + glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + }; + uint8_t initi_2_6 = { + glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + }; + int8_t initi_2_7 = { + glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + }; + + /* Assignments. */ + + glob_fp8 = glob_fp8; + glob_fp8 = 0; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + glob_fp8 = 0.1; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + glob_fp8 + = is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + glob_fp8 + = is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + glob_fp8 + = is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + glob_fp8 = is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + glob_fp8 + = is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + glob_fp8 + = is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + + is_an_int + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + is_a_float + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + is_a_double + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + is_a_short_int + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + is_a_uint8 + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + is_an_int8 + = glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + + /* Casting. */ + + (void)glob_fp8; + (mfloat8_t) glob_fp8; + + (int)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + (float)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + (double) + glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + (short)glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + (uint8_t) + glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + (int8_t) + glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + + (mfloat8_t) + is_an_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + (mfloat8_t) + is_a_float; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + (mfloat8_t) + is_a_double; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + (mfloat8_t) is_a_short_int; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + (mfloat8_t) + is_a_uint8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + (mfloat8_t) + is_an_int8; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + + /* Compound literals. */ + + (mfloat8_t){}; + (mfloat8_t){ glob_fp8 }; + (mfloat8_t){ 0 }; /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + (mfloat8_t){ + 0.1 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + }; + (mfloat8_t){ + is_a_float /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + }; + (mfloat8_t){ + is_an_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + }; + (mfloat8_t){ + is_a_double /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + }; + (mfloat8_t){ + is_a_short_int /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + }; + (mfloat8_t){ + is_a_uint8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + }; + (mfloat8_t){ + is_an_int8 /* { dg-error {invalid conversion to type 'mfloat8_t'} } */ + }; + + (int){ + glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + }; + (float){ + glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + }; + (double){ + glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + }; + (short){ + glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + }; + (uint8_t){ + glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + }; + (int8_t){ + glob_fp8 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + }; + + /* Arrays and Structs. */ + + typedef mfloat8_t array_type[2]; + extern mfloat8_t extern_array[]; + + mfloat8_t array[2]; + mfloat8_t zero_length_array[0]; + mfloat8_t empty_init_array[] = {}; + typedef mfloat8_t some_other_type[is_an_int]; + + struct struct1 + { + mfloat8_t a; + }; + + union union1 + { + mfloat8_t a; + }; + + /* Addressing and dereferencing. */ + + mfloat8_t *fp8_ptr = &scalar0; + scalar0 = *fp8_ptr; + + /* Pointer assignment. */ + + mfloat8_t *fp8_ptr2 = fp8_ptr; + mfloat8_t *fp8_ptr3 = array; + + /* Pointer arithmetic. */ + + ++fp8_ptr; + --fp8_ptr; + fp8_ptr++; + fp8_ptr--; + fp8_ptr += 1; + fp8_ptr -= 1; + fp8_ptr - fp8_ptr2; + fp8_ptr = &fp8_ptr3[0]; + fp8_ptr = &fp8_ptr3[1]; + + /* Simple comparison. */ + scalar0 + > glob_fp8; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + glob_fp8 + == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 > is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + is_a_float + == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 > 0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + 0 == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 > 0.1; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + 0.1 == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 + > is_an_int; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + is_an_int + == scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + + /* Pointer comparison. */ + + fp8_ptr == &scalar0; + fp8_ptr != &scalar0; + fp8_ptr < &scalar0; + fp8_ptr <= &scalar0; + fp8_ptr > &scalar0; + fp8_ptr >= &scalar0; + fp8_ptr == fp8_ptr2; + fp8_ptr != fp8_ptr2; + fp8_ptr < fp8_ptr2; + fp8_ptr <= fp8_ptr2; + fp8_ptr > fp8_ptr2; + fp8_ptr >= fp8_ptr2; + + /* Conditional expressions. */ + + 0 ? scalar0 : scalar0; + 0 ? scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + : is_a_float; + 0 ? is_a_float + : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + 0 ? scalar0 : 0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + 0 ? 0 : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + 0 ? 0.1 + : scalar0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + 0 ? scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + : 0.1; + 0 ? fp8_ptr : fp8_ptr2; + 0 ? fp8_ptr : uint8_ptr; /* { dg-error {conditional expression between distinct pointer types} } */ + 0 ? uint8_ptr : fp8_ptr; /* { dg-error {conditional expression between distinct pointer types} } */ + + scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + ? scalar0 + : scalar0; + scalar0 /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + ? is_a_float + : scalar0; + scalar0 ? scalar0 : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 ? is_a_float : is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + + /* Unary operators. */ + + +scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + -scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + ~scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + !scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + *scalar0; /* { dg-error {invalid type argument of unary} } */ + __real scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + __imag scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + ++scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + --scalar0; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + scalar0++; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + scalar0--; /* { dg-error {operation not permitted on type 'mfloat8_t'} } */ + + /* Binary arithmetic operations. */ + + scalar0 = glob_fp8 + scalar1_2; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 = glob_fp8 + *fp8_ptr; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 = glob_fp8 + + 0.1; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 = glob_fp8 + + 0; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + scalar0 = glob_fp8 + is_a_float; /* { dg-error {invalid conversion from type 'mfloat8_t'} } */ + + return scalar0; +}