https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127661
--- Comment #2 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The master branch has been updated by Kyrylo Tkachov <[email protected]>: https://gcc.gnu.org/g:a6b623a8eb41dd485c8b3b9fb92c50f551a486b7 commit r17-4986-ga6b623a8eb41dd485c8b3b9fb92c50f551a486b7 Author: Kyrylo Tkachov <[email protected]> Date: Tue Sep 29 16:58:49 2026 +0200 cprop: Do not queue dead CC setters when bypassing jumps [PR127661] The testcase in the PR is a long chain of if (v == 0) c->hit (0); if (v == 1) c->hit (1); ... At -O2 almost all of its compile time goes to jump bypassing in cprop1. The GIMPLE threaders move the edge after each call only a few tests forward. bypass_block then redirects each such edge to the next conditional block, which the forward sweep of bypass_conditional_jumps visits later, so a chain of N tests gives about N*N/2 redirections. Each redirection queues a copy of the flags setter of the bypassed block on the edge. The copies are dead, because the next block sets the flags again, but reg_killed_on_edge and insert_insn_on_edge walk the whole queue of the edge at each step, and commit_edge_insertions adds about N*N/2 dead compares. In gcc.target/aarch64/pr127661.c the block of the first call ends up as: (call_insn 10 ... (call (mem:DI (symbol_ref:DI ("f")) ...) ...)) (insn 76 ... (set (reg:CC 66 cc) (compare:CC (reg/v:SI 101 [ v ]) (const_int 1)))) (insn 78 ... (set (reg:CC 66 cc) (compare:CC (reg/v:SI 101 [ v ]) (const_int 2)))) ... five more compares, with the constants 3 to 7 ... This patch copies the setter only if it is needed on entry to the new destination, that is if it has side effects, can throw, or sets a register that is live there or is not a condition-code register. Setters of other registers are always copied, because debug insns and REG_EQUAL notes, which the liveness information ignores, can refer to them. The comment of bypass_setcc_needed_p explains why the liveness information, which predates the global propagation and the redirections, is safe to use. With the patch the block above contains only the call. gcc.dg/pr127661.c and gcc.target/aarch64/pr127661-2.c check that the copy stays when the flags are live at the new destination. For the testcase at N=2048 on Grace the compile time drops by 95% and the peak memory use by 78%. For the variant with the calls inlined the compile time at N=1024 drops by 92%. Dead copies no longer stop the bypass of an outgoing edge, so the patch can add redirections, but it adds none for the testcase, and the assembly output does not change for N from 64 to 2048. Bootstrapped and tested as a series on aarch64-linux-gnu and x86_64-linux-gnu. gcc/ChangeLog: PR rtl-optimization/127661 * cprop.cc (bypass_setcc_needed_p): New function. (bypass_block): Use it to decide whether to copy SETCC onto a redirected edge. (bypass_conditional_jumps): Update comment. gcc/testsuite/ChangeLog: PR rtl-optimization/127661 * gcc.dg/pr127661.c: New test. * gcc.target/aarch64/pr127661.c: New test. * gcc.target/aarch64/pr127661-2.c: New test. * gcc.target/i386/pr127661.c: New test. Signed-off-by: Kyrylo Tkachov <[email protected]>
