https://gcc.gnu.org/g:d2b2c6fb4d7f96d8319492a512a69278bdbb9073

commit d2b2c6fb4d7f96d8319492a512a69278bdbb9073
Author: Michael Meissner <[email protected]>
Date:   Fri Oct 16 16:51:05 2026 -0400

    Work on using vector insns to do BFmode operations.
    
    2026-10-15  Michael Meissner  <[email protected]>
    
            * config/rs6000/float16.cc (toplevel): Include emit-rtl.h.
            (bfloat16_operation_as_v4sf_inner): Use vslw if we are loading the
            value.  Try to improve constant handling.
            * config/rs6000/float16.md (bf_shift_left): New insn.
            * config/rs6000/predicates.md (easy_vector_constant_add_self): 
Generate
            xxspltib on power9 rather than issuing 2 altivec instructions.
            (easy_vector_constant_msb): Likewise.
            (easy_vector_constant_vsldoi): Likewise.
            (bfloat16_v4sf_operand): Rework code.

Diff:
---
 gcc/config/rs6000/float16.cc    | 74 +++++++++++++++++++++++++++++------------
 gcc/config/rs6000/float16.md    | 18 ++++++++++
 gcc/config/rs6000/predicates.md | 41 ++++++++++++-----------
 3 files changed, 92 insertions(+), 41 deletions(-)

diff --git a/gcc/config/rs6000/float16.cc b/gcc/config/rs6000/float16.cc
index e5206b910694..5a7317525396 100644
--- a/gcc/config/rs6000/float16.cc
+++ b/gcc/config/rs6000/float16.cc
@@ -39,6 +39,7 @@
 #include "attribs.h"
 #include "explow.h"
 #include "expr.h"
+#include "emit-rtl.h"
 #include "common/common-target.h"
 #include "rs6000-internal.h"
 
@@ -264,43 +265,74 @@ bfloat16_operation_as_v4sf_inner (enum rtx_code icode,
          break;
        }
 
-      /* Convert operands to V4SFmode format.  We use SPLAT for registers to
-        get the value into the upper 32-bits.  We can use XXSPLTW to splat
-        words instead of VSPLTIH since the XVCVBF16SPN instruction ignores the
-        odd half-words, and XXSPLTW can operate on all VSX registers instead
-        of just the Altivec registers.  Using SPLAT instead of a shift also
-        insure that other bits are not a signalling NaN.  If we are using
-        XXSPLTIW or XXSPLTIB to load the constant the other bits are
-        duplicated.  */
+      /* Convert operands to V4SFmode format.
+
+        We use SPLAT for registers to get the value into the upper 32-bits.
+        We can use XXSPLTW to splat words instead of VSPLTIH since the
+        XVCVBF16SPN instruction ignores the odd half-words, and XXSPLTW can
+        operate on all VSX registers instead of just the Altivec registers.
+        Using SPLAT instead of a shift also insure that other bits are not a
+        signalling NaN.  If we are using XXSPLTIW or XXSPLTIB to load the
+        constant the other bits are duplicated.
+
+        However, if we are loading up the value from memory, we know the other
+        bits will all be 0, so we can do a vslw to get the 16-bit BFmode value
+        into the position that xvcvspbf16 will use to create the BFmode
+        value after the operation.  */
 
       rtx tmp = ops_v4sf[i] = gen_reg_rtx (V4SFmode);
       if (op == CONST0_RTX (SFmode) || op == CONST0_RTX (BFmode))
        emit_move_insn (tmp, CONST0_RTX (V4SFmode));
 
-      else if (GET_MODE (op) == BFmode)
+      else if (CONST_DOUBLE_P (op))
        {
-         emit_insn (gen_xxspltw_bf (tmp, force_reg (BFmode, op)));
-         emit_insn (gen_xvcvbf16spn_bf (tmp, tmp));
+         rtx sf_op;
+
+         if (GET_MODE (op) == SFmode)
+           sf_op = op;
+         else
+           {
+             const REAL_VALUE_TYPE *rtype = CONST_DOUBLE_REAL_VALUE (op);
+             sf_op = const_double_from_real_value (*rtype, SFmode);
+           }
+
+         rtvec v = gen_rtvec (4, sf_op, sf_op, sf_op, sf_op);
+         rtx cv = gen_rtx_CONST_VECTOR (V4SFmode, v);
+         rtx insn = emit_insn (gen_rtx_SET (tmp, cv));
+         set_unique_reg_note (insn, REG_EQUIV, cv);
        }
 
-      else if (GET_MODE (op) == SFmode)
+      else if (GET_MODE (op) == BFmode)
        {
-         if (GET_CODE (op) == CONST_DOUBLE)
+         rtx op_reg = force_reg (BFmode, op);
+
+         if (MEM_P (op))
            {
-             rtvec v = rtvec_alloc (4);
+             rtx s = GEN_INT (16);
+             rtvec shift_vec = gen_rtvec (16,
+                                          s, s, s, s, s, s, s, s,
+                                          s, s, s, s, s, s, s, s);
 
-             for (size_t i = 0; i < 4; i++)
-               RTVEC_ELT (v, i) = op;
+             rtx shift = gen_rtx_CONST_VECTOR (V16QImode, shift_vec);
+             rtx tmp2 = gen_reg_rtx (V16QImode);
 
-             emit_insn (gen_rtx_SET (tmp,
-                                     gen_rtx_CONST_VECTOR (V4SFmode, v)));
-           }
+             rtx insn = emit_insn (gen_rtx_SET (tmp2, shift));
+             set_unique_reg_note (insn, REG_EQUIV, shift);
 
+             emit_insn (gen_bf_shift_left (tmp, op_reg, tmp2));
+           }
          else
