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]>

Reply via email to