On Sat, 22 Aug 2026, Jeffrey Law wrote: > > > On 8/15/2026 2:17 PM, Dominic P wrote: > > 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) > > > > gcc/ChangeLog: > > > > PR tree-optimization/111000 > > * 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]> > OK. While I might normally feel the need to ask about precisely what the LLM > was used for, in this case the patch is so trivial that I don't think it's > necessary. I'll push it to the trunk momentarily.
Oops. This also means we mis-handle out-of-range constants, meaning it qualifies for backporting. > Note this could be refined further by querying ranger for the range when the > shift count is variable. I would expect ranger to be able to determine a > useful range reasonably often. Obviously that would be an independent > followup. > > Jeff > -- Richard Biener <[email protected]> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Jochen Jaser, Andrew McDonald, Abhinav Puri; (HRB 36809, AG Nuernberg)
