The following helps the x86 backend by canonicalizing FMAs to have any negation done to one of the commutative multiplication operands be done to a register (and not a memory operand). Likewise to put a register operand first and a memory operand second; swap_commutative_operands_p seems to treat REG_P and MEM_P the same but comments indicate "complex expressiosn should be first".
In particular this does (fma MEM REG REG) -> (fma REG MEM REG) and (fma (neg MEM) REG REG) -> (fma (neg REG) MEM REG) which are the reasons for the testsuite regressions in gcc.target/i386/cond_op_fma*.c Bootstrapped and tested on x86_64-unknown-linux-gnu. I'm not quite sure this is the correct approach - simplify-rtx doesn't seem to do "only canonicalization" but the existing FMA case looks odd in that context. Should the target simply reject cases with wrong "canonicalization" or does it need to cope with all variants in the patterns that fail matching during combine without the change? Thanks, Richard. PR target/117072 * simplify-rtx.cc (simplify_context::simplify_ternary_operation): Adjust FMA canonicalization. --- gcc/simplify-rtx.cc | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc index e8e60404ef6..8b4fa0d7aa4 100644 --- a/gcc/simplify-rtx.cc +++ b/gcc/simplify-rtx.cc @@ -6830,10 +6830,21 @@ simplify_context::simplify_ternary_operation (rtx_code code, machine_mode mode, op0 = tem, op1 = XEXP (op1, 0), any_change = true; } - /* Canonicalize the two multiplication operands. */ + /* Canonicalize the two multiplication operands. A negation + should go first and if possible the negation should be + to a register. */ /* a * -b + c => -b * a + c. */ - if (swap_commutative_operands_p (op0, op1)) + if (swap_commutative_operands_p (op0, op1) + || (REG_P (op1) && !REG_P (op0) && GET_CODE (op0) != NEG)) std::swap (op0, op1), any_change = true; + else if (GET_CODE (op0) == NEG && !REG_P (XEXP (op0, 0)) + && REG_P (op1)) + { + op0 = XEXP (op0, 0); + op1 = simplify_gen_unary (NEG, mode, op1, mode); + std::swap (op0, op1); + any_change = true; + } if (any_change) return gen_rtx_FMA (mode, op0, op1, op2); -- 2.43.0