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