llvm / llvm/llvm-project

[LoopVectorize][AArch64] Missed SVE vectorization for mixed-type prefix sum (GCC partially vectorizes via loop distribution)

Open
#192,444 1 comment 0 reactions 0 assignees View on GitHub
backend:AArch64 missed-optimization SVE vectorizers
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

**Description:**

Clang fails to auto-vectorize a loop containing a backward loop-carried dependence (prefix sum pattern) with mixed-type conversions on AArch64 with SVE enabled, while GCC successfully partially vectorizes the same loop under identical compilation flags.

The loop in question computes out[i] = out[i-1] + (char)a[i] + (char)b[i] where a is const long *, b is const double *, and out is char *, creating a backward dependence with distance -1 on the out array. Although backward dependences typically prevent vectorization, GCC demonstrates that the data loading, type conversions (double → int via fcvtzs), and element-wise addition of a[i] + b[i] can be aggressively vectorized using SVE predicated operations and packed into a single char vector via uzp1 instructions, processing up to 8 vector blocks simultaneously. The prefix sum accumulation itself remains scalar, but the heavy lifting is vectorized through loop distribution. In contrast, Clang reports "unsafe dependent memory operations" citing a "backward loop carried data dependence" and generates purely scalar code, missing both the opportunity for partial vectorization via loop distribution and the ability to vectorize mixed-type conversions and narrow type packing using SVE.

**Test case:** https://godbolt.org/z/56TevEb7b
```c
#include
#include
long foo(
const long * __restrict__ a,
const double * __restrict__ b,
char * __restrict__ out,
int n
) {
for (int i = 0; i < n; i += 1)

{
int idx = i;
out[idx] = ((idx) >= 1 ? out[(idx) - 1] : (char)0) + (((char)a[idx]) + ((char)b[idx]));

}
return (long)0;
}
```

**clang version:**
```
clang version 21.1.1
Target: unknown
Thread model: posix
Build config: +unoptimized, +assertions
```

**Clang options:**
```
-S -O3 -ftree-vectorize -ftree-slp-vectorize --target=aarch64-linux-gnu -march=armv9-a+sve -Rpass=.*vectorize.* -Rpass-missed=.*vectorize.* -Rpass-analysis=.*vectorize.*
```

**The result of Clang:**
```
:13:18: remark: loop not vectorized: unsafe dependent memory operations in loop. Use #pragma clang loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop
Backward loop carried data dependence. Memory location is the same as accessed at example.c:13:34 [-Rpass-analysis=loop-vectorize]
13 | out[idx] = ((idx) >= 1 ? out[(idx) - 1] : (char)0) + (((char)a[idx]) + ((char)b[idx]));
| ^
:9:5: remark: loop not vectorized [-Rpass-missed=loop-vectorize]
9 | for (int i = 0; i < n; i += 1)
| ^ ^
```

**However, GCC vectorizes it.** GCC version 15.2.0.

**gcc version:**
```
aarch64-linux-gnu-gcc (GCC) 15.2.0
Copyright (C) 2025 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
```

**GCC options:**
```
-S -march=armv9-a+sve -ftree-vectorize -O3 -fopt-info-vec-all
```

**The result of GCC:**
```
:9:23: missed: couldn't vectorize loop
:13:60: missed: not vectorized, possible dependence between data-refs *_56 and *_43
:9:23: optimized: loop vectorized using 16 byte vectors
:9:23: optimized: loop vectorized using variable length vectors
:3:6: note: vectorized 1 loops in function.
:13:60: note: ***** Analysis failed with vector mode VNx16QI
:13:60: note: ***** The result for vector mode VNx16QI would be the same
:13:60: note: ***** Re-trying analysis with vector mode VNx8QI
:13:60: note: ***** Analysis failed with vector mode VNx8QI
:13:60: note: ***** Re-trying analysis with vector mode VNx4QI
:13:60: note: ***** Analysis failed with vector mode VNx4QI
:13:60: note: ***** Re-trying analysis with vector mode VNx2QI
:13:60: note: ***** Analysis failed with vector mode VNx2QI
:13:60: note: ***** Re-trying analysis with vector mode V16QI
:13:60: note: ***** Analysis failed with vector mode V16QI
:13:60: note: ***** Re-trying analysis with vector mode V8QI
:13:60: note: ***** Analysis failed with vector mode V8QI
:13:60: note: ***** The result for vector mode V4HI would be the same
:13:60: note: ***** Re-trying analysis with vector mode V2SI
:13:60: note: ***** Analysis failed with vector mode V2SI
```

Contributor guide

Open the contributing guide

Research direction

Reproduce the attached C test case with Clang using the documented AArch64 SVE options and inspect the loop-vectorization diagnostics. Compare the generated behavior with GCC's partial vectorization, then determine whether loop distribution and mixed-type conversion handling can support the same result. Done means Clang can safely vectorize the independent work while preserving the prefix-sum dependence, with a regression test covering the case.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.