]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
x86: Enable __bf16 type for TARGET_SSE2 and above
authorkonglin1 <lingling.kong@intel.com>
Mon, 15 Aug 2022 06:39:22 +0000 (14:39 +0800)
committerkonglin1 <lingling.kong@intel.com>
Mon, 15 Aug 2022 06:39:29 +0000 (14:39 +0800)
gcc/ChangeLog:

* config/i386/i386-builtin-types.def (BFLOAT16): New primitive type.
* config/i386/i386-builtins.cc : Support __bf16 type for i386 backend.
(ix86_register_bf16_builtin_type): New function.
(ix86_bf16_type_node): New.
(ix86_bf16_ptr_type_node): Ditto.
(ix86_init_builtin_types): Add ix86_register_bf16_builtin_type function call.
* config/i386/i386-modes.def (FLOAT_MODE): Add BFmode.
(ADJUST_FLOAT_FORMAT): Ditto.
* config/i386/i386.cc (classify_argument): Handle BFmode.
(construct_container): Ditto.
(function_value_32): Return __bf16 by %xmm0.
(function_value_64): Return __bf16 by SSE register.
(ix86_output_ssemov): Handle BFmode.
(ix86_legitimate_constant_p): Disable BFmode constant double.
(ix86_secondary_reload): Require gpr as intermediate register
to store __bf16 from sse register when sse4 is not available.
(ix86_scalar_mode_supported_p): Enable __bf16 under sse2.
(ix86_mangle_type): Add manlging for __bf16 type.
(ix86_invalid_conversion): New function for target hook.
(ix86_invalid_unary_op): Ditto.
(ix86_invalid_binary_op): Ditto.
(TARGET_INVALID_CONVERSION): New define for target hook.
(TARGET_INVALID_UNARY_OP): Ditto.
(TARGET_INVALID_BINARY_OP): Ditto.
* config/i386/i386.h (host_detect_local_cpu): Add BFmode.
* config/i386/i386.md ("mode"): Add BFmode.
(MODE_SIZE): Ditto.
(X87MODEFH): Ditto.
(HFBF): Add new define_mode_iterator.
(*pushhf_rex64): Change for BFmode.
(*push<mode>_rex64): Ditto.
(*pushhf): Ditto.
(*push<mode>): Ditto.
(MODESH): Ditto.
(hfbfconstf): Add new define_mode_attr.
(*mov<mode>_internal): Add BFmode.

gcc/testsuite/ChangeLog:

* g++.target/i386/bfloat_cpp_typecheck.C: New test.
* gcc.target/i386/bfloat16-1.c: Ditto.
* gcc.target/i386/sse2-bfloat16-1.c: Ditto.
* gcc.target/i386/sse2-bfloat16-2.c: Ditto.
* gcc.target/i386/sse2-bfloat16-scalar-typecheck.c: Ditto.

gcc/config/i386/i386-builtin-types.def
gcc/config/i386/i386-builtins.cc
gcc/config/i386/i386-modes.def
gcc/config/i386/i386.cc
gcc/config/i386/i386.h
gcc/config/i386/i386.md
gcc/testsuite/g++.target/i386/bfloat_cpp_typecheck.C [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/bfloat16-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/sse2-bfloat16-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/sse2-bfloat16-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/sse2-bfloat16-scalar-typecheck.c [new file with mode: 0644]

index 7a2da1db0b0e310faf69804d836b5dcb300aa6ca..63a360b0f8b99a3b35932692fb7b2a90410e74a7 100644 (file)
@@ -69,6 +69,7 @@ DEF_PRIMITIVE_TYPE (UINT16, short_unsigned_type_node)
 DEF_PRIMITIVE_TYPE (INT64, long_long_integer_type_node)
 DEF_PRIMITIVE_TYPE (UINT64, long_long_unsigned_type_node)
 DEF_PRIMITIVE_TYPE (FLOAT16, ix86_float16_type_node)
+DEF_PRIMITIVE_TYPE (BFLOAT16, ix86_bf16_type_node)
 DEF_PRIMITIVE_TYPE (FLOAT, float_type_node)
 DEF_PRIMITIVE_TYPE (DOUBLE, double_type_node)
 DEF_PRIMITIVE_TYPE (FLOAT80, float80_type_node)
index fe7243c3837514156b6dcc8016e60d2cd54ae77e..6a04fb57e65cab0f88add219187bbac4732c58e9 100644 (file)
@@ -126,6 +126,9 @@ BDESC_VERIFYS (IX86_BUILTIN_MAX,
 static GTY(()) tree ix86_builtin_type_tab[(int) IX86_BT_LAST_CPTR + 1];
 
 tree ix86_float16_type_node = NULL_TREE;
+tree ix86_bf16_type_node = NULL_TREE;
+tree ix86_bf16_ptr_type_node = NULL_TREE;
+
 /* Retrieve an element from the above table, building some of
    the types lazily.  */
 
@@ -1366,6 +1369,22 @@ ix86_register_float16_builtin_type (void)
                                            "_Float16");
 }
 
