[Bug target/124895] during RTL pass: narrow_gp_writes ICE: in df_lr_verify_transfer_functions, at df-problems.cc:1359 with -mnarrow-gp-writes
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124895 Drea Pinski changed: What|Removed |Added Target Milestone|--- |16.2
[Bug target/124895] during RTL pass: narrow_gp_writes ICE: in df_lr_verify_transfer_functions, at df-problems.cc:1359 with -mnarrow-gp-writes
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124895 --- Comment #12 from GCC Commits --- The releases/gcc-16 branch has been updated by Soumya AR : https://gcc.gnu.org/g:72010b551750e4846e67203e314866b1a63b8e4c commit r16-8963-g72010b551750e4846e67203e314866b1a63b8e4c Author: Soumya AR Date: Wed May 6 05:39:55 2026 + aarch64: Move pass_narrow_gp_writes above pass_free_cfg The narrow_gp_writes pass uses RTL-SSA and updates DF state via df_insn_rescan / df_insn_delete. Both routines look up the insn's bb via BLOCK_FOR_INSN to mark it dirty after a change, but pass_free_cfg has already cleared those per-insn pointers by the time narrow_gp_writes runs. When BLOCK_FOR_INSN returns NULL, the dirty-marking step is silently skipped, leaving the DF stale. Move the pass to run before pass_free_cfg. Bootstrapped and regtested on aarch64-linux-gnu. SPEC CPU 2017 shows no codegen differences (compared to previous placement). OK for trunk? Signed-off-by: Soumya AR PR target/124895 gcc/ChangeLog: * config/aarch64/aarch64-passes.def (pass_narrow_gp_writes): Move pass before pass_free_cfg. gcc/testsuite/ChangeLog: * gcc.target/aarch64/narrow-gp-writes-8.c: New test. (cherry picked from commit cefcc09723c363f61e65f9a2774f82258fc43474)
[Bug target/124895] during RTL pass: narrow_gp_writes ICE: in df_lr_verify_transfer_functions, at df-problems.cc:1359 with -mnarrow-gp-writes
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124895 Soumya AR changed: What|Removed |Added Resolution|--- |FIXED Status|ASSIGNED|RESOLVED --- Comment #11 from Soumya AR --- .
[Bug target/124895] during RTL pass: narrow_gp_writes ICE: in df_lr_verify_transfer_functions, at df-problems.cc:1359 with -mnarrow-gp-writes
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124895 --- Comment #10 from Soumya AR --- Fixed.
[Bug target/124895] during RTL pass: narrow_gp_writes ICE: in df_lr_verify_transfer_functions, at df-problems.cc:1359 with -mnarrow-gp-writes
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124895 --- Comment #9 from GCC Commits --- The master branch has been updated by Soumya AR : https://gcc.gnu.org/g:cefcc09723c363f61e65f9a2774f82258fc43474 commit r17-399-gcefcc09723c363f61e65f9a2774f82258fc43474 Author: Soumya AR Date: Wed May 6 05:39:55 2026 + aarch64: Move pass_narrow_gp_writes above pass_free_cfg The narrow_gp_writes pass uses RTL-SSA and updates DF state via df_insn_rescan / df_insn_delete. Both routines look up the insn's bb via BLOCK_FOR_INSN to mark it dirty after a change, but pass_free_cfg has already cleared those per-insn pointers by the time narrow_gp_writes runs. When BLOCK_FOR_INSN returns NULL, the dirty-marking step is silently skipped, leaving the DF stale. Move the pass to run before pass_free_cfg. Bootstrapped and regtested on aarch64-linux-gnu. SPEC CPU 2017 shows no codegen differences (compared to previous placement). OK for trunk? Signed-off-by: Soumya AR PR target/124895 gcc/ChangeLog: * config/aarch64/aarch64-passes.def (pass_narrow_gp_writes): Move pass before pass_free_cfg. gcc/testsuite/ChangeLog: * gcc.target/aarch64/narrow-gp-writes-8.c: New test.
[Bug target/124895] during RTL pass: narrow_gp_writes ICE: in df_lr_verify_transfer_functions, at df-problems.cc:1359 with -mnarrow-gp-writes
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124895 ktkachov at gcc dot gnu.org changed: What|Removed |Added CC||ktkachov at gcc dot gnu.org --- Comment #8 from ktkachov at gcc dot gnu.org --- (In reply to Soumya AR from comment #4) > I compiled SPEC2017 and saw 0 codegen differences after moving the pass > above pass_free_cfg. Same with GCC bootstrap. > > I also ran a GCC bootstrap with --enable-checking=all and that came clean as > well so I think moving the pass up should be safe. > > I'll push the fix for GCC17 then? Makes sense to me, but please post the patch to gcc-patches for review and archival as per the usual process
[Bug target/124895] during RTL pass: narrow_gp_writes ICE: in df_lr_verify_transfer_functions, at df-problems.cc:1359 with -mnarrow-gp-writes
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124895 --- Comment #7 from Sam James --- Thanks!
[Bug target/124895] during RTL pass: narrow_gp_writes ICE: in df_lr_verify_transfer_functions, at df-problems.cc:1359 with -mnarrow-gp-writes
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124895 --- Comment #6 from Soumya AR --- The latter. -mcpu=olympus when building SPEC and --with-cpu=olympus when configuring GCC for bootstrap. With O2 that triggers it by default. Although I did also add -fdump-rtl-narrow_gp_writes in both tests to verify the pass actually fired.
[Bug target/124895] during RTL pass: narrow_gp_writes ICE: in df_lr_verify_transfer_functions, at df-problems.cc:1359 with -mnarrow-gp-writes
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124895 --- Comment #5 from Sam James --- Out of interest, was that with -mnarrow-gp-writes enabled by default or otherwise definitely enabled duriaarch64_narrow_gp_writesng the bootstrap, or some -mcpu= which triggers it?
[Bug target/124895] during RTL pass: narrow_gp_writes ICE: in df_lr_verify_transfer_functions, at df-problems.cc:1359 with -mnarrow-gp-writes
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124895 --- Comment #4 from Soumya AR --- I compiled SPEC2017 and saw 0 codegen differences after moving the pass above pass_free_cfg. Same with GCC bootstrap. I also ran a GCC bootstrap with --enable-checking=all and that came clean as well so I think moving the pass up should be safe. I'll push the fix for GCC17 then?
[Bug target/124895] during RTL pass: narrow_gp_writes ICE: in df_lr_verify_transfer_functions, at df-problems.cc:1359 with -mnarrow-gp-writes
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124895 --- Comment #3 from Alex Coplan --- Thanks for the detailed analysis. Moving the pass above pass_free_cfg sounds like the correct fix to me too, and looking at the pass list I don't think it should be too invasive. I'd hope to see minimal codegen changes with such a change, perhaps you could verify that by compiling some benchmarks with -mnarrow-gp-writes and comparing binaries before/after that change? I tend to agree that we should stage the fix on trunk (perhaps once 16.1 has been released, since we can then enable the pass by default), and then backport to 16.2 if there's no fallout after a week or two.
[Bug target/124895] during RTL pass: narrow_gp_writes ICE: in df_lr_verify_transfer_functions, at df-problems.cc:1359 with -mnarrow-gp-writes
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124895 --- Comment #2 from Soumya AR --- The main issue here is that this pass runs after pass_free_cfg in an effort to run it as late as possible. But pass_free_cfg nulls the per-insn BLOCK_FOR_INSN pointer. RTL-SSA and DF rely on those to maintain bookkeeping when insns are modified, so the pass shouldn't be using them in this region. The correct fix would be to move this pass above pass_free_cfg. But that would require wider testing. Maybe we can push that to trunk and backport to GCC16.2 after the testing on trunk? Detailed analysis below: - For this particular test, -fpath-coverage and -fprofile-generate together produce a redundant AND instruction. At some point we have a PHI node whose result feeds an AND with 0x78. The PHI's inputs are 0x18 and 0x60, so when nonzero_bits ORs the masks of the PHI inputs we get exactly 0x78, making the AND redundant. This redundant operation would have ideally been folded by CCP in the middle-end, except -fno-tree-ccp makes it survive to late RTL. This later gets simplified to a set x0 x0 and marked as a noop. In the dtor, crtl->ssa->perform_pending_updates() walks the queue and calls ::delete_insn(rtl) for each queued noop. This calls df_insn_delete(insn), which tries to find the insn's BB via BLOCK_FOR_INSN(insn). But bb = BLOCK_FOR_INSN(insn) = NULL here since this runs after pass_free_cfg. With bb == NULL, df_insn_delete skips df_set_bb_dirty(bb) (it has a NULL-bb guard) but still runs df_insn_info_delete(uid) unconditionally. This bb's cached def bitmap is now stale, but the bb is not in df_lr->out_of_date_transfer_functions (set by df_set_bb_dirty), so DF still considers it clean. df_lr_verify_transfer_functions audits every BB not on the dirty list. It recomputes a new bitmap from the current insns and compares with its cached bitmap, skipping the dirty function bits. But since our modified BB was never set to dirty, bitmap_equal_p fails and causes the ICE. - There is another latent bug which this ICE exposes: for non-noop narrowings, the same BLOCK_FOR_INSN == NULL makes df_insn_rescan bail. For the passes that run afterwards this is OK because the regnums in the stale refs still match the new PATTERN's regnums, but if any future pass queried something else (e.g. the mode) it would get the pre-narrowing answer. - We can also fix this ICE for 16.1, if necessary, by just skipping narrowings that could result in a noop. This would be a lot less invasive and can be used as a band-aid until the real fix is tested.
[Bug target/124895] during RTL pass: narrow_gp_writes ICE: in df_lr_verify_transfer_functions, at df-problems.cc:1359 with -mnarrow-gp-writes
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124895 Soumya AR changed: What|Removed |Added Ever confirmed|0 |1 Last reconfirmed||2026-04-27 Status|UNCONFIRMED |ASSIGNED Assignee|unassigned at gcc dot gnu.org |soumyaa at gcc dot gnu.org
[Bug target/124895] during RTL pass: narrow_gp_writes ICE: in df_lr_verify_transfer_functions, at df-problems.cc:1359 with -mnarrow-gp-writes
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124895 --- Comment #1 from Soumya AR --- Reproducible, assigning to myself.
