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

            Bug ID: 128325
           Summary: wrong code with --param=vect-partial-vector-usage=2:
                    masked alignment peeling starts a shift induction two
                    steps ahead
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Keywords: wrong-code
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: dohanam2 at illinois dot edu
  Target Milestone: ---

With masked (partial-vector) peeling for alignment, a `x <<= 1` induction gets
the wrong start value: lane j of the first vector holds `x << (j + 1)`, but
lane j is iteration j - 1, which needs `x << (j - 1)`.

```c
__attribute__((noipa)) void
f (unsigned *d, unsigned x)
{
  d = __builtin_assume_aligned (d, 64, 4);
  for (int i = 0; i < 97; i++)
    {
      d[i] = x;
      x <<= 1;
    }
}

int
main (void)
{
  static unsigned buf[128] __attribute__((aligned (64)));
  f (buf + 1, 1);
  for (int i = 0; i < 97; i++)
    if (buf[i + 1] != (i < 32 ? 1u << i : 0))
      __builtin_abort ();
  return 0;
}
```

```
gcc -O3 -mavx512f --param=vect-partial-vector-usage=2 -fno-vect-cost-model t.c
```

Trunk at 44c0f794dd4129f279ca9010955095307b981b55 (which has the PR128267 fix)
emits for `f`:

```
        leal    (%rsi,%rsi), %eax
        kmovw   .LC2(%rip), %k2
        vpbroadcastd    %eax, %zmm0
        movl    $-2, %eax
        vpsllvd .LC0(%rip), %zmm0, %zmm0
        kmovw   %eax, %k1
        vmovdqa32       %zmm0, -4(%rdi){%k1}
```

`.LC0` is `{0, 1, ..., 15}`. The store goes to `-4(%rdi)`, i.e. `d - 1`, with
lane 0 masked off, so lane 1 is `d[0]` and gets `(2 * x) << 1 = 4 * x` instead
of `x`. The vect dump shows the same:

```
_6 = {x_9(D) << 1, x_9(D) << 1, ...};
_5 = _6 << { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
vectp_d.8_24 = d_8 + 18446744073709551612;
loop_mask_27 = PHI <_33(5), { 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1 }(6)>
```

I could not run it: this machine has no AVX-512. Built with this trunk, the
program passes at -O0 and at -O3 -mavx2. Without
`--param=vect-partial-vector-usage=2`, or with the default cost model, the loop
is not peeled with a mask and the code is fine. `x >>= 1` goes wrong the same
way.

It looks like `vect_peel_nonlinear_iv_init` moves the shl/shr start forward by
step * skip for `LOOP_VINFO_MASK_SKIP_NITERS`, but with masked peeling the
first vector starts skip iterations before iteration 0, so the start would have
to move back instead. A shift cannot be undone exactly, so perhaps such loops
should not be peeled with a mask at all.

Found with an LLM-based testing tool; I used Claude to reduce it and look for
the cause.
  • [Bug tree-optimization/128325] N... dohanam2 at illinois dot edu via Gcc-bugs

Reply via email to