The combine pass is trying to combine:

Trying 16, 22, 21 -> 23:
   16: r104:QI=flags:CCNO>0
   22: {r120:QI=r104:QI^0x1;clobber flags:CC;}
      REG_UNUSED flags:CC
   21: r119:QI=flags:CCNO<=0
      REG_DEAD flags:CCNO
   23: {r110:QI=r119:QI|r120:QI;clobber flags:CC;}
      REG_DEAD r120:QI
      REG_DEAD r119:QI
      REG_UNUSED flags:CC

and creates the following two insn sequence:

modifying insn i2    22: r104:QI=flags:CCNO>0
      REG_DEAD flags:CC
deferring rescan insn with uid = 22.
modifying insn i3    23: r110:QI=flags:CCNO<=0
      REG_DEAD flags:CC
deferring rescan insn with uid = 23.

where the REG_DEAD note in i2 is not correct, because the flags
register is still referenced in i3.  In try_combine() megafunction,
we have this part:

--cut here--
    /* Distribute all the LOG_LINKS and REG_NOTES from I1, I2, and I3.  */
    if (i3notes)
      distribute_notes (i3notes, i3, i3, newi2pat ? i2 : NULL,
            elim_i2, elim_i1, elim_i0);
    if (i2notes)
      distribute_notes (i2notes, i2, i3, newi2pat ? i2 : NULL,
            elim_i2, elim_i1, elim_i0);
    if (i1notes)
      distribute_notes (i1notes, i1, i3, newi2pat ? i2 : NULL,
            elim_i2, local_elim_i1, local_elim_i0);
    if (i0notes)
      distribute_notes (i0notes, i0, i3, newi2pat ? i2 : NULL,
            elim_i2, elim_i1, local_elim_i0);
    if (midnotes)
      distribute_notes (midnotes, NULL, i3, newi2pat ? i2 : NULL,
            elim_i2, elim_i1, elim_i0);
--cut here--

where the compiler distributes REG_UNUSED note from i2:

   22: {r120:QI=r104:QI^0x1;clobber flags:CC;}
      REG_UNUSED flags:CC

via distribute_notes() using the following:

--cut here--
      /* Otherwise, if this register is used by I3, then this register
         now dies here, so we must put a REG_DEAD note here unless there
         is one already.  */
      else if (reg_referenced_p (XEXP (note, 0), PATTERN (i3))
           && ! (REG_P (XEXP (note, 0))
             ? find_regno_note (i3, REG_DEAD,
                        REGNO (XEXP (note, 0)))
             : find_reg_note (i3, REG_DEAD, XEXP (note, 0))))
        {
          PUT_REG_NOTE_KIND (note, REG_DEAD);
          place = i3;
        }
--cut here--

Flags register is used in I3, but there already is a REG_DEAD note in I3.
The above condition doesn't trigger and continues in the "else" part where
REG_DEAD note is put to I2.  The proposed solution corrects the above
logic to trigger every time the register is referenced in I3, avoiding the
"else" part.

    PR rtl-optimization/118739

gcc/ChangeLog:

    * combine.cc (distribute_notes) <case REG_UNUSED>: Correct the
      logic when the register is used by I3.

gcc/testsuite/ChangeLog:

    * gcc.target/i386/pr118739.c: New test.

Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}.

OK for master and eventual backports?

Uros.
diff --git a/gcc/combine.cc b/gcc/combine.cc
index 3beeb514b81..1b2bd34748e 100644
--- a/gcc/combine.cc
+++ b/gcc/combine.cc
@@ -14523,14 +14523,15 @@ distribute_notes (rtx notes, rtx_insn *from_insn, 
rtx_insn *i3, rtx_insn *i2,
          /* Otherwise, if this register is used by I3, then this register
             now dies here, so we must put a REG_DEAD note here unless there
             is one already.  */
-         else if (reg_referenced_p (XEXP (note, 0), PATTERN (i3))
-                  && ! (REG_P (XEXP (note, 0))
-                        ? find_regno_note (i3, REG_DEAD,
-                                           REGNO (XEXP (note, 0)))
-                        : find_reg_note (i3, REG_DEAD, XEXP (note, 0))))
+         else if (reg_referenced_p (XEXP (note, 0), PATTERN (i3)))
            {
-             PUT_REG_NOTE_KIND (note, REG_DEAD);
-             place = i3;
+             if (! (REG_P (XEXP (note, 0))
+                    ? find_regno_note (i3, REG_DEAD, REGNO (XEXP (note, 0)))
+                    : find_reg_note (i3, REG_DEAD, XEXP (note, 0))))
+               {
+                 PUT_REG_NOTE_KIND (note, REG_DEAD);
+                 place = i3;
+               }
            }
 
          /* A SET or CLOBBER of the REG_UNUSED reg has been removed,
diff --git a/gcc/testsuite/gcc.target/i386/pr118739.c 
b/gcc/testsuite/gcc.target/i386/pr118739.c
new file mode 100644
index 00000000000..89bed546363
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr118739.c
@@ -0,0 +1,50 @@
+/* PR rtl-optimization/118739 */
+/* { dg-do run } */
+/* { dg-options "-O3 -fno-tree-forwprop -fno-tree-vrp" } */
+
+volatile int a;
+int b, c, d = 1, e, f, g;
+
+int h (void)
+{
+  int i = 1;
+
+ j:
+  for (b = 1; b; b--)
+    {
+      asm ("#");
+
+      g = 0;
+
+      for (; g <= 1; g++)
+       {
+         int k = f = 0;
+
+         for (; f <= 1; f++)
+           k = (1 == i) >= k || ((d = 0) >= a) + k;
+       }
+    }
+
+  for (; i < 3; i++)
+    {
+      if (!c)
+       return g;
+
+      if (e)
+       goto j;
+
+      asm ("#");
+    }
+
+  return 0;
+}
+
+int main()
+{
+  h();
+
+  if (d != 1)
+    __builtin_abort();
+
+  return 0;
+}

Reply via email to