https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127211
Bug ID: 127211
Summary: predcom fails to reset SCEV on its load-motion path
(scev_reset gated on changed > 1); stale cache blocks
ivopts
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: stevebezalel215 at gmail dot com
Target Milestone: ---
Target: x86_64-linux-gnu
int a[4096], b[4096];
void fn(int m)
{
int s = 0;
for (int i = 0; i < a[4]; i++)
{
a[3*i + 2] = m;
if (m & 1)
a[3*i + 5] = m - 1;
b[s] = m;
s += a[4];
}
}
$ gcc -O2 -fno-tree-slp-vectorize -S t.c
predcom's dr analysis queries SCEV about s while its step is still the load of
a[4], memoizing the cannot-analyze result (cached evolution of s_17 is s_17
itself). Load motion then hoists a[4] to a preheader temporary, after which s
is a provable affine IV {a_I_lsm0.4_26, +, a_I_lsm0.4_26}_1 — but the reset
only happens on the unroll path:
/* tree-predcom.cc:3511 */
if (changed > 0)
{
ret = TODO_update_ssa_only_virtuals;
/* Some loop(s) got unrolled. */
if (changed > 1)
{
scev_reset ();
so the stale entry survives to ivopts, which sees
;; niter scev_not_known
and does not turn the b[s] store into a pointer IV. The loop body keeps
movslq %ecx, %r8
addl %esi, %ecx
movl %edi, b(,%r8,4)
where a scev_reset () injected right after predcom gives
movl %edi, (%rcx)
addq %r8, %rcx
(setup hoisted to the preheader; one insn fewer per iteration in both loop
versions, equal static size). Resetting at any point before predcom instead
keeps the unimproved code, so the stale entries are predcom's own.
-fno-tree-slp-vectorize only removes accidental masking: predcom's TODO arms
pass_pre_slp_scalar_cleanup, whose FRE clears the SCEV cache before ivopts.
The changed > 1 gate is from r8-era d9c259efd71 (2017); the load-motion path
invalidates cached SCEV results just as the unroll path does, so the fix would
be to scev_reset () for changed > 0. Behavior is preserved, missed optimization
only.