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  <stam.markianos-wri...@arm.com>

        * 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  <stam.markianos-wri...@arm.com>

        * 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;
+}

Reply via email to