https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111000

--- Comment #6 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Jeff Law <[email protected]>:

https://gcc.gnu.org/g:58bf8a355a73b7fbc6d7bfebcc7281b3cdadd4da

commit r17-3550-g58bf8a355a73b7fbc6d7bfebcc7281b3cdadd4da
Author: Dominic P <[email protected]>
Date:   Sat Aug 22 20:05:35 2026 -0600

    [PATCH 1/3] tree-optimization: hoist shifts by an in-range constant count

    movement_possibility_1 restricts shifts and rotates to
    MOVE_PRESERVE_EXECUTION so that a count which is out of range is never
    speculatively executed.  The test was inverted: wi::ltu_p (count,
    precision) is true exactly when the count is in range and the shift is
    perfectly well defined, so it was the well-defined shifts that were
    pinned, while a constant count >= precision - the undefined case the
    comment describes - fell through as MOVE_POSSIBLE.

    The restriction was added by r14-4786-gd118738e71cf46 (PR111000), whose
    concern is a count that cannot be proven in range - there, hoisting can
    introduce an undefined shift on a path that never executed it.  That
    case is unaffected here: a non-INTEGER_CST count still takes the
    MOVE_PRESERVE_EXECUTION path through the first half of the disjunct, and
    gcc.dg/torture/pr111000.c still passes, and compiles to identical code
    before and after.

    compute_invariantness skips a MOVE_PRESERVE_EXECUTION statement whenever
    the block may not execute, and outermost_invariant_loop then returns
    NULL for its result, so the entire invariant chain rooted at such a
    shift was pinned with it.  In the new testcase the multiply and the
    divide then stay in the loop as well.

    How much of this reaches the emitted code varies.  It is clearest where
    the division survives as a libcall by a constant divisor: on
    arm-none-eabi at -Os -mcpu=arm1176jzf-s the bl __aeabi_idiv sits inside
    the loop body before this change and above the loop after it, and the
    register save list shrinks from eight registers to six.  Where the
    division is expanded inline the RTL loop-invariant pass can recover the
    motion on its own - at -O2 that same function is byte for byte identical
    before and after - and a non-constant divisor stays pinned either way as
    possibly trapping.  Hoisting earlier can also cost a little code size
    where it raises register pressure: a loop body with several such chains
    under one guard grows on Thumb at -Os, because the hoisted values are
    live across the loop.  The GIMPLE-level change is what the testcase
    checks.

    The series was bootstrapped on x86_64-pc-linux-gnu at trunk 7f549ea2b47
    with the stage2/stage3 comparison successful, and a full make check shows
    no regressions: 227924 gcc and 278399 g++ expected passes, and every one
    of the 112 unexpected results also occurs with the series reverted.  With
the
    patch reverted and the test kept, the lim2 dump moves
    no statements instead of three.

    Assisted-by: Claude Opus 5 (Anthropic)

            PR tree-optimization/111000
    gcc/ChangeLog:

            * tree-ssa-loop-im.cc (movement_possibility_1): Require
            MOVE_PRESERVE_EXECUTION for an out-of-range constant shift
            count, not an in-range one.

    gcc/testsuite/ChangeLog:

            * gcc.dg/tree-ssa/loop-im-shift-1.c: New test.

    Signed-off-by: Dominic P <[email protected]>

Reply via email to