Hi all,
This patch is part 2 of Bfloat16_t enablement in the Aarch64 back-end.
This new type is constrained using target hooks TARGET_INVALID_CONVERSION,
TARGET_INVALID_UNARY_OP, TARGET_INVALID_BINARY_OP so that it may only be used
through ACLE intrinsics (will be provided in later patches).
Regression testing on aarch64-none-elf passed successfully.
Ok for trunk?
Cheers,
Stam
ACLE documents are at https://developer.arm.com/docs/101028/latest
ISA documents are at https://developer.arm.com/docs/ddi0596/latest
Details on ARM Bfloat can be found here:
https://community.arm.com/developer/ip-products/processors/b/ml-ip-blog/posts/bfloat16-processing-for-neural-networks-on-armv8_2d00_a
PS. I don't have commit rights, so if someone could commit on my behalf,
that would be great :)
gcc/ChangeLog:
2019-12-16 Stam Markianos-Wright <[email protected]>
* config/aarch64/aarch64.c
(aarch64_invalid_conversion): New function for target hook.
(aarch64_invalid_unary_op): Likewise.
(aarch64_invalid_binary_op): Likewise.
(TARGET_INVALID_CONVERSION): Add back-end define for target hook.
(TARGET_INVALID_UNARY_OP): Likewise.
(TARGET_INVALID_BINARY_OP): Likewise.
gcc/testsuite/ChangeLog:
2019-12-16 Stam Markianos-Wright <[email protected]>
* gcc.target/aarch64/bfloat16_scalar_typecheck.c: New test.
* gcc.target/aarch64/bfloat16_vector_typecheck1.c: New test.
* gcc.target/aarch64/bfloat16_vector_typecheck2.c: New test.
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index f57469b6e23..f40f6432fd4 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -21661,6 +21661,68 @@ aarch64_stack_protect_guard (void)
return NULL_TREE;
}
+/* Return the diagnostic message string if conversion from FROMTYPE to
+ TOTYPE is not allowed, NULL otherwise. */
+
+static const char *
+aarch64_invalid_conversion (const_tree fromtype, const_tree totype)
+{
+ static char templ[100];
+ if ((GET_MODE_INNER (TYPE_MODE (fromtype)) == BFmode
+ || GET_MODE_INNER (TYPE_MODE (totype)) == BFmode)
+ && TYPE_MODE (fromtype) != TYPE_MODE (totype))
+ {
+ snprintf (templ, sizeof (templ), \
+ "incompatible types when assigning to type '%s' from type '%s'",
+ IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (totype))),
+ IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (fromtype))));
+ return N_(templ);
+ }
+ /* Conversion allowed. */
+ return NULL;
+}
+
+/* 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)
+{
+ static char templ[100];
+ /* Reject all single-operand operations on BFmode except for &. */
+ if (GET_MODE_INNER (TYPE_MODE (type)) == BFmode && op != ADDR_EXPR)
+ {
+ snprintf (templ, sizeof (templ),
+ "operation not permitted on type '%s'",
+ IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))));
+ return N_(templ);
+ }
+ /* Operation allowed. */
+ return NULL;
+}
+
+/* Return the diagnostic message string if the binary operation OP is
+ not permitted on TYPE1 and TYPE2, NULL otherwise. */
+
+static const char *
+aarch64_invalid_binary_op (int op ATTRIBUTE_UNUSED, const_tree type1,
+ const_tree type2)
+{
+ static char templ[100];
+ /* Reject all 2-operand operations on BFmode. */
+ if (GET_MODE_INNER (TYPE_MODE (type1)) == BFmode
+ || GET_MODE_INNER (TYPE_MODE (type2)) == BFmode)
+ {
+ snprintf (templ, sizeof (templ), \
+ "operation not permitted on types '%s', '%s'",
+ IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type1))),
+ IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type2))));
+ return N_(templ);
+ }
+ /* Operation allowed. */
+ return NULL;
+}
+
/* Implement TARGET_ASM_FILE_END for AArch64. This adds the AArch64 GNU NOTE
section at the end if needed. */
#define GNU_PROPERTY_AARCH64_FEATURE_1_AND 0xc0000000
@@ -21911,6 +21973,15 @@ 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
+
#undef TARGET_VERIFY_TYPE_CONTEXT
#define TARGET_VERIFY_TYPE_CONTEXT aarch64_verify_type_context
diff --git a/gcc/testsuite/gcc.target/aarch64/bfloat16_scalar_typecheck.c b/gcc/testsuite/gcc.target/aarch64/bfloat16_scalar_typecheck.c
new file mode 100644
index 00000000000..6f6a6af9587
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/bfloat16_scalar_typecheck.c
@@ -0,0 +1,83 @@
+/* { dg-do compile { target { aarch64*-*-* } } } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=armv8.2-a+i8mm" } */
+
+#include <arm_neon.h>
+
+bfloat16_t glob;
+float is_a_float;
+int n;
+
+bfloat16_t footest (bfloat16_t scalar0)
+{
+
+ /* Initialisation */
+
+ bfloat16_t scalar1 = 0.1; /* { dg-error "incompatible types when assigning to type 'bfloat16_t' from type 'double'" "" {target *-*-*} } */
+ bfloat16_t scalar2 = 0; /* { dg-error "incompatible types when assigning to type 'bfloat16_t' from type 'int'" "" {target *-*-*} } */
+ bfloat16_t scalar3 = {}; /* { dg-error "empty scalar initializer" "" {target *-*-*} } */
+
+ float16_t initi_a = scalar1; /* { dg-error "incompatible types when assigning to type 'float16_t' from type 'bfloat16_t'" "" {target *-*-*} } */
+ float16_t initi_b = { scalar1 }; /* { dg-error "incompatible types when assigning to type 'float16_t' from type 'bfloat16_t'" "" {target *-*-*} } */
+
+ /* Compound literals. */
+
+ (bfloat16_t) {}; /* { dg-error "empty scalar initializer" "" {target *-*-*} } */
+ (bfloat16_t) { scalar1 };
+
+ (int) { scalar1 }; /* { dg-error "incompatible types when assigning to type 'int' from type 'bfloat16_t'" "" {target *-*-*} } */
+
+ /* Casting. */
+
+ (void) scalar1;
+ (bfloat16_t) scalar1;
+
+ /* Arrays and Structs. */
+
+ typedef bfloat16_t array_type[2];
+ extern bfloat16_t extern_array[];
+
+ bfloat16_t array[2];
+ bfloat16_t zero_length_array[0];
+ bfloat16_t empty_init_array[] = {};
+ typedef bfloat16_t vla_type[n];
+
+ struct struct1 {
+ bfloat16_t a;
+ };
+
+ union union1 {
+ bfloat16_t a;
+ };
+
+ /* Assignments. */
+
+ n = scalar1; /* { dg-error "incompatible types when assigning to type 'int' from type 'bfloat16_t'" "" {target *-*-*} } */
+ is_a_float = scalar1; /* { dg-error "incompatible types when assigning to type 'float' from type 'bfloat16_t'" "" {target *-*-*} } */
+ scalar1 = 0; /* { dg-error "incompatible types when assigning to type 'bfloat16_t' from type 'int'" "" {target *-*-*} } */
+ scalar1 = 0.1; /* { dg-error "incompatible types when assigning to type 'bfloat16_t' from type 'double'" "" {target *-*-*} } */
+ scalar1 = scalar2;
+
+ /* Addressing and dereferencing. */
+
+ bfloat16_t *bfloat_ptr = &scalar1;
+ scalar1 = *bfloat_ptr;
+
+ /* Pointer assignment. */
+
+ bfloat16_t *bfloat_ptr2 = bfloat_ptr;
+
+ /* Single-operand operation. */
+
+ scalar1 = !glob; /* { dg-error "operation not permitted on type 'bfloat16_t'" "" {target *-*-*} } */
+
+ /* Double-operand operations. */
+
+ scalar1 = glob + *bfloat_ptr; /* { dg-error "operation not permitted on types 'bfloat16_t', 'bfloat16_t'" "" {target *-*-*} } */
+ scalar1 = glob + 0.1; /* { dg-error "operation not permitted on types 'bfloat16_t', 'double'" "" {target *-*-*} } */
+ scalar1 = glob + 0; /* { dg-error "operation not permitted on types 'bfloat16_t', 'int'" "" {target *-*-*} } */
+ scalar1 = glob + is_a_float; /* { dg-error "operation not permitted on types 'bfloat16_t', 'float'" "" {target *-*-*} } */
+
+ return scalar0;
+}
+
diff --git a/gcc/testsuite/gcc.target/aarch64/bfloat16_vector_typecheck1.c b/gcc/testsuite/gcc.target/aarch64/bfloat16_vector_typecheck1.c
new file mode 100644
index 00000000000..06786d9daa9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/bfloat16_vector_typecheck1.c
@@ -0,0 +1,85 @@
+/* { dg-do compile { target { aarch64*-*-* } } } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=armv8.2-a+i8mm" } */
+
+#include <arm_neon.h>
+
+bfloat16x4_t glob;
+float is_a_float;
+float16x4_t is_a_floatx4;
+int16x4_t intvec;
+int n;
+short n2;
+bfloat16_t scalar0, scalar1, scalar2, scalar3;
+
+bfloat16x4_t footest (bfloat16x4_t vector0)
+{
+ /* Initialisation */
+
+ bfloat16x4_t vector1 = { 0.0, n, n2, is_a_float };
+ /* { dg-error "incompatible types when assigning to type '__bf16' from type 'double'" "" {target *-*-*} 19 } */
+ /* { dg-error "incompatible types when assigning to type '__bf16' from type 'int'" "" {target *-*-*} 19 } */
+ /* { dg-error "incompatible types when assigning to type '__bf16' from type 'short int'" "" {target *-*-*} 19 } */
+ /* { dg-error "incompatible types when assigning to type '__bf16' from type 'float'" "" {target *-*-*} 19 } */
+
+ bfloat16x4_t vector2 = {};
+
+ (bfloat16x4_t) {};
+
+ bfloat16x4_t vector4 = { scalar0, scalar1, scalar2, scalar3 };
+
+ float16x4_t initi_a = vector1; /* { dg-error "incompatible types when initializing type 'float16x4_t' using type 'bfloat16x4_t'" "" {target *-*-*} } */
+
+ /* Casting. */
+
+ (void) vector1;
+ (bfloat16x4_t) vector1;
+
+ /* Arrays and Structs. */
+
+ typedef bfloat16x4_t array_type[2];
+ extern bfloat16x4_t extern_array[];
+
+ bfloat16x4_t array[2];
+ bfloat16x4_t zero_length_array[0];
+ bfloat16x4_t empty_init_array[] = {};
+ typedef bfloat16x4_t some_other_type[n];
+
+ struct struct1 {
+ bfloat16x4_t a;
+ };
+
+ union union1 {
+ bfloat16x4_t a;
+ };
+
+ /* Assignments. */
+
+ intvec = vector1; /* { dg-error "incompatible types when assigning to type 'int16x4_t' from type 'bfloat16x4_t'" "" {target *-*-*} } */
+ is_a_floatx4 = vector1; /* { dg-error "incompatible types when assigning to type 'float16x4_t' from type 'bfloat16x4_t'" "" {target *-*-*} } */
+ vector1 = 0; /* { dg-error "incompatible types when assigning to type 'bfloat16x4_t' from type 'int'" "" {target *-*-*} } */
+ vector1 = 0.1; /* { dg-error "incompatible types when assigning to type 'bfloat16x4_t' from type 'double'" "" {target *-*-*} } */
+ vector1 = vector2;
+
+ /* Addressing and dereferencing. */
+
+ bfloat16x4_t *bfloat_ptr = &vector1;
+ vector1 = *bfloat_ptr;
+
+ /* Pointer assignment. */
+
+ bfloat16x4_t *bfloat_ptr2 = bfloat_ptr;
+
+ /* Single-operand operation. */
+
+ vector1 = !glob; /* { dg-error "operation not permitted on type 'bfloat16x4_t'" "" {target *-*-*} } */
+
+ /* Double-operand operations. */
+
+ vector1 = glob + *bfloat_ptr; /* { dg-error "operation not permitted on types 'bfloat16x4_t', 'bfloat16x4_t'" "" {target *-*-*} } */
+ vector1 = glob + 0.1; /* { dg-error "operation not permitted on types 'bfloat16x4_t', 'double'" "" {target *-*-*} } */
+ vector1 = glob + 0; /* { dg-error "operation not permitted on types 'bfloat16x4_t', 'int'" "" {target *-*-*} } */
+ vector1 = glob + is_a_floatx4; /* { dg-error "operation not permitted on types 'bfloat16x4_t', 'float16x4_t'" "" {target *-*-*} } */
+
+ return vector0;
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/bfloat16_vector_typecheck2.c b/gcc/testsuite/gcc.target/aarch64/bfloat16_vector_typecheck2.c
new file mode 100644
index 00000000000..3be3e0551b2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/bfloat16_vector_typecheck2.c
@@ -0,0 +1,95 @@
+/* { dg-do compile { target { aarch64*-*-* } } } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } } */
+/* { dg-options "-march=armv8.2-a+i8mm" } */
+
+#include <arm_neon.h>
+
+bfloat16_t scalar0, scalar1, scalar2, scalar3;
+bfloat16x8_t glob;
+
+float16_t is_a_half_float;
+float16x8_t is_a_floatx8;
+int16x8_t intvec;
+
+float is_a_float;
+int is_an_int;
+unsigned int is_a_uint;
+short is_a_short_int;
+long is_long;
+long double is_long_double;
+
+bfloat16x8_t footest (bfloat16x8_t vector0)
+{
+ /* Initialisation */
+
+ bfloat16x8_t vector1 = { 0.0, is_an_int, is_a_short_int, is_a_float, is_a_half_float, is_long, is_a_uint, is_long_double };
+ /* { dg-error "incompatible types when assigning to type '__bf16' from type 'double'" "" {target *-*-*} 25 } */
+ /* { dg-error "incompatible types when assigning to type '__bf16' from type 'int'" "" {target *-*-*} 25 } */
+ /* { dg-error "incompatible types when assigning to type '__bf16' from type 'short int'" "" {target *-*-*} 25 } */
+ /* { dg-error "incompatible types when assigning to type '__bf16' from type 'float'" "" {target *-*-*} 25 } */
+ /* { dg-error "incompatible types when assigning to type '__bf16' from type 'float16_t'" "" {target *-*-*} 25 } */
+ /* { dg-error "incompatible types when assigning to type '__bf16' from type 'long int'" "" {target *-*-*} 25 } */
+ /* { dg-error "incompatible types when assigning to type '__bf16' from type 'unsigned int'" "" {target *-*-*} 25 } */
+ /* { dg-error "incompatible types when assigning to type '__bf16' from type 'long double'" "" {target *-*-*} 25 } */
+
+ bfloat16x8_t vector2 = {};
+
+ (bfloat16x8_t) {};
+
+ bfloat16x8_t vector4 = { scalar0, scalar1, scalar2, scalar3, scalar0, scalar1, scalar2, scalar3 };
+
+ float16x8_t initi_a = vector1; /* { dg-error "incompatible types when initializing type 'float16x8_t' using type 'bfloat16x8_t'" "" {target *-*-*} } */
+
+ /* Casting. */
+
+ (void) vector1;
+ (bfloat16x8_t) vector1;
+
+ /* Arrays and Structs. */
+
+ typedef bfloat16x8_t array_type[2];
+ extern bfloat16x8_t extern_array[];
+
+ bfloat16x8_t array[2];
+ bfloat16x8_t zero_length_array[0];
+ bfloat16x8_t empty_init_array[] = {};
+ typedef bfloat16x8_t some_other_type[is_an_int];
+
+ struct struct1 {
+ bfloat16x8_t a;
+ };
+
+ union union1 {
+ bfloat16x8_t a;
+ };
+
+ /* Assignments. */
+
+ intvec = vector1; /* { dg-error "incompatible types when assigning to type 'int16x8_t' from type 'bfloat16x8_t'" "" {target *-*-*} } */
+ is_a_floatx8 = vector1; /* { dg-error "incompatible types when assigning to type 'float16x8_t' from type 'bfloat16x8_t'" "" {target *-*-*} } */
+ vector1 = 0; /* { dg-error "incompatible types when assigning to type 'bfloat16x8_t' from type 'int'" "" {target *-*-*} } */
+ vector1 = 0.1; /* { dg-error "incompatible types when assigning to type 'bfloat16x8_t' from type 'double'" "" {target *-*-*} } */
+ vector1 = vector2;
+
+ /* Addressing and dereferencing. */
+
+ bfloat16x8_t *bfloat_ptr = &vector1;
+ vector1 = *bfloat_ptr;
+
+ /* Pointer assignment. */
+
+ bfloat16x8_t *bfloat_ptr2 = bfloat_ptr;
+
+ /* Single-operand operation. */
+
+ vector1 = !glob; /* { dg-error "operation not permitted on type 'bfloat16x8_t'" "" {target *-*-*} } */
+
+ /* Double-operand operations. */
+
+ vector1 = glob + *bfloat_ptr; /* { dg-error "operation not permitted on types 'bfloat16x8_t', 'bfloat16x8_t'" "" {target *-*-*} } */
+ vector1 = glob + 0.1; /* { dg-error "operation not permitted on types 'bfloat16x8_t', 'double'" "" {target *-*-*} } */
+ vector1 = glob + 0; /* { dg-error "operation not permitted on types 'bfloat16x8_t', 'int'" "" {target *-*-*} } */
+ vector1 = glob + is_a_floatx8; /* { dg-error "operation not permitted on types 'bfloat16x8_t', 'float16x8_t'" "" {target *-*-*} } */
+
+ return vector0;
+}