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

login
register
mail settings
Submitter Jakub Jelinek
Date Aug. 25, 2010, 5:09 p.m.
Message ID <20100825170909.GX702@tyan-ft48-01.lab.bos.redhat.com>
Download mbox | patch
Permalink /patch/62726/
State New
Headers show

Comments

Jakub Jelinek - Aug. 25, 2010, 5:09 p.m.
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
Ian Taylor - Aug. 25, 2010, 5:41 p.m.
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

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;
+}