https://gcc.gnu.org/g:e1b8d097297d6375eb42fc05b46dc13236a63404

commit r16-6062-ge1b8d097297d6375eb42fc05b46dc13236a63404
Author: Jakub Jelinek <[email protected]>
Date:   Fri Dec 12 15:18:08 2025 +0100

    rtlanal: Use REG_UNUSED notes in single_set only in passes where df_analyze 
has computed them [PR121852]
    
    REG_UNUSED and REG_DEAD notes are only valid when computed by df
    with df_note_add_problem () before df_analyze ().
    Generally, especially CSE/GCSE optimizations can invalidate those
    notes by reusing the REG_UNUSED results later on, unfortunately dropping
    REG_UNUSED notes in such cases is not very easy.
    See e.g. PR113059 and PR40209 for additional details.
    
    Most users of REG_UNUSED/REG_DEAD notes add the note problems, but
    single_set function is called from many of the passes and requiring
    that df_note_add_problem () is done in each such a case would be very
    slow and would need some checking.
    
    The following patch instead limits the use of REG_UNUSED notes to
    passes which have the note problem computed (i.e. df && df_note), and
    for pseudos as a fallback uses DF_REG_USE_COUNT == 0 check if at least
    df is computed.
    
    2025-12-12  Jakub Jelinek  <[email protected]>
    
            PR rtl-optimization/121852
            * rtlanal.cc (single_set_2): Only look for REG_UNUSED notes if
            df && df_note, otherwise if df and SET_DEST is a pseudo with
            DF_REG_USE_COUNT 0, assume it is unused as well.  Otherwise
            assume it may be used.
    
            * gcc.dg/pr121852.c: New test.

Diff:
---
 gcc/rtlanal.cc                  | 22 ++++++++++++------
 gcc/testsuite/gcc.dg/pr121852.c | 49 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 64 insertions(+), 7 deletions(-)

diff --git a/gcc/rtlanal.cc b/gcc/rtlanal.cc
index 63a1d08c46cf..1a754f8dff88 100644
--- a/gcc/rtlanal.cc
+++ b/gcc/rtlanal.cc
@@ -1546,6 +1546,9 @@ single_set_2 (const rtx_insn *insn, const_rtx pat)
            case CLOBBER:
              break;
 
+           default:
+             return NULL_RTX;
+
            case SET:
              /* We can consider insns having multiple sets, where all
                 but one are dead as single set insns.  In common case
@@ -1555,23 +1558,28 @@ single_set_2 (const rtx_insn *insn, const_rtx pat)
                 When we reach set first time, we just expect this is
                 the single set we are looking for and only when more
                 sets are found in the insn, we check them.  */
+             auto unused = [] (const rtx_insn *insn, rtx dest) {
+               if (!df)
+                 return false;
+               if (df_note)
+                 return !!find_reg_note (insn, REG_UNUSED, dest);
+               return (REG_P (dest)
+                       && !HARD_REGISTER_P (dest)
+                       && REGNO (dest) < df->regs_inited
+                       && DF_REG_USE_COUNT (REGNO (dest)) == 0);
+             };
              if (!set_verified)
                {
-                 if (find_reg_note (insn, REG_UNUSED, SET_DEST (set))
-                     && !side_effects_p (set))
+                 if (unused (insn, SET_DEST (set)) && !side_effects_p (set))
                    set = NULL;
                  else
                    set_verified = 1;
                }
              if (!set)
                set = sub, set_verified = 0;
-             else if (!find_reg_note (insn, REG_UNUSED, SET_DEST (sub))
-                      || side_effects_p (sub))
+             else if (!unused (insn, SET_DEST (sub)) || side_effects_p (sub))
                return NULL_RTX;
              break;
-
-           default:
-             return NULL_RTX;
            }
        }
     }
diff --git a/gcc/testsuite/gcc.dg/pr121852.c b/gcc/testsuite/gcc.dg/pr121852.c
new file mode 100644
index 000000000000..d5e3ffcd5fe2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr121852.c
@@ -0,0 +1,49 @@
+/* PR rtl-optimization/121852 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fno-gcse" } */
+
+int a[] = { 0 }, d, e, h, i, j, k, l, n[1], *o = n;
+volatile int m;
+
+int
+foo (char q)
+{
+  return a[e ^ (q & 5)];
+}
+
+int
+bar (int q[])
+{
+  int b = 5;
+  for (int g = 0; g < d; ++g)
+    {
+      int c = foo (q[g] >> 6);
+      int f = (c & 4095) ^ a[c & 5];
+      b = f;
+    }
+  return b;
+}
+
+int
+baz (volatile int q)
+{
+  k = 5 % q;
+  int r[] = { h, i, k, j };
+  return bar (r);
+}
+
+int
+main ()
+{
+  int t;
+  do
+    {
+      if (baz (5))
+       m = 4;
+      l--;
+      t = l - 1 % m + 1;
+    }
+  while (!baz (5));
+  o[0] = 2 % t;
+  return 0;
+}

Reply via email to