On Wed, Feb 4, 2026 at 5:08 PM Robin Dapp <[email protected]> wrote:
>
> 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;
But the function comment documents this.
> - }
> - }
> - 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;
It seems to be the fix is to check ops[] properly? But maybe I
mis-understand the failure
mode.
> +
> + /* 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