Hi!

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.

Bootstrapped/regtested on x86_64-linux, i686-linux and aarch64-linux,
ok for trunk?

2025-12-11  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.

--- gcc/rtlanal.cc.jj   2025-12-10 18:04:44.154840114 +0100
+++ gcc/rtlanal.cc      2025-12-10 18:16:26.760821476 +0100
@@ -1546,6 +1546,9 @@ single_set_2 (const rtx_insn *insn, cons
            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, cons
                 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;
            }
        }
     }
--- gcc/testsuite/gcc.dg/pr121852.c.jj  2025-12-10 19:06:57.413947775 +0100
+++ gcc/testsuite/gcc.dg/pr121852.c     2025-12-10 19:05:37.350319926 +0100
@@ -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;
+}

        Jakub

Reply via email to