https://gcc.gnu.org/g:874b933495ade45b71d0801cc9acfb2c5ba6f817

commit 874b933495ade45b71d0801cc9acfb2c5ba6f817
Author: Michael Meissner <[email protected]>
Date:   Mon Oct 19 22:17:14 2026 -0400

    Rework BFmode to V4SF mode code.
    
    2026-10-19  Michael Meissner  <[email protected]>
    
            * config/rs6000/float16.cc (fp16_vectorization): Add FP16_UNARY 
support.
            (bfloat16_operation_as_v4sf_inner): Likewise.
            (struct bfloat16_to_v4sf_stats): New structure.
            (zero_bfloat16_to_v4sf_stats): Likewise.
            (bfloat16_to_v4sf_inner): New function.
            (bfloat16_to_v4sf_p): Likewise.
            (bfloat16_to_v4sf_split): Likewise.
            * config/rs6000/float16.md (bfloat16_as_v4sf_1): New insn to support
            using V4SFmode to evaluate BFmode expressions.
            (bfloat16_as_v4sf_2): Likewise.
            (bfloat16_as_v4sf_3): Likewise.
            (bfloat16_binary_op_internal1): For now, keep old BFmode to V4SFmode
            code controlled by the -mno-float16-bf-v4sf switch.
            (bfloat16_binary_op_internal2): Likewise.
            (bfloat16_fma_internal1): Likewise.
            (bfloat16_fma_internal2): Likewise.
            (bfloat16_fms_internal1): Likewise.
            (bfloat16_fms_internal2): Likewise.
            (bfloat16_nfma_internal1): Likewise.
            (bfloat16_nfma_internal2): Likewise.
            (bfloat16_nfms_internal1): Likewise.
            (bfloat16_nfms_internal2): Likewise.
            * config/rs6000/predicates.md (bfloat16_to_v4sf_operand): New 
predicate.
            * config/rs6000/rs6000.h (enum fp16_operation): Add FP16_UNARY.
            * config/rs6000/rs6000-protos.h (bfloat16_to_v4sf_p): New prototype.
            (bfloat16_to_v4sf_split): Likewise.
            * config/rs6000/rs6000.opt (-mfloat16-bf-v4sf): New debug switch.

Diff:
---
 gcc/config/rs6000/float16.cc      | 399 ++++++++++++++++++++++++++++++++++++++
 gcc/config/rs6000/float16.md      |  67 +++++--
 gcc/config/rs6000/predicates.md   |  15 ++
 gcc/config/rs6000/rs6000-protos.h |   3 +
 gcc/config/rs6000/rs6000.opt      |   4 +
 5 files changed, 476 insertions(+), 12 deletions(-)

