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.
/* 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,
--- /dev/null
+/* 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;
+}