Hi,

When looking for FMA opportunities we can find a multiplication use in an
else operand:

  vect_pretmp_50.23_121 = MEM <vector(2) charD.2> [(charD.2 *)&dD.2916 + 14B];
  vect__28.25_123 = vect_pretmp_50.23_121 * { 2, 2 };
  vect_patt_99.26_124 = .COND_ADD ({ -1, -1 }, vect_pretmp_50.23_121, { 14, 15 
}, vect__28.25_123);

and build it:
  vect_pretmp_50.23_121 = MEM <vector(2) charD.2> [(charD.2 *)&dD.2916 + 14B];
  vect_patt_99.26_124 = .FMA (vect_pretmp_50.23_121, { 2, 2 }, 
vect_pretmp_50.23_121);

But that's invalid as the else operand is actually unused as the
conditional mask is always true.

In can_interpret_as_conditional_op_p we don't set cond and else if the
cond is always true.  Therefore the existing check for else_value ==
result does not succeed.

This patch reinstates the cond and else operands and lets the callers
handle an always-true cond.

Bootstrapped and regtested on x86, power10, and aarch64.
Regtested on riscv64.

Regards
 Robin

        PR tree-optimization/123940

gcc/ChangeLog:

        * internal-fn.cc (can_interpret_as_conditional_op_p): Don't set
        cond and else to zero if cond is always true.
        * tree-ssa-math-opts.cc (convert_mult_to_fma_1): Handle
        always-true cond.
        (convert_mult_to_fma): Ditto.

gcc/testsuite/ChangeLog:

        * gcc.target/riscv/rvv/autovec/pr123940.c: New test.
---
 gcc/internal-fn.cc                            | 10 +-------
 .../gcc.target/riscv/rvv/autovec/pr123940.c   | 25 +++++++++++++++++++
 gcc/tree-ssa-math-opts.cc                     | 10 +++++---
 3 files changed, 32 insertions(+), 13 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123940.c

diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc
index d879568c6e3..3cab3a491de 100644
--- a/gcc/internal-fn.cc
+++ b/gcc/internal-fn.cc
@@ -4978,15 +4978,7 @@ can_interpret_as_conditional_op_p (gimple *stmt, tree 
*cond_out,
            for (unsigned int i = 0; i < 3; ++i)
              ops[i] = i < nops ? gimple_call_arg (call, i + 1) : NULL_TREE;
            *else_out = gimple_call_arg (call, nops + 1);
-           if (len_index < 0)
-             {
-               if (integer_truep (*cond_out))
-                 {
-                   *cond_out = NULL_TREE;
-                   *else_out = NULL_TREE;
-                 }
-             }
-           else
+           if (len_index != -1)
              {
                *len = gimple_call_arg (call, len_index);
                *bias = gimple_call_arg (call, len_index + 1);
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123940.c 
b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123940.c
new file mode 100644
index 00000000000..329e598f068
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr123940.c
@@ -0,0 +1,25 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -march=rv64gcv -mabi=lp64d -std=gnu99 
-fdump-tree-widening_mul" } */
+
+long a;
+long long b;
+_Bool c[16];
+char d[16];
+char e = 0;
+int f = 1;
+
+int main ()
+{
+  for (long i = 0; i < 16; ++i)
+    c[i] = 40;
+  for (int j = 0; j < 16; j++)
+    {
+      e = (c[j] ? j : d[j]) + d[j];
+      a = f * c[j] ?: ~0;
+    }
+  b = (int) e;
+  if (b != 15)
+    __builtin_abort ();
+}
+
+/* { dg-final { scan-tree-dump-not "FMA" "widening_mul" } } */
diff --git a/gcc/tree-ssa-math-opts.cc b/gcc/tree-ssa-math-opts.cc
index 4b50a96ad3a..1f72ba7f1fc 100644
--- a/gcc/tree-ssa-math-opts.cc
+++ b/gcc/tree-ssa-math-opts.cc
@@ -3190,7 +3190,7 @@ convert_mult_to_fma_1 (tree mul_result, tree op1, tree 
op2)
        fma_stmt
          = gimple_build_call_internal (IFN_COND_LEN_FMA, 7, cond, mulop1, op2,
                                        addop, else_value, len, bias);
-      else if (cond)
+      else if (!integer_truep (cond))
        fma_stmt = gimple_build_call_internal (IFN_COND_FMA, 5, cond, mulop1,
                                               op2, addop, else_value);
       else
@@ -3560,10 +3560,12 @@ convert_mult_to_fma (gimple *mul_stmt, tree op1, tree 
op2,
          if (mul_cond && cond != mul_cond)
            return false;
 
-         if (cond)
+         if (cond == result || else_value == result)
+           return false;
+
+         /* For a real mask, use a conditional FMA.  */
+         if (!integer_truep (cond))
            {
-             if (cond == result || else_value == result)
-               return false;
              if (!direct_internal_fn_supported_p (IFN_COND_FMA, type,
                                                   opt_type))
                return false;
-- 
2.52.0

Reply via email to