https://gcc.gnu.org/g:b7b8307893ef0b6a2a0565d75af831cca4c9511a
commit r14-11376-gb7b8307893ef0b6a2a0565d75af831cca4c9511a Author: Uros Bizjak <ubiz...@gmail.com> Date: Wed Feb 12 11:19:57 2025 +0100 combine: Discard REG_UNUSED note in i2 when register is also referenced in i3 [PR118739] 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. (cherry picked from commit a92dc3fe31c95d56019b2fb95a58414bca06241f) Diff: --- gcc/combine.cc | 15 +++++----- gcc/testsuite/gcc.target/i386/pr118739.c | 50 ++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/gcc/combine.cc b/gcc/combine.cc index a40b295bd0db..8ce8e0696ff0 100644 --- a/gcc/combine.cc +++ b/gcc/combine.cc @@ -14485,14 +14485,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 000000000000..89bed5463639 --- /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; +}