https://gcc.gnu.org/bugzilla/show_bug.cgi?id=125375
--- Comment #20 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The trunk branch has been updated by Richard Sandiford <[email protected]>: https://gcc.gnu.org/g:3f4f26849bc42374d9b07df045cd172bd37dfbfa commit r17-676-g3f4f26849bc42374d9b07df045cd172bd37dfbfa Author: Richard Sandiford <[email protected]> Date: Fri May 22 16:27:31 2026 +0100 cfgrtl: Forbid forwarder blocks from having clobbers [PR125375] In this testcase, jump2 was presented with: L1: set the return register do epilogue stuff goto L4 L2: do the same epilogue stuff L3: clobber the return register goto L4 The question then is: is the L3 block a forwarder block? It is a forwarder block in the sense that a jump to L3 can be replaced with a jump to L4. But it isn't a forwarder block in the sense of a jump to L3 being equivalent to a jump to L4. In particular, a jump to L4 cannot be merged with a jump or fallthrough to L3 unless we can prove that the clobber is valid for both paths. In the testcase, L3 was marked as a forwarder block and so cross-jumping created: L1: set the return register L2: do epilogue stuff L3: clobber the return register goto L4 The set of the return register was then inevitably deleted as dead. The clobber in this case is of the return register. But the same principle/problem would apply to any clobber. We can't introduce new clobbers on a path without proving that the clobbered thing is dead. This question arises due to an old quirk of active_insn_p that predates CVS history: bool active_insn_p (const rtx_insn *insn) { return (CALL_P (insn) || JUMP_P (insn) || JUMP_TABLE_DATA_P (insn) /* FIXME */ || (NONJUMP_INSN_P (insn) && (! reload_completed || (GET_CODE (PATTERN (insn)) != USE && GET_CODE (PATTERN (insn)) != CLOBBER)))); } Thus a clobber is "active" before RA but not after it. This means that, according to flow_active_insn_p, a block with a clobber is not a forwarder block before RA, but can be afterwards. The "most optimal" solution would probably be to split the concept of forwarder block into two, one that allows clobbers and one that doesn't. However, that would be difficult to retrofit at this stage and isn't likely to be suitable for backporting. This patch therefore takes the more conservative approach of making flow_active_insn_p treat clobbers in the same way after RA as it does before RA. Some of this infrastructure is probably ripe for updating. For example, flow might have required explicit uses of the return register, but DF should cope well enough without. We should probably also check whether the active_insn_p behaviour still makes sense. gcc/ PR rtl-optimization/125375 * cfgrtl.cc (flow_active_insn_p): Return true for clobbers. gcc/testsuite/ * gcc.dg/pr125375.c: New test.