diff --git a/gcc/config/rs6000/float16.cc b/gcc/config/rs6000/float16.cc
index d81c0f944b97..0cd8ce01e909 100644
--- a/gcc/config/rs6000/float16.cc
+++ b/gcc/config/rs6000/float16.cc
@@ -72,6 +72,10 @@ fp16_vectorization (enum rtx_code icode,
 
   switch (subtype)
     {
+    case FP16_UNARY:
+      n_opts = 1;
+      break;
+
     case FP16_BINARY:
       n_opts = 2;
       break;
@@ -123,6 +127,16 @@ fp16_vectorization (enum rtx_code icode,
   /* Do 2 sets of V4SFmode operations.  */
   switch (subtype)
     {
+    case FP16_UNARY:
+      emit_insn (gen_rtx_SET (result_hi,
+                             gen_rtx_fmt_e (icode, V4SFmode,
+                                            op_hi[0])));
+
+      emit_insn (gen_rtx_SET (result_lo,
+                             gen_rtx_fmt_e (icode, V4SFmode,
+                                            op_lo[0])));
+      break;
+
     case FP16_BINARY:
       emit_insn (gen_rtx_SET (result_hi,
                              gen_rtx_fmt_ee (icode, V4SFmode,
@@ -219,6 +233,11 @@ bfloat16_operation_as_v4sf_inner (enum rtx_code icode,
 
   switch (subtype)
     {
+    case FP16_UNARY:
+      n_opts = 1;
+      gcc_assert (op2 == NULL_RTX && op3 == NULL_RTX);
+      break;
+
     case FP16_BINARY:
       n_opts = 2;
       gcc_assert (op3 == NULL_RTX);
@@ -244,6 +263,15 @@ bfloat16_operation_as_v4sf_inner (enum rtx_code icode,
 
       switch (GET_CODE (op))
        {
+       case NEG:
+       case ABS:
+         ops_v4sf[i] = bfloat16_operation_as_v4sf_inner (GET_CODE (op),
+                                                         XEXP (op, 0),
+                                                         NULL_RTX,
+                                                         NULL_RTX,
+                                                         FP16_UNARY);
+         continue;
+
          /* Handle chained operations.  */
        case PLUS:
        case MINUS:
@@ -317,6 +345,13 @@ bfloat16_operation_as_v4sf_inner (enum rtx_code icode,
   /* Do the operation in V4SFmode.  */
   switch (subtype)
     {
+    case FP16_UNARY:
+      emit_insn (gen_rtx_SET (result_v4sf,
+                             gen_rtx_fmt_e (icode, V4SFmode,
+                                            ops_v4sf[0])));
+
+      break;
+
     case FP16_BINARY:
       emit_insn (gen_rtx_SET (result_v4sf,
                              gen_rtx_fmt_ee (icode, V4SFmode,
@@ -396,3 +431,367 @@ bfloat16_operation_as_v4sf (enum rtx_code icode,
   else
     gcc_unreachable ();
 }
+
+
+/*
+ * Recognize if can BFmode operations in V4SFmode.  If the operation mostly
+ * involves BFmode values with some SFmode values. it is faster to convert the
+ * scalar code to vector and do the operation using one element of the vector,
+ * due to the lack of instructions to convert between BFmode and SFmode/DFmode
+ * scalars on power10.
+ *
+ * We allow multiple operations (a + b + c) to be folded together to try to do
+ * as much possible in the vector unit without having to convert back to scalar
+ * mode.
+ *
+ * We also fold in loads from memory to simplify the conversion.
+ *
+ * The expression that is combined is split before register allocation.
+ */
+
+/*
+ * Stats for whole expression.
+ */
+
+struct bfloat16_to_v4sf_stats
+{
+  unsigned num_bf_regs;                // # of BF registers used
+  unsigned num_bf_loads;               // # of BF values loaded from memory
+  unsigned num_sf_regs;                // # of SF registers used
+  unsigned num_const;          // # of constants used
+  unsigned num_binary;         // # of binary operations done
+  unsigned num_fma;            // # of FMA (fused multiply-adds) done
+  unsigned num_unary;          // # of unary ops not folded into FMA/ABS
+  unsigned num_neg_folded;     // # of negates folded into a FMA/ABS insn
+  unsigned num_extend;         // # of FLOAT_EXTENDs
+};
+
+/* Initialize the bfloat16_to_v4sf_stats structure.  */
+static struct bfloat16_to_v4sf_stats   zero_bfloat16_to_v4sf_stats;
+
+/*
+ * Recursively evaluate whether a RTX expression can be optimized to use
+ * V4SFmode operations.  Return true if the expression might be able to be
+ * optimized, and update the stats.
+ */
+
+static bool
+bfloat16_to_v4sf_inner (rtx op, struct bfloat16_to_v4sf_stats *stats)
+{
+  machine_mode mode = GET_MODE (op);
+  rtx arg;
+  rtx_code code;
+  bool ret = true;
+  bool update_stats = false;
+
+#ifdef TARGET_DEBUG_EXTRA1
+  if (TARGET_DEBUG_EXTRA1)
+    update_stats = true;
+#endif
+
+  if (mode != BFmode && mode != SFmode)
+    ret = false;
+
+  else
+    {
+      switch (GET_CODE (op))
+       {
+       default:
+         ret = false;
+         break;
+
+         // Update register counts.
+       case REG:
+       case SUBREG:
+         if (mode == BFmode)
+           stats->num_bf_regs++;
+         else
+           stats->num_sf_regs++;
+
+         break;
+
+         // Update memory counts.
+       case MEM:
+         if (mode != BFmode)
+           ret = false;
+         else
+           stats->num_bf_loads++;
+
+         break;
+
+         // Update constants
+       case CONST_DOUBLE:
+         stats->num_const++;
+         break;
+
+         // Process absolute value
+       case ABS:
+         stats->num_unary++;
+         if (!bfloat16_to_v4sf_inner (XEXP (op, 0), stats))
+           ret = false;
+
+         break;
+
+         // Process negation, deal with negate being folded into FMA or ABS.
+       case NEG:
+         arg = XEXP (op, 0);
+         code = GET_CODE (arg);
+
+         if (code == FMA || code == ABS)
+           stats->num_neg_folded++;
+         else
+           stats->num_unary++;
+
+         if (!bfloat16_to_v4sf_inner (arg, stats))
+           ret = false;
+
+         break;
+
+         // Process binary operations
+       case PLUS:
+       case MINUS:
+       case MULT:
+       case SMIN:
+       case SMAX:
+         stats->num_binary++;
+
+         if (update_stats)
+           {
+             bool ret1 = bfloat16_to_v4sf_inner (XEXP (op, 0), stats);
+             bool ret2 = bfloat16_to_v4sf_inner (XEXP (op, 1), stats);
+             if (!ret1 || !ret2)
+               ret = false;
+           }
+         else if (!bfloat16_to_v4sf_inner (XEXP (op, 0), stats)
+                  || !bfloat16_to_v4sf_inner (XEXP (op, 1), stats))
+           ret = false;
+
+         break;
+
+         // Process fused multiply-adds
+       case FMA:
+         stats->num_fma++;
+
+         if (update_stats)
+           {
+             bool ret1 = bfloat16_to_v4sf_inner (XEXP (op, 0), stats);
+             bool ret2 = bfloat16_to_v4sf_inner (XEXP (op, 1), stats);
+             bool ret3 = bfloat16_to_v4sf_inner (XEXP (op, 2), stats);
+             if (!ret1 || !ret2 || !ret3)
+               ret = false;
+           }
+         else
+           if (!bfloat16_to_v4sf_inner (XEXP (op, 0), stats)
+               || !bfloat16_to_v4sf_inner (XEXP (op, 1), stats)
+               || !bfloat16_to_v4sf_inner (XEXP (op, 2), stats))
+             ret = false;
+
+         break;
+
+         // Process extend BF -> SF
+       case FLOAT_EXTEND:
+         stats->num_extend++;
+         arg = XEXP (op, 0);
+         if (mode != SFmode || GET_MODE (arg) != BFmode)
+           ret = false;;
+
+         if (!bfloat16_to_v4sf_inner (arg, stats))
+           ret = false;
+       }
+    }
+
+  return ret;
+}
+
+/*
+ * Decide whether an expression can optimize BFmode to use V4SFmode.
+ */
+
+bool
+bfloat16_to_v4sf_p (rtx op, machine_mode mode)
+{
+  if (mode != BFmode && mode != SFmode)
+    return false;
+
+#ifdef TARGET_DEBUG_EXTRA1
+  rtx orig_op = op;
+#endif
+
+  struct bfloat16_to_v4sf_stats stats = zero_bfloat16_to_v4sf_stats;
+
+  // Handle top level FLOAT_TRUNCATE
+  if (GET_CODE (op) == FLOAT_TRUNCATE
+      && mode == BFmode
+      && GET_MODE (XEXP (op, 0)) == SFmode)
+    op = XEXP (op, 0);
+
+  bool ret = bfloat16_to_v4sf_inner (op, &stats);
+
+  // Make sure we had enough BFmode operations to do the optimization
+  if (ret)
+    {
+      unsigned num_bf = stats.num_bf_regs + stats.num_bf_loads;
+
+      // If we had no BFmode values, don't do the optimization.
+      if (!num_bf)
+       ret = false;
+
+      // If we had no binary or fma opertors, don't do the optimization.
+      else if (!stats.num_binary && !stats.num_fma)
+       ret = false;
+
+      // If the expression has much more SFmode elements than BFmode, prefer
+      // converting BFmode to SFmode instead of using V4SFmode.
+      else if (stats.num_sf_regs > (num_bf + 2))
+       ret = false;
+    }
+
+  // Debugging.
+#ifdef TARGET_DEBUG_EXTRA1
+  if (TARGET_DEBUG_EXTRA1)
+    {
+      fprintf (stderr, "\n========== bfloat16_to_v4sf_p, return = %s",
+              ret ? "true" : "false");
+
+      if (stats.num_bf_regs)
+       fprintf (stderr, ", # BF regs = %u", stats.num_bf_regs);
+
+      if (stats.num_bf_loads)
+       fprintf (stderr, ", # BF values loaded = %u", stats.num_bf_loads);
+
+      if (stats.num_sf_regs)
+       fprintf (stderr, ", # SF regs = %u", stats.num_sf_regs);
+
+      if (stats.num_const)
+       fprintf (stderr, ", # constants = %u", stats.num_const);
+
+      if (stats.num_extend)
+       fprintf (stderr, ", # extends = %u", stats.num_extend);
+
+      if (stats.num_unary)
+       fprintf (stderr, ", # unary = %u", stats.num_unary);
+
+      if (stats.num_binary)
+       fprintf (stderr, ", # binary = %u", stats.num_binary);
+
+      if (stats.num_fma)
+       fprintf (stderr, ", # fma = %u", stats.num_fma);
+
+      if (stats.num_neg_folded)
+       fprintf (stderr, ", # neg fold  = %u", stats.num_neg_folded);
+
+      fprintf (stderr, "\n");
+      debug_rtx (orig_op);
+    }
+#endif
+
+  return ret;
+}
+
+/*
+ * Split the isnsns tht optimize BFmode to use V4SFmode.
+ */
+
+void
+bfloat16_to_v4sf_split (rtx dest, rtx src)
+{
+  rtx orig_src = src;
+  enum rtx_code code = GET_CODE (src);
+  rtx arg, op0, op1, op2;
+
+#ifdef TARGET_DEBUG_EXTRA2
+  if (TARGET_DEBUG_EXTRA2)
+    debug_rtx (gen_rtx_SET (dest, src));
+#endif
+
+  if (code == FLOAT_EXTEND || code == FLOAT_TRUNCATE)
+    {
+      src = XEXP (src, 0);
+      code = GET_CODE (src);
+    }
+
+  switch (code)
+    {
+    case ABS:
+      bfloat16_operation_as_v4sf (code, dest,
+                                 XEXP (src, 0),
+                                 NULL_RTX,
+                                 NULL_RTX,
+                                 FP16_UNARY);
+      break;
+
+    case NEG:
+      arg = XEXP (src, 0);
+      if (GET_CODE (arg) == FMA)
+       {
+         op0 = XEXP (arg, 0);
+         op1 = XEXP (arg, 1);
+         op2 = XEXP (arg, 2);
+         if (GET_CODE (op2) == NEG)
+           {
+             op2 = XEXP (op2, 0);
+             bfloat16_operation_as_v4sf (code, dest,
+                                         op0,
+                                         op1,
+                                         op2,
+                                         FP16_NFMS);
+           }
+
+         else
+           bfloat16_operation_as_v4sf (code, dest,
+                                       op0,
+                                       op1,
+                                       op2,
+                                       FP16_NFMA);
+       }
+
+      else
+       bfloat16_operation_as_v4sf (code, dest,
+                                   XEXP (arg, 0),
+                                   NULL_RTX,
+                                   NULL_RTX,
+                                   FP16_UNARY);
+
+      break;
+
+    case PLUS:
+    case MINUS:
+    case MULT:
+    case SMIN:
+    case SMAX:
+      bfloat16_operation_as_v4sf (code, dest,
+                                 XEXP (src, 0),
+                                 XEXP (src, 1),
+                                 NULL_RTX,
+                                 FP16_BINARY);
+      break;
+
+    case FMA:
+      op0 = XEXP (src, 0);
+      op1 = XEXP (src, 1);
+      op2 = XEXP (src, 2);
+      if (GET_CODE (op2) == NEG)
+       {
+         op2 = XEXP (op2, 0);
+         bfloat16_operation_as_v4sf (code, dest,
+                                     op0,
+                                     op1,
+                                     op2,
+                                     FP16_FMS);
+       }
+
+      else
+       bfloat16_operation_as_v4sf (code, dest,
+                                   op0,
+                                   op1,
+                                   op2,
+                                   FP16_FMA);
+
+      break;
+
+    default:
+      fatal_insn_not_found (gen_rtx_SET (dest, orig_src));
+    }
+
+  return;
+}
diff --git a/gcc/config/rs6000/float16.md b/gcc/config/rs6000/float16.md
index d3a31791f9bc..4f14862945f4 100644
--- a/gcc/config/rs6000/float16.md
+++ b/gcc/config/rs6000/float16.md
@@ -1283,12 +1283,55 @@
 ;; uses -Ofast.  Without -Ofast, it will always convert BFmode into
 ;; SFmode.
 
+(define_insn_and_split "*bfloat16_as_v4sf_1"
+  [(set (match_operand:BF 0 "vsx_register_operand")
+       (match_operand:BF 1 "bfloat16_to_v4sf_operand"))]
+  "TARGET_BF_V4SF
+   && TARGET_BFLOAT16_HW
+   && can_create_pseudo_p ()"
+  "#"
+  "&& 1"
+  [(pc)]
+{
+  bfloat16_to_v4sf_split (operands[0], operands[1]);
+  DONE;
+})
+
+(define_insn_and_split "*bfloat16_as_v4sf_2"
+  [(set (match_operand:BF 0 "vsx_register_operand")
+       (float_truncate:BF
+        (match_operand:SF 1 "bfloat16_to_v4sf_operand")))]
+  "TARGET_BF_V4SF
+   && TARGET_BFLOAT16_HW
+   && can_create_pseudo_p ()"
+  "#"
+  "&& 1"
+  [(pc)]
+{
+  bfloat16_to_v4sf_split (operands[0], operands[1]);
+  DONE;
+})
+
+(define_insn_and_split "*bfloat16_as_v4sf_3"
+  [(set (match_operand:SF 0 "vsx_register_operand")
+       (match_operand:SF 1 "bfloat16_to_v4sf_operand"))]
+  "TARGET_BF_V4SF
+   && TARGET_BFLOAT16_HW
+   && can_create_pseudo_p ()"
+  "#"
+  "&& 1"
+  [(pc)]
+{
+  bfloat16_to_v4sf_split (operands[0], operands[1]);
+  DONE;
+})
+
 (define_insn_and_split "*bfloat16_binary_op_internal1"
   [(set (match_operand:SF 0 "vsx_register_operand")
        (match_operator:SF 1 "fp16_binary_operator"
                           [(match_operand:SF 2 "bfloat16_v4sf_operand")
                            (match_operand:SF 3 "bfloat16_v4sf_operand")]))]
-  "TARGET_BFLOAT16_HW && can_create_pseudo_p ()
+  "!TARGET_BF_V4SF && TARGET_BFLOAT16_HW && can_create_pseudo_p ()
    && (bfloat16_bf_operand (operands[2], SFmode)
        || bfloat16_bf_operand (operands[3], SFmode))"
   "#"
@@ -1306,7 +1349,7 @@
         (match_operator:SF 1 "fp16_binary_operator"
                            [(match_operand:SF 2 "bfloat16_v4sf_operand")
                             (match_operand:SF 3 "bfloat16_v4sf_operand")])))]
-  "TARGET_BFLOAT16_HW && can_create_pseudo_p ()
+  "!TARGET_BF_V4SF && TARGET_BFLOAT16_HW && can_create_pseudo_p ()
    && (bfloat16_bf_operand (operands[2], SFmode)
        || bfloat16_bf_operand (operands[3], SFmode))"
   "#"
@@ -1324,7 +1367,7 @@
         (match_operand:SF 1 "bfloat16_v4sf_operand")
         (match_operand:SF 2 "bfloat16_v4sf_operand")
         (match_operand:SF 3 "bfloat16_v4sf_operand")))]
-  "TARGET_BFLOAT16_HW && can_create_pseudo_p ()
+  "!TARGET_BF_V4SF && TARGET_BFLOAT16_HW && can_create_pseudo_p ()
    && (bfloat16_bf_operand (operands[1], SFmode)
        + bfloat16_bf_operand (operands[2], SFmode)
        + bfloat16_bf_operand (operands[3], SFmode) >= 2)"
@@ -1344,7 +1387,7 @@
          (match_operand:SF 1 "bfloat16_v4sf_operand")
          (match_operand:SF 2 "bfloat16_v4sf_operand")
          (match_operand:SF 3 "bfloat16_v4sf_operand"))))]
-  "TARGET_BFLOAT16_HW && can_create_pseudo_p ()
+  "!TARGET_BF_V4SF && TARGET_BFLOAT16_HW && can_create_pseudo_p ()
    && (bfloat16_bf_operand (operands[1], SFmode)
        + bfloat16_bf_operand (operands[2], SFmode)
        + bfloat16_bf_operand (operands[3], SFmode) >= 2)"
@@ -1364,7 +1407,7 @@
         (match_operand:SF 2 "bfloat16_v4sf_operand")
         (neg:SF
          (match_operand:SF 3 "bfloat16_v4sf_operand"))))]
-  "TARGET_BFLOAT16_HW && can_create_pseudo_p ()
+  "!TARGET_BF_V4SF && TARGET_BFLOAT16_HW && can_create_pseudo_p ()
    && (bfloat16_bf_operand (operands[1], SFmode)
        + bfloat16_bf_operand (operands[2], SFmode)
        + bfloat16_bf_operand (operands[3], SFmode) >= 2)"
@@ -1385,7 +1428,7 @@
          (match_operand:SF 2 "bfloat16_v4sf_operand")
          (neg:SF
           (match_operand:SF 3 "bfloat16_v4sf_operand")))))]