-           emit_insn (gen_vsx_splat_v4sf (tmp,
-                                          force_reg (SFmode, op)));
+           {
+             rtx tmp2 = gen_reg_rtx (V4SFmode);
+             emit_insn (gen_xxspltw_bf (tmp2, op_reg));
+             emit_insn (gen_xvcvbf16spn_bf (tmp, tmp2));
+           }
        }
 
+      else if (GET_MODE (op) == SFmode)
+       emit_insn (gen_vsx_splat_v4sf (tmp,
+                                      force_reg (SFmode, op)));
+
       else
        gcc_unreachable ();
     }
diff --git a/gcc/config/rs6000/float16.md b/gcc/config/rs6000/float16.md
index d3a31791f9bc..696e2e1bd18d 100644
--- a/gcc/config/rs6000/float16.md
+++ b/gcc/config/rs6000/float16.md
@@ -1242,6 +1242,24 @@
   "TARGET_BFLOAT16_HW"
   "xvcvbf16spn %x0,%x1"
   [(set_attr "type" "vecperm")])
+
+(define_insn_and_split "bf_shift_left"
+  [(set (match_operand:V4SF 0 "altivec_register_operand" "=v")
+       (unspec:V4SF [(match_operand:BF 1 "altivec_register_operand" "v")
+                     (match_operand:V16QI 2 "altivec_register_operand" "v")]
+                    UNSPEC_CVT_FP16_TO_V4SF))]
+  "TARGET_BFLOAT16_HW"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 3)
+       (ashift:V4SI (match_dup 4)
+                    (match_dup 5)))]
+{
+  operands[3] = gen_rtx_REG (V4SImode, reg_or_subregno (operands[0]));
+  operands[4] = gen_rtx_REG (V4SImode, reg_or_subregno (operands[1]));
+  operands[5] = gen_rtx_REG (V4SImode, reg_or_subregno (operands[2]));
+}
+  [(set_attr "type" "vecsimple")])
 
 ;; Optimize __bfloat16 binary operations.  Unlike _Float16 where we
 ;; have instructions to convert between HFmode and SFmode as scalar
diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index afe63447eb0d..873416f1f60f 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -820,6 +820,8 @@
   int elt;
   if (mode == V2DImode || mode == V2DFmode)
     return 0;
+  if (TARGET_P9_VECTOR && xxspltib_constant_nosplit (op, mode))
+    return false;
   elt = BYTES_BIG_ENDIAN ? GET_MODE_NUNITS (mode) - 1 : 0;
   val = const_vector_elt_as_int (op, elt);
   val = sext_hwi (val, 8);
@@ -839,6 +841,8 @@
   int isz = GET_MODE_SIZE (inner);
   if (mode == V2DImode || mode == V2DFmode)
     return 0;
+  if (TARGET_P9_VECTOR && xxspltib_constant_nosplit (op, mode))
+    return false;
   elt = BYTES_BIG_ENDIAN ? GET_MODE_NUNITS (mode) - 1 : 0;
   if (isz < sz)
     {
@@ -858,6 +862,7 @@
   (and (match_code "const_vector")
        (and (match_test "TARGET_ALTIVEC")
            (and (match_test "easy_altivec_constant (op, mode)")
+                (match_test "!xxspltib_constant_nosplit (op, mode)")
                 (match_test "vspltis_shifted (op) != 0")))))
 
 ;; Return true if this is a vector constant and each byte in
@@ -2320,6 +2325,9 @@
 (define_predicate "bfloat16_v4sf_operand"
   (match_code 
"reg,subreg,const_double,float_extend,float_truncate,plus,minus,mult")
 {
+  rtx arg;
+  machine_mode arg_mode;
+
   if (mode != BFmode && mode != SFmode)
     return false;
 
@@ -2336,32 +2344,25 @@
        return true;
 
       case FLOAT_EXTEND:
-       {
-         if (mode != SFmode)
-           return false;
-
-         rtx arg = XEXP (op, 0);
-         machine_mode arg_mode = GET_MODE (arg);
+       if (mode != SFmode)
+         return false;
 
-         if (arg_mode != BFmode)
-           return false;
+       arg = XEXP (op, 0);
+       arg_mode = GET_MODE (arg);
 
-         if (MEM_P (arg))
-           return true;
+       if (arg_mode != BFmode)
+         return false;
 
-         return register_operand (arg, arg_mode);
-       }
+       return register_operand (arg, arg_mode) || MEM_P (arg);
 
       case FLOAT_TRUNCATE:
-       {
-          if (mode != BFmode)
-           return false;
+       if (mode != BFmode)
+         return false;
 
-         rtx arg = XEXP (op, 0);
-         return (GET_MODE (arg) == SFmode
-                 && GET_CODE (arg) == FLOAT_EXTEND
-                 && GET_MODE (XEXP (arg, 0)) == BFmode);
-       }
+       arg = XEXP (op, 0);
+       return (GET_MODE (arg) == SFmode
+               && GET_CODE (arg) == FLOAT_EXTEND
+               && GET_MODE (XEXP (arg, 0)) == BFmode);
 
         /* Allow for chained operations.  */
       case PLUS:

Reply via email to