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

            Bug ID: 128206
           Summary: [x86-64] Failure to vectorize a loop with a carried
                    dependence and a converted scalar operand
           Product: gcc
           Version: 16.1.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: bug_hunters at yeah dot net
  Target Milestone: ---

## Description

GCC 16.1.0 fails to vectorize a loop that loads `out[i - 8]` (a carried
dependence with distance 8), adds a `char` struct member converted to `long`,
and stores the result back to a `long` array, on x86-64. GCC reports `no
vectype for stmt: ... scalar_type: long int`.

Clang 22.1.0 successfully vectorizes the same loop with a vectorization width
of 4 and an interleaved count of 1, without requiring an explicit vectorization
pragma.

The failure is not specific to floating point: the reproducer uses only integer
types. Removing the converted scalar operand, or making the struct field the
same type as the arithmetic, makes GCC vectorize the loop.

## Test case

```c
typedef struct {
    char v;
} elem;

long
foo(const elem * __restrict__ data, long * __restrict__ out, int n)
{
    for (int i = 0; i < n; i += 1)
    {
        out[i] = (i >= 8 ? out[i - 8] : 0L)
               + (long)data[i].v;
    }

    return 0;
}
```

## GCC version

```text
gcc version 16.1.0
```

## GCC options

```text
-S -O3 -ftree-vectorize -ftree-slp-vectorize -march=x86-64-v3
-fopt-info-vec-all -fvect-cost-model=unlimited 
```

## GCC output

```text
<source>:8:23: missed: couldn't vectorize loop
<source>:10:26: missed: not vectorized: no vectype for stmt: iftmp.0_35 = *_36;
 scalar_type: long int
<source>:8:23: missed: couldn't vectorize loop
<source>:10:16: missed: not vectorized: no vectype for stmt: *_9 = _7;
 scalar_type: long int
<source>:6:1: note: vectorized 0 loops in function.
<source>:11:16: note: ***** Analysis failed with vector mode V32QI
<source>:11:16: note: ***** The result for vector mode V32QI would be the same
<source>:11:16: note: ***** Re-trying analysis with vector mode V16QI
<source>:11:16: note: ***** Analysis failed with vector mode V16QI
<source>:11:16: note: ***** Re-trying analysis with vector mode V8QI
<source>:11:16: note: ***** Analysis failed with vector mode V8QI
<source>:11:16: note: ***** Re-trying analysis with vector mode V4QI
<source>:11:16: note: ***** Analysis failed with vector mode V4QI
```

GCC generates scalar code: the first eight iterations are peeled, then a scalar
loop from `i = 8`:

```asm
foo(elem const*, long*, int):
        mov     ecx, edx
        test    edx, edx
        jle     .L2
        movsx   rax, BYTE PTR [rdi]
        mov     QWORD PTR [rsi], rax
        cmp     edx, 1
        je      .L2
        movsx   rax, BYTE PTR [rdi+1]
        mov     QWORD PTR [rsi+8], rax
        ...
        movsx   rax, BYTE PTR [rdi+7]
        mov     QWORD PTR [rsi+56], rax
        cmp     edx, 8
        je      .L2
        mov     eax, 8
.L3:
        movsx   rdx, BYTE PTR [rdi+rax]
        add     rdx, QWORD PTR [rsi-64+rax*8]
        mov     QWORD PTR [rsi+rax*8], rdx
        add     rax, 1
        cmp     ecx, eax
        jg      .L3
.L2:
        xor     eax, eax
        ret
```

## Comparison with Clang

### Clang version

```text
clang version 22.1.0
LLVM commit:
4434dabb69916856b824f68a64b029c67175e532
```

Clang options:

```text
-S -O3 -ftree-vectorize -ftree-slp-vectorize --target=x86_64-linux-gnu
-march=x86-64-v3 -Rpass=.*vectorize.* -Rpass-missed=.*vectorize.*
-Rpass-analysis=.*vectorize.*
```

Clang reports:

```text
<source>:8:5: remark: the cost-model indicates that interleaving is not
beneficial [-Rpass-analysis=loop-vectorize]
<source>:8:5: remark: vectorized loop (vectorization width: 4, interleaved
count: 1) [-Rpass=loop-vectorize]
```

The generated assembly uses AVX2 instructions: `vpcmpgtq` + `vpmaskmovq` handle
the `i >= 8` guard for the carried load of `out[i - 8]`, `vpmovsxbq`
sign-extends the `char` member to `long`, and `vpaddq` / `vmovdqu` compute and
store four results at a time:

```asm
; main vectorized loop: masked load of out[i-8], sign-extend char, add, store
.LBB0_4:
        vpxor   ymm4, ymm0, ymm1
        vpcmpgtq        ymm4, ymm4, ymm2
        vpmaskmovq      ymm4, ymm4, ymmword ptr [rsi + 8*rdx - 64]
        vpmovsxbq       ymm5, dword ptr [rdi + rdx]
        vpaddq  ymm4, ymm4, ymm5
        vmovdqu ymmword ptr [rsi + 8*rdx], ymm4
        add     rdx, 4
        vpaddq  ymm0, ymm0, ymm3
        cmp     rcx, rdx
        jne     .LBB0_4
```

The `vpcmpgtq` / `vpmaskmovq` sequence implements the `i >= 8` guard for the
carried load, `vpmovsxbq` performs the `char` to `long` conversion, and
`vmovdqu` stores 4 results at a time.

## Additional observations

The following variants were tested:

1. **The failure is not specific to floating point.** The reproducer uses only
`char` and `long`; GCC reports `no vectype for stmt ... scalar_type: long int`.
The same failure reproduces with `double` (`scalar_type: double`), so
floating-point arithmetic and strict-fp settings are not the cause.
2. **The converted scalar operand is essential.** Removing the `+
(long)data[i].v` term (leaving only the carried load `out[i - 8]`) makes GCC
vectorize the loop.
3. **The conversion is essential.** If the struct field is changed to `long`
(so no conversion is needed), i.e. `out[i] = (i >= 8 ? out[i - 8] : 0L) +
data[i].v;`, GCC vectorizes the loop.
4. **The dependence distance is not essential.** A distance of 4 instead of 8
reproduces the failure identically.
5. **A constant addend is not essential.** Removing an extra `+ 2` constant
term from the original test case does not change the divergence.

The failure appears to be in the vectorizer's vectype determination for the
carried load / store when the stored value combines a dependence-carried load
with a type-converted scalar operand.

## Live examples

GCC:
https://godbolt.org/z/vaK8T1rb9

Clang:
https://godbolt.org/z/6r3dKqWen

Reply via email to