-  "TARGET_BFLOAT16_HW && can_create_pseudo_p ()
+  "!TARGET_BF_V4SF && TARGET_BFLOAT16_HW && can_create_pseudo_p ()
    && (bfloat16_bf_operand (operands[1], SFmode)
        + bfloat16_bf_operand (operands[2], SFmode)
        + bfloat16_bf_operand (operands[3], SFmode) >= 2)"
@@ -1405,7 +1448,7 @@
          (match_operand:SF 1 "bfloat16_v4sf_operand")
          (match_operand:SF 2 "bfloat16_v4sf_operand")
          (match_operand:SF 3 "bfloat16_v4sf_operand"))))]
-  "TARGET_BFLOAT16_HW && can_create_pseudo_p ()
+  "!TARGET_BF_V4SF && TARGET_BFLOAT16_HW && can_create_pseudo_p ()
    && (bfloat16_bf_operand (operands[1], SFmode)
        + bfloat16_bf_operand (operands[2], SFmode)
        + bfloat16_bf_operand (operands[3], SFmode) >= 2)"
@@ -1426,7 +1469,7 @@
           (match_operand:SF 1 "bfloat16_v4sf_operand")
           (match_operand:SF 2 "bfloat16_v4sf_operand")
           (match_operand:SF 3 "bfloat16_v4sf_operand")))))]
