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.
  • [Bug tree-optimization/12721... stevebezalel215 at gmail dot com via Gcc-bugs

Reply via email to