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;
+}

Reply via email to