-  "TARGET_BFLOAT16_HW && can_create_pseudo_p ()
+  "!TARGET_BF_V4SF && TARGET_BFLOAT16_HW && can_create_pseudo_p ()
    && (bfloat16_bf_operand (operands[1], SFmode)
        + bfloat16_bf_operand (operands[2], SFmode)
        + bfloat16_bf_operand (operands[3], SFmode) >= 2)"
@@ -1447,7 +1490,7 @@
           (match_operand:SF 1 "bfloat16_v4sf_operand")
           (match_operand:SF 2 "bfloat16_v4sf_operand")
           (match_operand:SF 3 "bfloat16_v4sf_operand")))))]
-  "TARGET_BFLOAT16_HW && can_create_pseudo_p ()
+  "!TARGET_BF_V4SF && TARGET_BFLOAT16_HW && can_create_pseudo_p ()
    && (bfloat16_bf_operand (operands[1], SFmode)
        + bfloat16_bf_operand (operands[2], SFmode)
        + bfloat16_bf_operand (operands[3], SFmode) >= 2)"
@@ -1468,7 +1511,7 @@
          (match_operand:SF 2 "bfloat16_v4sf_operand")
          (neg:SF
           (match_operand:SF 3 "bfloat16_v4sf_operand")))))]
-  "TARGET_BFLOAT16_HW && can_create_pseudo_p ()
+  "!TARGET_BF_V4SF && TARGET_BFLOAT16_HW && can_create_pseudo_p ()
    && (bfloat16_bf_operand (operands[1], SFmode)
        + bfloat16_bf_operand (operands[2], SFmode)
        + bfloat16_bf_operand (operands[3], SFmode) >= 2)"
