Clang 21/22 fails to vectorize masked positive-sum loop on ARM SVE.
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
# Summary
Clang 21/22 fails to vectorize masked positive-sum loop on ARM SVE.
# Details
We kindly observe that Clang 21/22 cannot vectorize this simple conditional reduction loop (sum if positive), whereas GCC 15/16 vectorizes it efficiently with SVE.
The reported reason ("value that could not be identified as reduction is used outside the loop") seems to be a missed pattern, as the reduction variable `sum` is only used after the loop.
We would greatly appreciate it if the LLVM team could consider improving the reduction recognition for such conditional idioms.
Thank you for your understanding and continued excellent work.
Test case:
```c
#include
void foo(const float * __restrict__ a, float * __restrict__ out)
{
float x;
float sum = 0.0f;
for (int i = 0; i < 102400; i += 1) {
x = a[i];
if ((x) > (0.0f)) {
sum += x;
}
}
out[0] = sum;
}
```
Clang Compilation Options
`-march=armv9-a+sve -S -O3 -Rpass=loop-vectorize -Rpass-missed=loop-vectorize -Rpass-analysis=loop-vectorize`
GCC Compilation Options
`-O3 -S -march=armv9-a+sve -ftree-vectorize -fopt-info-vec-all`
## Clang Behavior
Clang 21.1.0 and 22.1.0 do not vectorize the loop.
Clang 21.1.0 log
```
:8:5: remark: loop not vectorized: value that could not be identified as reduction is used outside the loop [-Rpass-analysis=loop-vectorize]
8 | for (int i = 0; i < 102400; i += 1) {
| ^
:8:5: remark: loop not vectorized [-Rpass-missed=loop-vectorize]
Compiler returned: 0
```
Clang 22.1.0 log
```
:8:5: remark: loop not vectorized: value that could not be identified as reduction is used outside the loop [-Rpass-analysis=loop-vectorize]
8 | for (int i = 0; i < 102400; i += 1) {
| ^
:8:5: remark: loop not vectorized [-Rpass-missed=loop-vectorize]
Compiler returned: 0
```
Clang 22.1.0 output
```asm
foo(float const*, float*):
movi d0, #0000000000000000
mov x8, xzr
.LBB0_1:
ldr s1, [x0, x8]
add x8, x8, #4
fadd s2, s0, s1
fcmp s1, #0.0
fcsel s0, s2, s0, gt
cmp x8, #100, lsl #12
b.ne .LBB0_1
str s0, [x1]
ret
```
## GCC Behavior
GCC 15/16 successfully vectorizes the same loop.
```
:8:23: optimized: loop vectorized using variable length vectors
:8:23: optimized: epilogue loop vectorized using variable length vectors
:3:6: note: vectorized 1 loops in function.
:17:1: note: ***** Analysis failed with vector mode VNx4SF
:17:1: note: ***** Skipping vector mode VNx16QI, which would repeat the analysis for VNx4SF
Compiler returned: 0
```
# Potential Cause Analysis
1. Masked Reduction Not Recognized
Clang indicates that the value could not be identified as a reduction. The if (x > 0.0f) conditional prevents the loop vectorizer from recognizing sum += x as a masked reduction, even though ARM SVE supports predicated operations.
2. Scalar Dependence Misinterpretation
`sum` is used outside the loop. The conditional accumulation may make Clang conservatively treat `sum` as a scalar dependency, preventing vectorization.
3. GCC Vectorization Shows Feasibility
The GCC output confirms that SVE masked vector reduction is feasible, suggesting Clang could improve loop vectorizer analysis for this case.
# Expected Behavior
Clang should recognize `sum += x` under `if (x > 0.0f)` as a masked floating-point reduction.
Generate SVE vector code using predicated operations, similar to GCC.
# Notes
This is a small, reproducible test case.
The loop is a classic candidate for vectorization on SVE due to independent iterations and predictable memory access.
Supporting masked reductions would allow Clang to generate highly efficient code for this pattern.
If you could provide some guidance on a possible fix, I would be happy to give it a try!
Contributor guide
Assessment
This issue has not been assessed yet.