[llvm] e701968 - [LAA] Properly report strided access preventing store-to-load forwarding (#208791)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 3 08:52:14 PDT 2026
Author: Andrei Elovikov
Date: 2026-08-03T15:52:09Z
New Revision: e70196862584c5b8952919b0e8b994c4e3649326
URL: https://github.com/llvm/llvm-project/commit/e70196862584c5b8952919b0e8b994c4e3649326
DIFF: https://github.com/llvm/llvm-project/commit/e70196862584c5b8952919b0e8b994c4e3649326.diff
LOG: [LAA] Properly report strided access preventing store-to-load forwarding (#208791)
Original test by @fhahn in https://github.com/llvm/llvm-project/pull/191867, further reduced here.
Before this change LAA results in
> maximum safe store-load forward width of 32|0 bits
for `i32` accesses, effectively meaning that only `VF == 1` is safe, yet
not explicitly returning `false` from `couldPreventStoreLoadForward`.
This PR fixes that.
Added:
Modified:
llvm/lib/Analysis/LoopAccessAnalysis.cpp
llvm/test/Analysis/LoopAccessAnalysis/num-iters-for-store-load-conflict.ll
Removed:
################################################################################
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index c99d43dd1ccc2..e248b22de7d43 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -1970,6 +1970,13 @@ bool MemoryDepChecker::couldPreventStoreLoadForward(uint64_t Distance,
uint64_t MaxVFInBits = MaxVF * TypeByteSize * 8;
MaxStoreLoadForwardSafeDistanceInBits =
std::min(MaxStoreLoadForwardSafeDistanceInBits, MaxVFInBits);
+
+ if (MaxVF < 2) {
+ LLVM_DEBUG(
+ dbgs() << "LAA: strided access with Distance " << Distance
+ << " that could cause a store-load forwarding conflict\n");
+ return true;
+ }
}
return false;
}
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/num-iters-for-store-load-conflict.ll b/llvm/test/Analysis/LoopAccessAnalysis/num-iters-for-store-load-conflict.ll
index d3eda21dee27e..71eaa0ed2341e 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/num-iters-for-store-load-conflict.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/num-iters-for-store-load-conflict.ll
@@ -308,3 +308,91 @@ outer.latch:
exit:
ret void
}
+
+define void @stride2_store_load_preventing_forwarding(ptr %A) {
+; CHECK-LABEL: 'stride2_store_load_preventing_forwarding'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Report: 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
+; CHECK-NEXT: Backward loop carried data dependence that prevents store-to-load forwarding.
+; CHECK-NEXT: Dependences:
+; CHECK-NEXT: BackwardVectorizableButPreventsForwarding:
+; CHECK-NEXT: %ld = load i32, ptr %gep.ld, align 4 ->
+; CHECK-NEXT: store i32 %ld, ptr %gep.st, align 4
+; CHECK-EMPTY:
+; CHECK-NEXT: Run-time memory checks:
+; CHECK-NEXT: Grouped accesses:
+; CHECK-EMPTY:
+; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop.
+; CHECK-NEXT: SCEV assumptions:
+; CHECK-EMPTY:
+; CHECK-NEXT: Expressions re-written:
+;
+entry:
+ %A.offset = getelementptr i32, ptr %A, i64 6
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+
+ %iv.x2 = mul i64 %iv, 2
+ %gep.ld = getelementptr i32, ptr %A, i64 %iv.x2
+ %ld = load i32, ptr %gep.ld, align 4
+ %gep.st = getelementptr i32, ptr %A.offset, i64 %iv.x2
+ store i32 %ld, ptr %gep.st, align 4
+
+ %iv.next = add i64 %iv, 1
+ %cmp = icmp ne i64 %iv, 1024
+ br i1 %cmp, label %loop, label %exit
+
+exit:
+ ret void
+}
+
+; FIXME: VF 2 is safe for store-load forwarding:
+; idx | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
+; v/iter 0 load lane | 0 | | | 1 | | | | | | | | | | | | | | | |
+; v/iter 0 store lane | | | | | | | 0 | | | 1 | | | | | | | | | |
+; -------------------------------------------------------------------------------------------------------------------|
+; v/iter 1 load lane | | | | | | | 0 | | | 1 | | | | | | | | | |
+; v/iter 1 store lane | | | | | | | | | | | | | 0 | | | 1 | | | |
+; -------------------------------------------------------------------------------------------------------------------|
+; v/iter 2 load lane | | | | | | | | | | | | | 0 | | | 1 | | | |
+; v/iter 2 store lane | | | | | | | | | | | | | | | | | | | 0 |
+define void @stride3_store_load_forwarding_safe_dist(ptr %A) {
+; CHECK-LABEL: 'stride3_store_load_forwarding_safe_dist'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Report: 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
+; CHECK-NEXT: Backward loop carried data dependence that prevents store-to-load forwarding.
+; CHECK-NEXT: Dependences:
+; CHECK-NEXT: BackwardVectorizableButPreventsForwarding:
+; CHECK-NEXT: %ld = load i32, ptr %gep.ld, align 4 ->
+; CHECK-NEXT: store i32 %ld, ptr %gep.st, align 4
+; CHECK-EMPTY:
+; CHECK-NEXT: Run-time memory checks:
+; CHECK-NEXT: Grouped accesses:
+; CHECK-EMPTY:
+; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop.
+; CHECK-NEXT: SCEV assumptions:
+; CHECK-EMPTY:
+; CHECK-NEXT: Expressions re-written:
+;
+entry:
+ %A.offset = getelementptr i32, ptr %A, i64 6
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+
+ %iv.x2 = mul i64 %iv, 3
+ %gep.ld = getelementptr i32, ptr %A, i64 %iv.x2
+ %ld = load i32, ptr %gep.ld, align 4
+ %gep.st = getelementptr i32, ptr %A.offset, i64 %iv.x2
+ store i32 %ld, ptr %gep.st, align 4
+
+ %iv.next = add i64 %iv, 1
+ %cmp = icmp ne i64 %iv, 1024
+ br i1 %cmp, label %loop, label %exit
+
+exit:
+ ret void
+}
More information about the llvm-commits
mailing list