Patchwork Fix combiner bug with 4th insn

login
register
mail settings
Submitter Eric Botcazou
Date March 23, 2013, 11:04 a.m.
Message ID <2617378.mUruDL8GLh@polaris>
Download mbox | patch
Permalink /patch/230324/
State New
Headers show

Comments

Eric Botcazou - March 23, 2013, 11:04 a.m.
We ran into a combiner bug on the 4.7 branch for ARM (LE/soft-float/Thumb):

FAIL: gcc.c-torture/execute/930718-1.c compilation,  -O2  (internal compiler 
error)

It's a bug introduced by the handling of the 4th instruction:

(insn 8 68 9 2 (set (reg/v:SI 139 [ foo ])
        (const_int 1 [0x1])) 930718-1.c:11:16 714 {*thumb2_movsi_insn}
     (nil))

(insn 9 8 11 2 (set (zero_extract:SI (reg/v:SI 139 [ foo ])
            (const_int 1 [0x1])
            (const_int 1 [0x1]))
        (const_int 0 [0])) 930718-1.c:11:16 84 {insv_zero}
     (nil))

(insn 14 13 67 2 (set (reg:CC_NOOV 24 cc)
        (compare:CC_NOOV (zero_extract:SI (reg/v:SI 139 [ foo ])
                (const_int 2 [0x2])
                (const_int 0 [0]))
            (const_int 0 [0]))) 930718-1.c:11:16 79 
{*zeroextractsi_compare0_scratch}
     (expr_list:REG_DEAD (reg/v:SI 139 [ foo ])
        (nil)))

(insn 21 19 22 2 (set (reg:SI 147)
        (if_then_else:SI (eq:SI (reg:CC_NOOV 24 cc)
                (const_int 0 [0]))
            (const_int 2 [0x2])
            (const_int 0 [0]))) 930718-1.c:31:30 721 {*thumb2_movsicc_insn}
     (expr_list:REG_DEAD (reg:CC 24 cc)
        (nil)))

The combiner first thinks that it needs to keep the set in insn 8, only to 
discover later that the REG_DEAD note in insn 14 kills it, which confuses the 
code putting back the notes at the end.

Fixed thusly.  The patch also does a bit of refactoring in the block of code 
putting back notes at the end.

Tested on x86_64-suse-linux, applied on the mainline.


2013-03-23  Eric Botcazou  <ebotcazou@adacore.com>

	* combine.c (try_combine): Adjust comment.  Do not add the set of
	insn #0 if the destination indirectly is set or dies in insn #2.
	Tidy up code to distribute a new note.

Patch

Index: combine.c
===================================================================
--- combine.c	(revision 196816)
+++ combine.c	(working copy)
@@ -2845,13 +2845,13 @@  try_combine (rtx i3, rtx i2, rtx i1, rtx
 
   /* See if the SETs in I1 or I2 need to be kept around in the merged
      instruction: whenever the value set there is still needed past I3.
-     For the SETs in I2, this is easy: we see if I2DEST dies or is set in I3.
+     For the SET in I2, this is easy: we see if I2DEST dies or is set in I3.
 
-     For the SET in I1, we have two cases:  If I1 and I2 independently
-     feed into I3, the set in I1 needs to be kept around if I1DEST dies
+     For the SET in I1, we have two cases: if I1 and I2 independently feed
+     into I3, the set in I1 needs to be kept around unless I1DEST dies
      or is set in I3.  Otherwise (if I1 feeds I2 which feeds I3), the set
      in I1 needs to be kept around unless I1DEST dies or is set in either
-     I2 or I3.  The same consideration applies to I0.  */
+     I2 or I3.  The same considerations apply to I0.  */
 
   added_sets_2 = !dead_or_set_p (i3, i2dest);
 
@@ -2863,8 +2863,9 @@  try_combine (rtx i3, rtx i2, rtx i1, rtx
 
   if (i0)
     added_sets_0 =  !(dead_or_set_p (i3, i0dest)
-		      || (i0_feeds_i2_n && dead_or_set_p (i2, i0dest))
-		      || (i0_feeds_i1_n && dead_or_set_p (i1, i0dest)));
+		      || (i0_feeds_i1_n && dead_or_set_p (i1, i0dest))
+		      || ((i0_feeds_i2_n || (i0_feeds_i1_n && i1_feeds_i2_n))
+			  && dead_or_set_p (i2, i0dest)));
   else
     added_sets_0 = 0;
 
@@ -4158,14 +4159,12 @@  try_combine (rtx i3, rtx i2, rtx i1, rtx
 
     if (i3dest_killed)
       {
+	rtx new_note = alloc_reg_note (REG_DEAD, i3dest_killed, NULL_RTX);
 	if (newi2pat && reg_set_p (i3dest_killed, newi2pat))
-	  distribute_notes (alloc_reg_note (REG_DEAD, i3dest_killed,
-					    NULL_RTX),
-			    NULL_RTX, i2, NULL_RTX, elim_i2, elim_i1, elim_i0);
+	  distribute_notes (new_note, NULL_RTX, i2, NULL_RTX, elim_i2,
+			    elim_i1, elim_i0);
 	else
-	  distribute_notes (alloc_reg_note (REG_DEAD, i3dest_killed,
-					    NULL_RTX),
-			    NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
+	  distribute_notes (new_note, NULL_RTX, i3, newi2pat ? i2 : NULL_RTX,
 			    elim_i2, elim_i1, elim_i0);
       }