@@ -1490,7 +1533,7 @@
           (match_operand:SF 2 "bfloat16_v4sf_operand")
           (neg:SF
            (match_operand:SF 3 "bfloat16_v4sf_operand"))))))]
-  "TARGET_BFLOAT16_HW && can_create_pseudo_p ()
+  "!TARGET_BF_V4SF && TARGET_BFLOAT16_HW && can_create_pseudo_p ()
    && (bfloat16_bf_operand (operands[1], SFmode)
        + bfloat16_bf_operand (operands[2], SFmode)
        + bfloat16_bf_operand (operands[3], SFmode) >= 2)"
@@ -1512,7 +1555,7 @@
           (match_operand:SF 2 "bfloat16_v4sf_operand")
           (neg:SF
            (match_operand:SF 3 "bfloat16_v4sf_operand"))))))]
-  "TARGET_BFLOAT16_HW && can_create_pseudo_p ()
+  "!TARGET_BF_V4SF && TARGET_BFLOAT16_HW && can_create_pseudo_p ()
    && (bfloat16_bf_operand (operands[1], SFmode)
        + bfloat16_bf_operand (operands[2], SFmode)
        + bfloat16_bf_operand (operands[3], SFmode) >= 2)"
diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index afe63447eb0d..70a927940b10 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -2315,6 +2315,21 @@
 (define_predicate "fp16_binary_operator"
   (match_code "plus,minus,mult,smax,smin"))
 
