https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118739

--- Comment #21 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The releases/gcc-13 branch has been updated by Uros Bizjak <u...@gcc.gnu.org>:

https://gcc.gnu.org/g:3634a7d15d94590cef313f503a32d4698276fd04

commit r13-9413-g3634a7d15d94590cef313f503a32d4698276fd04
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)

Reply via email to