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

Reply via email to