https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118739
--- Comment #14 from Uroš Bizjak <ubizjak at gmail dot com> --- Untested patch: --cut here-- diff --git a/gcc/combine.cc b/gcc/combine.cc index 3beeb514b81..99cd64ada1f 100644 --- a/gcc/combine.cc +++ b/gcc/combine.cc @@ -14559,7 +14559,8 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2, referenced in i3) that it's unused, just as it was unused before, and we place the note in i2. */ if (from_insn != i3 && i2 && INSN_P (i2) - && reg_referenced_p (XEXP (note, 0), PATTERN (i2))) + && reg_referenced_p (XEXP (note, 0), PATTERN (i2)) + && !reg_referenced_p (XEXP (note, 0), PATTERN (i3))) { if (!reg_set_p (XEXP (note, 0), PATTERN (i2))) PUT_REG_NOTE_KIND (note, REG_DEAD); --cut here-- The combine 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: 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. 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() with: --cut here-- /* Otherwise, if this register is now referenced in i2 then the register used to be modified in one of the original insns. If it was i3 (say, in an unused parallel), it's now completely gone, so the note can be discarded. But if it was modified in i2, i1 or i0 and we still reference it in i2, then we're referencing the previous value, and since the register was modified and REG_UNUSED, we know that the previous value is now dead. So, if we only reference the register in i2, we change the note to REG_DEAD, to reflect the previous value. However, if we're also setting or clobbering the register as scratch, we know (because the register was not referenced in i3) that it's unused, just as it was unused before, and we place the note in i2. */ if (from_insn != i3 && i2 && INSN_P (i2) && reg_referenced_p (XEXP (note, 0), PATTERN (i2))) { if (!reg_set_p (XEXP (note, 0), PATTERN (i2))) PUT_REG_NOTE_KIND (note, REG_DEAD); if (! (REG_P (XEXP (note, 0)) ? find_regno_note (i2, REG_NOTE_KIND (note), REGNO (XEXP (note, 0))) : find_reg_note (i2, REG_NOTE_KIND (note), XEXP (note, 0)))) place = i2; } --cut here-- However (and as shown in Comment #11) the flags register is far from UNUSED (let alone DEAD), because it is used in i3. So, the proposed solution is to simply remove REG_UNUSED or REG_DEAD notes when the register is also mentioned in i3.