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
