https://gcc.gnu.org/bugzilla/show_bug.cgi?id=128200
Bug ID: 128200
Summary: [x86-64] Failure to vectorize a double-to-long
converting store loop
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 simple loop that loads `double` values from an
array of structs, converts them to `long`, and stores them to a `long` array,
on x86-64, reporting `no vectype for stmt: _4 = _3->v; scalar_type: const
double`.
Clang 22.1.0 successfully vectorizes the same loop with a vectorization width
of 4 and an interleaved count of 4, without requiring an explicit vectorization
pragma.
## Test case
```c
typedef struct {
double v;
} elem;
void
foo(const elem *data, long *out, int n)
{
for (int i = 0; i < n; i += 1)
{
out[i] = data[i].v;
}
}
```
## 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: _4 = _3->v;
scalar_type: const double
<source>:6:1: note: vectorized 0 loops in function.
<source>:12:1: note: ***** Analysis failed with vector mode V4DF
<source>:12:1: note: ***** Skipping vector mode V32QI, which would repeat the
analysis for V4DF
```
GCC generates a scalar loop with a scalar `vcvttsd2si` and a scalar store per
iteration:
```asm
foo(elem const*, long*, int):
test edx, edx
jle .L5
mov edx, edx
xor eax, eax
sal rdx, 3
.L3:
vcvttsd2si rcx, QWORD PTR [rdi+rax]
mov QWORD PTR [rsi+rax], rcx
add rax, 8
cmp rax, rdx
jne .L3
.L5:
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: vectorized loop (vectorization width: 4, interleaved
count: 4) [-Rpass=loop-vectorize]
```
The generated assembly uses AVX2 instructions to load four `double` values at a
time, convert them with `vcvttsd2si`, pack them into vector registers with
`vpunpcklqdq`, and store them with `vmovdqu`. Relevant excerpt — the vectorized
main loop:
```asm
; main vectorized loop: 16 doubles per iteration (4x4 interleaved),
; converted with vcvttsd2si and stored as long with vmovdqu
.LBB0_6:
vcvttsd2si r9, qword ptr [rdi + r8 + 8]
vcvttsd2si r10, qword ptr [rdi + r8]
vmovq xmm0, r9
vcvttsd2si r9, qword ptr [rdi + r8 + 24]
vmovq xmm1, r10
vcvttsd2si r10, qword ptr [rdi + r8 + 16]
vmovq xmm2, r9
vpunpcklqdq xmm0, xmm1, xmm0
vmovq xmm1, r10
vpunpcklqdq xmm1, xmm1, xmm2
...
vmovdqu xmmword ptr [rsi + r8 + 16], xmm1
vmovdqu xmmword ptr [rsi + r8], xmm0
vmovdqu xmmword ptr [rsi + r8 + 32], xmm3
vmovdqu xmmword ptr [rsi + r8 + 48], xmm2
vmovdqu xmmword ptr [rsi + r8 + 64], xmm5
vmovdqu xmmword ptr [rsi + r8 + 80], xmm4
vmovdqu xmmword ptr [rsi + r8 + 96], xmm7
vmovdqu xmmword ptr [rsi + r8 + 112], xmm6
sub r8, -128
cmp rdx, r8
jne .LBB0_6
```
The `vcvttsd2si` / `vpunpcklqdq` / `vmovdqu` sequence shows Clang vectorizing
the `double -> long` conversion and the packed store, processing 16 elements
per iteration (vectorization width 4, interleaved count 4).
## Additional observations
The following variants were tested (each recompiled and re-checked; the
criterion was that GCC remains unvectorized and does not fall back to SLP
vectorization of the loop body, while Clang still vectorizes):
1. **The loop direction is irrelevant.** A forward loop (`i += 1`) reproduces
the failure identically to the original reverse loop (`i -= 1`).
2. **`__restrict__` is irrelevant.** Removing `__restrict__` from both pointers
does not change the GCC/Clang divergence.
3. **The explicit `(long)` cast is irrelevant.** Using an implicit `double ->
long` conversion in the assignment reproduces the failure identically.
4. **The function signature is irrelevant.** The failure reproduces with a
`void` return type, so no return value is needed in the reproducer.
5. The failure maybe appears to occur early in the vectorizer, during data-ref
analysis
## Live examples
GCC:
https://godbolt.org/z/s9h8sPYrs
Clang:
https://godbolt.org/z/4zsehfvPE