+static void
+ix86_register_bf16_builtin_type (void)
+{
+  ix86_bf16_type_node = make_node (REAL_TYPE);
+  TYPE_PRECISION (ix86_bf16_type_node) = 16;
+  SET_TYPE_MODE (ix86_bf16_type_node, BFmode);
+  layout_type (ix86_bf16_type_node);
+
+  if (!maybe_get_identifier ("__bf16") && TARGET_SSE2)
+    {
+      lang_hooks.types.register_builtin_type (ix86_bf16_type_node,
+                                           "__bf16");
+      ix86_bf16_ptr_type_node = build_pointer_type (ix86_bf16_type_node);
+    }
+}
+
 static void
 ix86_init_builtin_types (void)
 {
@@ -1396,6 +1415,8 @@ ix86_init_builtin_types (void)
 
   ix86_register_float16_builtin_type ();
 
+  ix86_register_bf16_builtin_type ();
+
   const_string_type_node
     = build_pointer_type (build_qualified_type
                          (char_type_node, TYPE_QUAL_CONST));
index e2e1e18d24d4209b10fc1019d31b45f7eaaa4f93..b49daaef253941aea920c70882dc69c217a6419c 100644 (file)
@@ -24,6 +24,8 @@ along with GCC; see the file COPYING3.  If not see
 FRACTIONAL_FLOAT_MODE (XF, 80, 12, ieee_extended_intel_96_format);
 FLOAT_MODE (TF, 16, ieee_quad_format);
 FLOAT_MODE (HF, 2, ieee_half_format);
+FLOAT_MODE (BF, 2, 0);
+ADJUST_FLOAT_FORMAT (BF, &arm_bfloat_half_format);
 
 /* In ILP32 mode, XFmode has size 12 and alignment 4.
    In LP64 mode, XFmode has size and alignment 16.  */
index 5be76e1dd6ffb8288b31a15635b05e85cce245e1..fa3722a11e1e65e0d17d542db9f8e0d9159f7cbb 100644 (file)
@@ -2399,6 +2399,7 @@ classify_argument (machine_mode mode, const_tree type,
     case E_CTImode:
       return 0;
     case E_HFmode:
+    case E_BFmode:
       if (!(bit_offset % 64))
        classes[0] = X86_64_SSEHF_CLASS;
       else
@@ -2792,9 +2793,10 @@ construct_container (machine_mode mode, machine_mode orig_mode,
            intreg++;
            break;
          case X86_64_SSEHF_CLASS:
+           tmpmode = (mode == BFmode ? BFmode : HFmode);
            exp [nexps++]
              = gen_rtx_EXPR_LIST (VOIDmode,
-                                  gen_rtx_REG (HFmode,
+                                  gen_rtx_REG (tmpmode,
                                                GET_SSE_REGNO (sse_regno)),
                                   GEN_INT (i*8));
            sse_regno++;
@@ -4001,8 +4003,8 @@ function_value_32 (machine_mode orig_mode, machine_mode mode,
     /* Most things go in %eax.  */
     regno = AX_REG;
 
-  /* Return _Float16/_Complex _Foat16 by sse register.  */
-  if (mode == HFmode)
+  /* Return __bf16/ _Float16/_Complex _Foat16 by sse register.  */
+  if (mode == HFmode || mode == BFmode)
     regno = FIRST_SSE_REG;
   if (mode == HCmode)
     {
@@ -4050,6 +4052,7 @@ function_value_64 (machine_mode orig_mode, machine_mode mode,
 
       switch (mode)
        {
+       case E_BFmode:
        case E_HFmode:
        case E_HCmode:
        case E_SFmode:
@@ -5631,6 +5634,7 @@ ix86_output_ssemov (rtx_insn *insn, rtx *operands)
        return "%vmovss\t{%1, %0|%0, %1}";
 
     case MODE_HF:
+    case MODE_BF:
       if (REG_P (operands[0]) && REG_P (operands[1]))
        return "vmovsh\t{%d1, %0|%0, %d1}";
       else
@@ -10648,6 +10652,11 @@ ix86_legitimate_constant_p (machine_mode mode, rtx x)
     case CONST_VECTOR:
       if (!standard_sse_constant_p (x, mode))
        return false;
+      break;
+
+    case CONST_DOUBLE:
+      if (mode == E_BFmode)
+       return false;
 
     default:
       break;
@@ -19415,7 +19424,8 @@ ix86_secondary_reload (bool in_p, rtx x, reg_class_t rclass,
     }
 
   /* Require movement to gpr, and then store to memory.  */
-  if ((mode == HFmode || mode == HImode || mode == V2QImode)
+  if ((mode == HFmode || mode == HImode || mode == V2QImode
+       || mode == BFmode)
       && !TARGET_SSE4_1
       && SSE_CLASS_P (rclass)
       && !in_p && MEM_P (x))
@@ -22358,7 +22368,7 @@ ix86_scalar_mode_supported_p (scalar_mode mode)
     return default_decimal_float_supported_p ();
   else if (mode == TFmode)
     return true;
-  else if (mode == HFmode && TARGET_SSE2)
+  else if ((mode == HFmode || mode == BFmode) && TARGET_SSE2)
     return true;
   else
     return default_scalar_mode_supported_p (mode);
@@ -22673,6 +22683,8 @@ ix86_mangle_type (const_tree type)
 
   switch (TYPE_MODE (type))
     {
+    case E_BFmode:
+      return "u6__bf16";
     case E_HFmode:
       /* _Float16 is "DF16_".
         Align with clang's decision in https://reviews.llvm.org/D33719. */
@@ -22688,6 +22700,55 @@ ix86_mangle_type (const_tree type)
     }
 }
 
+/* Return the diagnostic message string if conversion from FROMTYPE to
+   TOTYPE is not allowed, NULL otherwise.  */
+
+static const char *
+ix86_invalid_conversion (const_tree fromtype, const_tree totype)
+{
+  if (element_mode (fromtype) != element_mode (totype))
+    {
+      /* Do no allow conversions to/from BFmode scalar types.  */
+      if (TYPE_MODE (fromtype) == BFmode)
+       return N_("invalid conversion from type %<__bf16%>");
+      if (TYPE_MODE (totype) == BFmode)
+       return N_("invalid conversion to type %<__bf16%>");
+    }
+
+  /* Conversion allowed.  */
+  return NULL;
+}
+
+/* Return the diagnostic message string if the unary operation OP is
+   not permitted on TYPE, NULL otherwise.  */
+
+static const char *
+ix86_invalid_unary_op (int op, const_tree type)
+{
+  /* Reject all single-operand operations on BFmode except for &.  */
+  if (element_mode (type) == BFmode && op != ADDR_EXPR)
+    return N_("operation not permitted on type %<__bf16%>");
+
+  /* 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 *
+ix86_invalid_binary_op (int op ATTRIBUTE_UNUSED, const_tree type1,
+                          const_tree type2)
+{
+  /* Reject all 2-operand operations on BFmode.  */
+  if (element_mode (type1) == BFmode
+      || element_mode (type2) == BFmode)
+    return N_("operation not permitted on type %<__bf16%>");
+
+  /* Operation allowed.  */
+  return NULL;
+}
+
 static GTY(()) tree ix86_tls_stack_chk_guard_decl;
 
 static tree
@@ -24745,6 +24806,15 @@ ix86_libgcc_floating_mode_supported_p
 #undef TARGET_MANGLE_TYPE
 #define TARGET_MANGLE_TYPE ix86_mangle_type
 
+#undef TARGET_INVALID_CONVERSION
+#define TARGET_INVALID_CONVERSION ix86_invalid_conversion
+
+#undef TARGET_INVALID_UNARY_OP
+#define TARGET_INVALID_UNARY_OP ix86_invalid_unary_op
+
+#undef TARGET_INVALID_BINARY_OP
+#define TARGET_INVALID_BINARY_OP ix86_invalid_binary_op
+
 #undef TARGET_STACK_PROTECT_GUARD
 #define TARGET_STACK_PROTECT_GUARD ix86_stack_protect_guard
 
index f16df633e84b33ee12f75d1704cd7368be0158a4..0da3dce1d31c5e063e218fa71f7ad8228a3671f2 100644 (file)
@@ -1046,7 +1046,7 @@ extern const char *host_detect_local_cpu (int argc, const char **argv);
    || (MODE) == V8HFmode || (MODE) == V4HFmode || (MODE) == V2HFmode   \
    || (MODE) == V4QImode || (MODE) == V2HImode || (MODE) == V1SImode   \
    || (MODE) == V2DImode || (MODE) == V2QImode || (MODE) == DFmode     \
-   || (MODE) == HFmode)
+   || (MODE) == HFmode || (MODE) == BFmode)
 
 #define VALID_SSE_REG_MODE(MODE)                                       \
   ((MODE) == V1TImode || (MODE) == TImode                              \
@@ -1077,7 +1077,7 @@ extern const char *host_detect_local_cpu (int argc, const char **argv);
    || (MODE) == CQImode || (MODE) == CHImode                           \
    || (MODE) == CSImode || (MODE) == CDImode                           \
    || (MODE) == SDmode || (MODE) == DDmode                             \
-   || (MODE) == HFmode || (MODE) == HCmode                             \
+   || (MODE) == HFmode || (MODE) == HCmode || (MODE) == BFmode         \
    || (MODE) == V2HImode || (MODE) == V2HFmode                         \
    || (MODE) == V1SImode || (MODE) == V4QImode || (MODE) == V2QImode   \
    || (TARGET_64BIT                                                    \
index 2fde8cdf48b3b7afc1967ac111b7ab820be22408..5f7e2457f5c7b52796aae652b2ba3e507b175ef2 100644 (file)
 
 ;; Main data type used by the insn
 (define_attr "mode"
-  "unknown,none,QI,HI,SI,DI,TI,OI,XI,HF,SF,DF,XF,TF,V32HF,V16HF,V8HF,
+  "unknown,none,QI,HI,SI,DI,TI,OI,XI,HF,BF,SF,DF,XF,TF,V32HF,V16HF,V8HF,
    V16SF,V8SF,V4DF,V4SF,V2DF,V2SF,V1DF,V8DF,V4HF,V2HF"
   (const_string "unknown"))
 
 ;; GET_MODE_SIZE (<MODE>mode).  For XFmode which depends on
 ;; command line options just use GET_MODE_SIZE macro.
 (define_mode_attr MODE_SIZE [(QI "1") (HI "2") (SI "4") (DI "8")
-                            (TI "16") (HF "2") (SF "4") (DF "8")
+                            (TI "16") (HF "2") (BF "2") (SF "4") (DF "8")
                             (XF "GET_MODE_SIZE (XFmode)")
                             (V16QI "16") (V32QI "32") (V64QI "64")
                             (V8HI "16") (V16HI "32") (V32HI "64")
 (define_mode_iterator X87MODEF [SF DF XF])
 
 ;; All x87 floating point modes plus HFmode
-(define_mode_iterator X87MODEFH [HF SF DF XF])
+(define_mode_iterator X87MODEFH [HF SF DF XF BF])
 
 ;; All SSE floating point modes
 (define_mode_iterator SSEMODEF [HF SF DF TF])
   operands[0] = replace_equiv_address (operands[0], stack_pointer_rtx);
 })
 
-(define_insn "*pushhf_rex64"
-  [(set (match_operand:HF 0 "push_operand" "=X,X")
-       (match_operand:HF 1 "nonmemory_no_elim_operand" "r,x"))]
+(define_mode_iterator HFBF [HF BF])
+
+(define_insn "*push<mode>_rex64"
+  [(set (match_operand:HFBF 0 "push_operand" "=X,X")
+       (match_operand:HFBF 1 "nonmemory_no_elim_operand" "r,x"))]
   "TARGET_64BIT"
 {
   /* Anything else should be already split before reg-stack.  */
    (set_attr "type" "push,multi")
    (set_attr "mode" "DI,TI")])
 
-(define_insn "*pushhf"
-  [(set (match_operand:HF 0 "push_operand" "=X,X")
-       (match_operand:HF 1 "general_no_elim_operand" "rmF,x"))]
+(define_insn "*push<mode>"
+  [(set (match_operand:HFBF 0 "push_operand" "=X,X")
+       (match_operand:HFBF 1 "general_no_elim_operand" "rmF,x"))]
   "!TARGET_64BIT"
 {
   /* Anything else should be already split before reg-stack.  */
    (set_attr "unit" "i387,*,*")
    (set_attr "mode" "SF,SI,SF")])
 
-(define_mode_iterator MODESH [SF HF])
+(define_mode_iterator MODESH [SF HF BF])
 ;; %%% Kill this when call knows how to work this out.
 (define_split
   [(set (match_operand:MODESH 0 "push_operand")
           ]
           (const_string "*")))])
 
-(define_insn "*movhf_internal"
- [(set (match_operand:HF 0 "nonimmediate_operand"
+(define_mode_attr hfbfconstf
+ [(HF "F") (BF "")])
+
+(define_insn "*mov<mode>_internal"
+ [(set (match_operand:HFBF 0 "nonimmediate_operand"
         "=?r,?r,?r,?m,v,v,?r,m,?v,v")
-       (match_operand:HF 1 "general_operand"
-        "r  ,F ,m ,rF,C,v, v,v,r ,m"))]
+       (match_operand:HFBF 1 "general_operand"
+        "r  ,F ,m ,r<hfbfconstf>,C,v, v,v,r ,m"))]
  "!(MEM_P (operands[0]) && MEM_P (operands[1]))
   && (lra_in_progress
       || reload_completed
       || !CONST_DOUBLE_P (operands[1])
       || (TARGET_SSE2
-         && standard_sse_constant_p (operands[1], HFmode) == 1)
-      || memory_operand (operands[0], HFmode))"
+         && standard_sse_constant_p (operands[1], <MODE>mode) == 1)
+      || memory_operand (operands[0], <MODE>mode))"
 {
   switch (get_attr_type (insn))
     {
                         (not (match_test "TARGET_HIMODE_MATH"))))
                 (const_string "SI")
              ]
-             (const_string "HI")))])
+             (const_string "HI")))
+   (set (attr "enabled")
+       (cond [(and (match_test "<MODE>mode == BFmode")
+                   (eq_attr "alternative" "1"))
+               (symbol_ref "false")
+             ]
+             (const_string "*")))])
 
 (define_split
   [(set (match_operand 0 "any_fp_register_operand")
diff --git a/gcc/testsuite/g++.target/i386/bfloat_cpp_typecheck.C b/gcc/testsuite/g++.target/i386/bfloat_cpp_typecheck.C
new file mode 100644 (file)
index 0000000..5152336
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-msse2 -O3 --save-temps" } */
+
+void foo (void)
+{
+  __bf16 (); /* { dg-bogus {invalid conversion to type '__bf16'} "" { xfail *-*-* } } */
+  __bf16 a = __bf16(); /* { dg-bogus {invalid conversion to type '__bf16'} "" { xfail *-*-* } } */
+  __bf16 (0x1234); /* { dg-error {invalid conversion to type '__bf16'} } */
+  __bf16 (0.1); /* { dg-error {invalid conversion to type '__bf16'} } */
+}
diff --git a/gcc/testsuite/gcc.target/i386/bfloat16-1.c b/gcc/testsuite/gcc.target/i386/bfloat16-1.c
new file mode 100644 (file)
index 0000000..6aaec28
--- /dev/null
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-msse2 -O2" } */
+__bf16
+foo (int a)
+{
+  union {
+    int a;
+    __bf16 b;
+  }c;
+  c.a = a;
+  return c.b;
+}
diff --git a/gcc/testsuite/gcc.target/i386/sse2-bfloat16-1.c b/gcc/testsuite/gcc.target/i386/sse2-bfloat16-1.c
new file mode 100644 (file)
index 0000000..612d55b
--- /dev/null
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mno-sse2" } */
+
+__bf16/* { dg-error "unknown type name '__bf16'" } */
+foo (__bf16 x) /* { dg-error "unknown type name '__bf16'" } */
+{
+  return x;
+}
diff --git a/gcc/testsuite/gcc.target/i386/sse2-bfloat16-2.c b/gcc/testsuite/gcc.target/i386/sse2-bfloat16-2.c
new file mode 100644 (file)
index 0000000..a3286e2
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -msse2 -mno-avx512f" } */
+
+union flt
+{
+  __bf16 flt;
+  short s;
+};
+
+__bf16
+foo (union flt x)
+{
+  return x.flt;
+}
+
+/* { dg-final { scan-assembler {(?n)pinsrw[\t ].*%xmm0} { target ia32 } } } */
+/* { dg-final { scan-assembler {(?n)movd[\t ].*%xmm0} { target { ! ia32 } } } } */
diff --git a/gcc/testsuite/gcc.target/i386/sse2-bfloat16-scalar-typecheck.c b/gcc/testsuite/gcc.target/i386/sse2-bfloat16-scalar-typecheck.c
new file mode 100644 (file)
index 0000000..f76d554
--- /dev/null
@@ -0,0 +1,215 @@
+/* { dg-do compile } */
+/* { dg-options "-msse2 -O2" } */
+
+
+__bf16 glob_bfloat;
+
+int is_an_int;
+short is_a_short_int;
+float is_a_float;
+float is_a_float16;
+double is_a_double;
+
+float *float_ptr;
+
+__bf16 foo1 (void) { return (__bf16) 0x1234; } /* { dg-error {invalid conversion to type '__bf16'} } */
+__bf16 foo2 (void) { return (__bf16) (short) 0x1234; } /* { dg-error {invalid conversion to type '__bf16'} } */
+
+__bf16 footest (__bf16 scalar0)
+{
+
+  /* Initialisation  */
+
+  __bf16 scalar1_1;
+  __bf16 scalar1_2 = glob_bfloat;
+  __bf16 scalar1_3 = 0;   /* { dg-error {invalid conversion to type '__bf16'} } */
+  __bf16 scalar1_4 = 0.1; /* { dg-error {invalid conversion to type '__bf16'} } */
+  __bf16 scalar1_5 = is_a_float; /* { dg-error {invalid conversion to type '__bf16'} } */
+  __bf16 scalar1_6 = is_an_int;  /* { dg-error {invalid conversion to type '__bf16'} } */
+  __bf16 scalar1_7 = is_a_float16; /* { dg-error {invalid conversion to type '__bf16'} } */
+  __bf16 scalar1_8 = is_a_double; /* { dg-error {invalid conversion to type '__bf16'} } */
+  __bf16 scalar1_9 = is_a_short_int; /* { dg-error {invalid conversion to type '__bf16'} } */
+
+  int initi_1_1 = glob_bfloat; /* { dg-error {invalid conversion from type '__bf16'} } */
+  float initi_1_2 = glob_bfloat; /* { dg-error {invalid conversion from type '__bf16'} } */
+  _Float16 initi_1_3 = glob_bfloat; /* { dg-error {invalid conversion from type '__bf16'} } */
+  short initi_1_4 = glob_bfloat; /* { dg-error {invalid conversion from type '__bf16'} } */
+  double initi_1_5 = glob_bfloat; /* { dg-error {invalid conversion from type '__bf16'} } */
+
+  __bf16 scalar2_1 = {}; /* { dg-error {empty scalar initializer} } */
+  __bf16 scalar2_2 = { glob_bfloat };
+  __bf16 scalar2_3 = { 0 }; /* { dg-error {invalid conversion to type '__bf16'} } */
+  __bf16 scalar2_4 = { 0.1 }; /* { dg-error {invalid conversion to type '__bf16'} } */
+  __bf16 scalar2_5 = { is_a_float }; /* { dg-error {invalid conversion to type '__bf16'} } */
+  __bf16 scalar2_6 = { is_an_int }; /* { dg-error {invalid conversion to type '__bf16'} } */
+  __bf16 scalar2_7 = { is_a_float16 }; /* { dg-error {invalid conversion to type '__bf16'} } */
+  __bf16 scalar2_8 = { is_a_double }; /* { dg-error {invalid conversion to type '__bf16'} } */
+  __bf16 scalar2_9 = { is_a_short_int }; /* { dg-error {invalid conversion to type '__bf16'} } */
+
+  int initi_2_1 = { glob_bfloat }; /* { dg-error {invalid conversion from type '__bf16'} } */
+  float initi_2_2 = { glob_bfloat }; /* { dg-error {invalid conversion from type '__bf16'} } */
+  _Float16 initi_2_3 = { glob_bfloat }; /* { dg-error {invalid conversion from type '__bf16'} } */
+  short initi_2_4 = { glob_bfloat }; /* { dg-error {invalid conversion from type '__bf16'} } */
+  double initi_2_5 = { glob_bfloat }; /* { dg-error {invalid conversion from type '__bf16'} } */
+
+  /* Assignments.  */
+
+  glob_bfloat = glob_bfloat;
+  glob_bfloat = 0;   /* { dg-error {invalid conversion to type '__bf16'} } */
+  glob_bfloat = 0.1; /* { dg-error {invalid conversion to type '__bf16'} } */
+  glob_bfloat = is_a_float; /* { dg-error {invalid conversion to type '__bf16'} } */
+  glob_bfloat = is_an_int; /* { dg-error {invalid conversion to type '__bf16'} } */
+  glob_bfloat = is_a_float16; /* { dg-error {invalid conversion to type '__bf16'} } */
+  glob_bfloat = is_a_double; /* { dg-error {invalid conversion to type '__bf16'} } */
+  glob_bfloat = is_a_short_int; /* { dg-error {invalid conversion to type '__bf16'} } */
+
+  is_an_int = glob_bfloat; /* { dg-error {invalid conversion from type '__bf16'} } */
+  is_a_float = glob_bfloat; /* { dg-error {invalid conversion from type '__bf16'} } */
+  is_a_float16 = glob_bfloat; /* { dg-error {invalid conversion from type '__bf16'} } */
+  is_a_double = glob_bfloat; /* { dg-error {invalid conversion from type '__bf16'} } */
+  is_a_short_int = glob_bfloat; /* { dg-error {invalid conversion from type '__bf16'} } */
+
+  /* Casting.  */
+
+  (void) glob_bfloat;
+  (__bf16) glob_bfloat;
+
+  (int) glob_bfloat; /* { dg-error {invalid conversion from type '__bf16'} } */
+  (float) glob_bfloat; /* { dg-error {invalid conversion from type '__bf16'} } */
+  (_Float16) glob_bfloat; /* { dg-error {invalid conversion from type '__bf16'} } */
+  (double) glob_bfloat; /* { dg-error {invalid conversion from type '__bf16'} } */
+  (short) glob_bfloat; /* { dg-error {invalid conversion from type '__bf16'} } */
+
+  (__bf16) is_an_int; /* { dg-error {invalid conversion to type '__bf16'} } */
+  (__bf16) is_a_float; /* { dg-error {invalid conversion to type '__bf16'} } */
+  (__bf16) is_a_float16; /* { dg-error {invalid conversion to type '__bf16'} } */
+  (__bf16) is_a_double; /* { dg-error {invalid conversion to type '__bf16'} } */
+  (__bf16) is_a_short_int; /* { dg-error {invalid conversion to type '__bf16'} } */
+
+  /* Compound literals.  */
+
+  (__bf16) {}; /* { dg-error {empty scalar initializer} } */
+  (__bf16) { glob_bfloat };
+  (__bf16) { 0 }; /* { dg-error {invalid conversion to type '__bf16'} } */
+  (__bf16) { 0.1 }; /* { dg-error {invalid conversion to type '__bf16'} } */
+  (__bf16) { is_a_float }; /* { dg-error {invalid conversion to type '__bf16'} } */
+  (__bf16) { is_an_int }; /* { dg-error {invalid conversion to type '__bf16'} } */
+  (__bf16) { is_a_float16 }; /* { dg-error {invalid conversion to type '__bf16'} } */
+  (__bf16) { is_a_double }; /* { dg-error {invalid conversion to type '__bf16'} } */
+  (__bf16) { is_a_short_int }; /* { dg-error {invalid conversion to type '__bf16'} } */
+
+  (int) { glob_bfloat }; /* { dg-error {invalid conversion from type '__bf16'} } */
+  (float) { glob_bfloat }; /* { dg-error {invalid conversion from type '__bf16'} } */
+  (_Float16) { glob_bfloat }; /* { dg-error {invalid conversion from type '__bf16'} } */
+  (double) { glob_bfloat }; /* { dg-error {invalid conversion from type '__bf16'} } */
+  (short) { glob_bfloat }; /* { dg-error {invalid conversion from type '__bf16'} } */
+
+  /* Arrays and Structs.  */
+
+  typedef __bf16 array_type[2];
+  extern __bf16 extern_array[];
+
+  __bf16 array[2];
+  __bf16 zero_length_array[0];
+  __bf16 empty_init_array[] = {};
+  typedef __bf16 some_other_type[is_an_int];
+
+  struct struct1 {
+    __bf16 a;
+  };
+
+  union union1 {
+    __bf16 a;
+  };
+
+  /* Addressing and dereferencing.  */
+
+  __bf16 *bfloat_ptr = &scalar0;
+  scalar0 = *bfloat_ptr;
+
+  /* Pointer assignment.  */
+
+  __bf16 *bfloat_ptr2 = bfloat_ptr;
+  __bf16 *bfloat_ptr3 = array;
+
+  /* Pointer arithmetic.  */
+
+  ++bfloat_ptr;
+  --bfloat_ptr;
+  bfloat_ptr++;
+  bfloat_ptr--;
+  bfloat_ptr += 1;
+  bfloat_ptr -= 1;
+  bfloat_ptr - bfloat_ptr2;
+  bfloat_ptr = &bfloat_ptr3[0];
+  bfloat_ptr = &bfloat_ptr3[1];
+
+  /* Simple comparison.  */
+  scalar0 > glob_bfloat; /* { dg-error {operation not permitted on type '__bf16'} } */
+  glob_bfloat == scalar0; /* { dg-error {operation not permitted on type '__bf16'} } */
+  scalar0 > is_a_float; /* { dg-error {operation not permitted on type '__bf16'} } */
+  is_a_float == scalar0; /* { dg-error {operation not permitted on type '__bf16'} } */
+  scalar0 > 0; /* { dg-error {operation not permitted on type '__bf16'} } */
+  0 == scalar0; /* { dg-error {operation not permitted on type '__bf16'} } */
+  scalar0 > 0.1; /* { dg-error {operation not permitted on type '__bf16'} } */
+  0.1 == scalar0; /* { dg-error {operation not permitted on type '__bf16'} } */
+  scalar0 > is_an_int; /* { dg-error {operation not permitted on type '__bf16'} } */
+  is_an_int == scalar0; /* { dg-error {operation not permitted on type '__bf16'} } */
+
+  /* Pointer comparison.  */
+
+  bfloat_ptr == &scalar0;
+  bfloat_ptr != &scalar0;
+  bfloat_ptr < &scalar0;
+  bfloat_ptr <= &scalar0;
+  bfloat_ptr > &scalar0;
+  bfloat_ptr >= &scalar0;
+  bfloat_ptr == bfloat_ptr2;
+  bfloat_ptr != bfloat_ptr2;
+  bfloat_ptr < bfloat_ptr2;
+  bfloat_ptr <= bfloat_ptr2;
+  bfloat_ptr > bfloat_ptr2;
+  bfloat_ptr >= bfloat_ptr2;
+
+  /* Conditional expressions.  */
+
+  0 ? scalar0 : scalar0;
+  0 ? scalar0 : is_a_float; /* { dg-error {invalid conversion from type '__bf16'} } */
+  0 ? is_a_float : scalar0; /* { dg-error {invalid conversion from type '__bf16'} } */
+  0 ? scalar0 : 0; /* { dg-error {invalid conversion to type '__bf16'} } */
+  0 ? 0 : scalar0; /* { dg-error {invalid conversion to type '__bf16'} } */
+  0 ? 0.1 : scalar0; /* { dg-error {invalid conversion from type '__bf16'} } */
+  0 ? scalar0 : 0.1; /* { dg-error {invalid conversion from type '__bf16'} } */
+  0 ? bfloat_ptr : bfloat_ptr2;
+  0 ? bfloat_ptr : float_ptr; /* { dg-warning {pointer type mismatch in conditional expression} } */
+  0 ? float_ptr : bfloat_ptr; /* { dg-warning {pointer type mismatch in conditional expression} } */
+
+  scalar0 ? scalar0 : scalar0; /* { dg-error {operation not permitted on type '__bf16'} } */
+  scalar0 ? is_a_float : scalar0; /* { dg-error {operation not permitted on type '__bf16'} } */
+  scalar0 ? scalar0 : is_a_float; /* { dg-error {operation not permitted on type '__bf16'} } */
+  scalar0 ? is_a_float : is_a_float; /* { dg-error {operation not permitted on type '__bf16'} } */
+
+  /* Unary operators.  */
+
+  +scalar0; /* { dg-error {operation not permitted on type '__bf16'} } */
+  -scalar0; /* { dg-error {operation not permitted on type '__bf16'} } */
+  ~scalar0; /* { dg-error {operation not permitted on type '__bf16'} } */
+  !scalar0; /* { dg-error {operation not permitted on type '__bf16'} } */
+  *scalar0; /* { dg-error {invalid type argument of unary '\*'} } */
+  __real scalar0; /* { dg-error {operation not permitted on type '__bf16'} } */
+  __imag scalar0; /* { dg-error {operation not permitted on type '__bf16'} } */
+  ++scalar0; /* { dg-error {operation not permitted on type '__bf16'} } */
+  --scalar0; /* { dg-error {operation not permitted on type '__bf16'} } */
+  scalar0++; /* { dg-error {operation not permitted on type '__bf16'} } */
+  scalar0--; /* { dg-error {operation not permitted on type '__bf16'} } */
+
+  /* Binary arithmetic operations.  */
+
+  scalar0 = glob_bfloat + *bfloat_ptr; /* { dg-error {operation not permitted on type '__bf16'} } */
+  scalar0 = glob_bfloat + 0.1; /* { dg-error {operation not permitted on type '__bf16'} } */
+  scalar0 = glob_bfloat + 0; /* { dg-error {operation not permitted on type '__bf16'} } */
+  scalar0 = glob_bfloat + is_a_float; /* { dg-error {operation not permitted on type '__bf16'} } */
+
+  return scalar0;
+}
+