Fix an endless recursion during simplification of MULT (PR rtl-optimization/49472)

Submitted by Jakub Jelinek on July 4, 2011, 5:40 p.m.

Details

Message ID 20110704174043.GU16443@tyan-ft48-01.lab.bos.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek July 4, 2011, 5:40 p.m.
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  <jakub@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.


	Jakub

Comments

Eric Botcazou July 4, 2011, 6:42 p.m.
> 2011-07-04  Jakub Jelinek  <jakub@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.

OK for mainline and 4.6 branch.

Patch hide | download patch | download mbox

--- 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