Hi!

On the attached testcase simplify-rtx.c was endlessly oscillating when
trying to simplify a complex debug insn location.  The first
hunk changes oscillation between 3 possible expressions into oscillation
between 2 possible expressions, by preferring to change second argument
instead of first, because swap_commutative_operands_p prefers to put
NEG to the second argument instead of first.

The second hunk fixes the oscillation by not trying to optimize
if we just move the NEG around.  Otherwise, on
(mult (mult (reg A) (reg B)) (neg (reg B)))
those hunks try to move the neg to the first argument to see if it would
simplify things.  That becomes then (mult (mult (reg A) (neg (reg B))) (reg B))
and as MULT is associative and swap_commutative_operands_p prefers to
put NEG last, it optimizes it again into the original form and back
endlessly.  The patch still tries to simplify the negation of the other
argument, but if the other argument is also MULT and it didn't really
simplify it, just moved the negation around, it will stop.

Bootstrapped/regtested on x86_64-linux and i686-linux.  Ok for trunk?
The bug is latent on 4.6 branch, ok for branch as well?

2011-07-04  Jakub Jelinek  <ja...@redhat.com>

        PR rtl-optimization/49472
        * simplify-rtx.c (simplify_unary_operation_1) <case NEG>: When
        negating MULT, negate the second operand instead of first.
        (simplify_binary_operation_1) <case MULT>: If one operand is
        a NEG and the other is MULT, don't attempt to optimize by
        negation of the MULT operand if it only moves the NEG operation
        around.

        * gfortran.dg/pr49472.f90: New test.

--- gcc/simplify-rtx.c.jj       2011-06-21 16:46:01.000000000 +0200
+++ gcc/simplify-rtx.c  2011-07-04 12:14:51.000000000 +0200
@@ -686,13 +686,13 @@ simplify_unary_operation_1 (enum rtx_cod
          return simplify_gen_binary (MINUS, mode, temp, XEXP (op, 1));
        }
 
-      /* (neg (mult A B)) becomes (mult (neg A) B).
+      /* (neg (mult A B)) becomes (mult A (neg B)).
         This works even for floating-point values.  */
       if (GET_CODE (op) == MULT
          && !HONOR_SIGN_DEPENDENT_ROUNDING (mode))
        {
-         temp = simplify_gen_unary (NEG, mode, XEXP (op, 0), mode);
-         return simplify_gen_binary (MULT, mode, temp, XEXP (op, 1));
+         temp = simplify_gen_unary (NEG, mode, XEXP (op, 1), mode);
+         return simplify_gen_binary (MULT, mode, XEXP (op, 0), temp);
        }
 
       /* NEG commutes with ASHIFT since it is multiplication.  Only do
@@ -2271,12 +2271,34 @@ simplify_binary_operation_1 (enum rtx_co
       if (GET_CODE (op0) == NEG)
        {
          rtx temp = simplify_unary_operation (NEG, mode, op1, mode);
+         /* If op1 is a MULT as well and simplify_unary_operation
+            just moved the NEG to the second operand, simplify_gen_binary
+            below could through simplify_associative_operation move
+            the NEG around again and recurse endlessly.  */
+         if (temp
+             && GET_CODE (op1) == MULT
+             && GET_CODE (temp) == MULT
+             && XEXP (op1, 0) == XEXP (temp, 0)
+             && GET_CODE (XEXP (temp, 1)) == NEG
+             && XEXP (op1, 1) == XEXP (XEXP (temp, 1), 0))
+           temp = NULL_RTX;
          if (temp)
            return simplify_gen_binary (MULT, mode, XEXP (op0, 0), temp);
        }
       if (GET_CODE (op1) == NEG)
        {
          rtx temp = simplify_unary_operation (NEG, mode, op0, mode);
+         /* If op0 is a MULT as well and simplify_unary_operation
+            just moved the NEG to the second operand, simplify_gen_binary
+            below could through simplify_associative_operation move
+            the NEG around again and recurse endlessly.  */
+         if (temp
+             && GET_CODE (op0) == MULT
+             && GET_CODE (temp) == MULT
+             && XEXP (op0, 0) == XEXP (temp, 0)
+             && GET_CODE (XEXP (temp, 1)) == NEG
+             && XEXP (op0, 1) == XEXP (XEXP (temp, 1), 0))
+           temp = NULL_RTX;
          if (temp)
            return simplify_gen_binary (MULT, mode, temp, XEXP (op1, 0));
        }
--- gcc/testsuite/gfortran.dg/pr49472.f90.jj    2011-07-04 12:23:12.000000000 
+0200
+++ gcc/testsuite/gfortran.dg/pr49472.f90       2011-07-04 12:22:53.000000000 
+0200
@@ -0,0 +1,15 @@
+! PR rtl-optimization/49472
+! { dg-do compile }
+! { dg-options "-O -fcompare-debug -ffast-math" }
+subroutine pr49472
+  integer, parameter :: n = 3
+  real(8) :: a, b, c, d, e (n+1)
+  integer :: i
+  do i=2, (n+1)
+    b = 1. / ((i - 1.5d0) * 1.)
+    c = b * a
+    d = -b * c / (1. + b * b) ** 1.5d0
+    e(i) = d
+  end do
+  call dummy (e)
+end subroutine

        Jakub

Reply via email to