+
+;; Match bfloat16/float operands that can be optimized to do the
+;; operation in V4SFmode.
+(define_predicate "bfloat16_to_v4sf_operand"
+  (match_code 
"reg,subreg,const_double,float_extend,plus,minus,mult,fma,neg,abs")
+{
+  if (mode != BFmode && mode != SFmode)
+    return false;
+
+  if (mode != GET_MODE (op))
+    return false;
+
+  return bfloat16_to_v4sf_p (op, mode);
+})
+
 ;; Match bfloat16/float operands that can be optimized to do the
 ;; operation in V4SFmode.
 (define_predicate "bfloat16_v4sf_operand"
diff --git a/gcc/config/rs6000/rs6000-protos.h 
b/gcc/config/rs6000/rs6000-protos.h
index 3691b522f42c..1f8f75201461 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -262,6 +262,7 @@ extern unsigned constant_generates_xxspltidp 
(vec_const_128bit_type *);
 /* From float16.cc.  */
 /* Optimize bfloat16 and float16 operations.  */
 enum fp16_operation {
+  FP16_UNARY,                          /* Bfloat16/float16 unary op.  */
   FP16_BINARY,                         /* Bfloat16/float16 binary op.  */
   FP16_FMA,                            /* (a * b) + c.  */
   FP16_FMS,                            /* (a * b) - c.  */
@@ -273,6 +274,8 @@ extern void fp16_vectorization (enum rtx_code, rtx, rtx, 
rtx, rtx,
                                enum fp16_operation);
 extern void bfloat16_operation_as_v4sf (enum rtx_code, rtx, rtx, rtx, rtx,
                                        enum fp16_operation);
+extern bool bfloat16_to_v4sf_p (rtx, machine_mode);
+extern void bfloat16_to_v4sf_split (rtx, rtx);
 #endif /* RTX_CODE */
 
 #ifdef TREE_CODE
diff --git a/gcc/config/rs6000/rs6000.opt b/gcc/config/rs6000/rs6000.opt
index 973051afc350..47a705a20dbc 100644
--- a/gcc/config/rs6000/rs6000.opt
+++ b/gcc/config/rs6000/rs6000.opt
@@ -650,6 +650,10 @@ mfloat16-gpr-convert
 Target Undocumented Var(TARGET_FLOAT16_GPR_CONVERT) Init(1) Save
 Pass/return (do not pass/return) 16-it float conversions in GPR registers.
 
+mfloat16-bf-v4sf
+Target Undocumented Var(TARGET_BF_V4SF) Init(1) Save
+Optimize bfloat16 to use float vector instructions.
+
 ; Documented parameters
 
 -param=rs6000-vect-unroll-limit=

Reply via email to