diff mbox

Fix combiner when optimizing 3 insns into 2 (PR rtl-optimization/44858)

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

Commit Message

Jakub Jelinek Aug. 25, 2010, 5:09 p.m. UTC
Hi!

When recog_for_combine needs to add some clobbers to newi2pat here,
it might prevent the insns from being emitted in that order, if
newpat depends on the content of the clobbered registers.

On the testcase we have:
(parallel [
  (set (reg:SI 71) (ne:SI (reg:CCZ 17 flags) (const_int 0 [0])))
  (set (reg/v:SI 62 [ c ]) (and:SI (reg:SI 68) (const_int 2 [0x2])))
])
which doesn't match, so we try to split it into 2 insns.  The comment
says, except for HAVE_cc0 targets it usually doesn't matter much in
which order we emit the two insns and thus it tries to emit the and
in i2 and != in i3.  But for the and it adds flags CLOBBER, so the
!= which depends on flags sees a clobbered value.

The patch below in that case tries to swap the two insns if possible
(it is in this case) and only gives up if neither order works.

Bootstrapped/regtested on x86_64-linux and i686-linux.  Ok for trunk/4.5?

2010-08-25  Jakub Jelinek  <jakub@redhat.com>

	PR rtl-optimization/44858
	* combine.c (try_combine): If recog_for_combine added CLOBBERs to
	newi2pat, make sure they don't affect newpat.

	* gcc.c-torture/execute/pr44858.c: New test.


	Jakub

Comments

Ian Lance Taylor Aug. 25, 2010, 5:41 p.m. UTC | #1
Jakub Jelinek <jakub@redhat.com> writes:

> 2010-08-25  Jakub Jelinek  <jakub@redhat.com>
>
> 	PR rtl-optimization/44858
> 	* combine.c (try_combine): If recog_for_combine added CLOBBERs to
> 	newi2pat, make sure they don't affect newpat.
>
> 	* gcc.c-torture/execute/pr44858.c: New test.

This is OK.

Thanks.

Ian
diff mbox

Patch

--- gcc/combine.c.jj	2010-08-20 16:05:41.000000000 +0200
+++ gcc/combine.c	2010-08-25 15:40:07.000000000 +0200
@@ -3725,7 +3725,58 @@  try_combine (rtx i3, rtx i2, rtx i1, rtx
       i2_code_number = recog_for_combine (&newi2pat, i2, &new_i2_notes);
 
       if (i2_code_number >= 0)
-	insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+	{
+	  /* recog_for_combine might have added CLOBBERs to newi2pat.
+	     Make sure NEWPAT does not depend on the clobbered regs.  */
+	  if (GET_CODE (newi2pat) == PARALLEL)
+	    {
+	      for (i = XVECLEN (newi2pat, 0) - 1; i >= 0; i--)
+		if (GET_CODE (XVECEXP (newi2pat, 0, i)) == CLOBBER)
+		  {
+		    rtx reg = XEXP (XVECEXP (newi2pat, 0, i), 0);
+		    if (reg_overlap_mentioned_p (reg, newpat))
+		      break;
+		  }
+
+	      if (i >= 0)
+		{
+		  /* CLOBBERs on newi2pat prevent it going first.
+		     Try the other order of the insns if possible.  */
+		  temp = newpat;
+		  newpat = XVECEXP (newi2pat, 0, 0);
+		  newi2pat = temp;
+#ifdef HAVE_cc0
+		  if (reg_referenced_p (cc0_rtx, newpat))
+		    {
+		      undo_all ();
+		      return 0;
+		    }
+#endif
+
+		  i2_code_number = recog_for_combine (&newi2pat, i2,
+						      &new_i2_notes);
+		  if (i2_code_number < 0)
+		    {
+		      undo_all ();
+		      return 0;
+		    }
+
+		  if (GET_CODE (newi2pat) == PARALLEL)
+		    for (i = XVECLEN (newi2pat, 0) - 1; i >= 0; i--)
+		      if (GET_CODE (XVECEXP (newi2pat, 0, i)) == CLOBBER)
+			{
+			  rtx reg = XEXP (XVECEXP (newi2pat, 0, i), 0);
+			  if (reg_overlap_mentioned_p (reg, newpat))
+			    {
+			      undo_all ();
+			      return 0;
+			    }
+			}
+		}
+	    }
+
+	  insn_code_number = recog_for_combine (&newpat, i3, &new_i3_notes);
+	}
     }
 
   /* If it still isn't recognized, fail and change things back the way they
--- gcc/testsuite/gcc.c-torture/execute/pr44858.c.jj	2010-08-25 15:10:01.000000000 +0200
+++ gcc/testsuite/gcc.c-torture/execute/pr44858.c	2010-08-25 15:09:06.000000000 +0200
@@ -0,0 +1,28 @@ 
+/* PR rtl-optimization/44858 */
+
+extern void abort (void);
+int a = 3;
+int b = 1;
+
+__attribute__((noinline)) long long
+foo (int x, int y)
+{
+  return x / y;
+}
+
+__attribute__((noinline)) int
+bar (void)
+{
+  int c = 2;
+  c &= foo (1, b) > b;
+  b = (a != 0) | c;
+  return c;
+}
+
+int
+main (void)
+{
+  if (bar () != 0 || b != 1)
+    abort ();
+  return 0;
+}