[llvm] [LAA] Switch safe-distance APIs to operate in elements instead of bits, NFCI'ish (PR #191867)
Andrei Elovikov via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 3 10:45:58 PDT 2026
https://github.com/eas updated https://github.com/llvm/llvm-project/pull/191867
>From b8ef9ca386740503d99685cdd9c4bb8fdf3a2c77 Mon Sep 17 00:00:00 2001
From: Andrei Elovikov <andrei.elovikov at sifive.com>
Date: Fri, 10 Jul 2026 07:24:43 -0700
Subject: [PATCH 1/8] Add test
---
.../safe-with-dep-distance-non-power-of-2.ll | 62 +++++++++++++++++++
1 file changed, 62 insertions(+)
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll b/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll
index 79dcfd2c4c08d..e697d4ac1b496 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll
@@ -258,3 +258,65 @@ loop:
exit:
ret void
}
+
+; FIXME: "maximum safe store-load forward width of 32 bits" for i32 access means
+; there is no safe VF, need to be reported properly.
+define void @two_store_load_forward_deps(ptr %A, ptr %B) {
+; CHECK-LABEL: 'two_store_load_forward_deps'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Memory dependences are safe with a maximum safe vector width of 96 bits, with a maximum safe store-load forward width of 32 bits with run-time checks
+; CHECK-NEXT: Dependences:
+; CHECK-NEXT: BackwardVectorizable:
+; CHECK-NEXT: %vb = load i32, ptr %b.ld, align 4 ->
+; CHECK-NEXT: store i32 %vb, ptr %b.st, align 4
+; CHECK-EMPTY:
+; CHECK-NEXT: BackwardVectorizable:
+; CHECK-NEXT: %va = load i32, ptr %a.ld, align 4 ->
+; CHECK-NEXT: store i32 %va, ptr %a.st, align 4
+; CHECK-EMPTY:
+; CHECK-NEXT: Run-time memory checks:
+; CHECK-NEXT: Check 0:
+; CHECK-NEXT: Comparing group GRP0:
+; CHECK-NEXT: %a.ld = getelementptr i32, ptr %A, i64 %iv
+; CHECK-NEXT: %a.st = getelementptr i32, ptr %A, i64 %a.off
+; CHECK-NEXT: Against group GRP1:
+; CHECK-NEXT: %b.ld = getelementptr i32, ptr %B, i64 %ib
+; CHECK-NEXT: %b.st = getelementptr i32, ptr %B, i64 %b.off
+; CHECK-NEXT: Grouped accesses:
+; CHECK-NEXT: Group GRP0:
+; CHECK-NEXT: (Low: %A High: (4132 + %A))
+; CHECK-NEXT: Member: {%A,+,4}<nw><%loop>
+; CHECK-NEXT: Member: {(32 + %A),+,4}<nw><%loop>
+; CHECK-NEXT: Group GRP1:
+; CHECK-NEXT: (Low: %B High: (8220 + %B))
+; CHECK-NEXT: Member: {%B,+,8}<nw><%loop>
+; CHECK-NEXT: Member: {(24 + %B),+,8}<nw><%loop>
+; 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:
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %a.ld = getelementptr i32, ptr %A, i64 %iv
+ %va = load i32, ptr %a.ld, align 4
+ %a.off = add i64 %iv, 8
+ %a.st = getelementptr i32, ptr %A, i64 %a.off
+ store i32 %va, ptr %a.st, align 4
+ %ib = shl i64 %iv, 1
+ %b.ld = getelementptr i32, ptr %B, i64 %ib
+ %vb = load i32, ptr %b.ld, align 4
+ %b.off = add i64 %ib, 6
+ %b.st = getelementptr i32, ptr %B, i64 %b.off
+ store i32 %vb, ptr %b.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
+}
>From dca9b619a64a69f475796b3e2dd80cc23c30ac79 Mon Sep 17 00:00:00 2001
From: Andrei Elovikov <andrei.elovikov at sifive.com>
Date: Fri, 10 Jul 2026 10:37:16 -0700
Subject: [PATCH 2/8] [LAA] Properly report strided access preventing
store-to-load forwarding
Test by @fhahn in https://github.com/llvm/llvm-project/pull/191867.
Before this change LAA results in
> maximum safe store-load forward width of 32 bits
for i32 accesses, effectively meaning that only `VF == 1` is safe, yet
not explicitly returning `false` from `couldPreventStoreLoadForward`.
This PR fixes that.
---
llvm/lib/Analysis/LoopAccessAnalysis.cpp | 7 +++++++
.../safe-with-dep-distance-non-power-of-2.ll | 7 +++----
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index ff1032e669265..3c2d65da94b3c 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -1958,6 +1958,13 @@ bool MemoryDepChecker::couldPreventStoreLoadForward(uint64_t Distance,
uint64_t MaxVFInBits = MaxVF * TypeByteSize * 8;
MaxStoreLoadForwardSafeDistanceInBits =
std::min(MaxStoreLoadForwardSafeDistanceInBits, MaxVFInBits);
+
+ if (MaxVF == 1) {
+ 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/safe-with-dep-distance-non-power-of-2.ll b/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll
index e697d4ac1b496..0ad4d1b7bf3b9 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll
@@ -259,14 +259,13 @@ exit:
ret void
}
-; FIXME: "maximum safe store-load forward width of 32 bits" for i32 access means
-; there is no safe VF, need to be reported properly.
define void @two_store_load_forward_deps(ptr %A, ptr %B) {
; CHECK-LABEL: 'two_store_load_forward_deps'
; CHECK-NEXT: loop:
-; CHECK-NEXT: Memory dependences are safe with a maximum safe vector width of 96 bits, with a maximum safe store-load forward width of 32 bits with run-time checks
+; 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: BackwardVectorizable:
+; CHECK-NEXT: BackwardVectorizableButPreventsForwarding:
; CHECK-NEXT: %vb = load i32, ptr %b.ld, align 4 ->
; CHECK-NEXT: store i32 %vb, ptr %b.st, align 4
; CHECK-EMPTY:
>From 1fe01f44b555ecd5c49d99fd3932a7dc06daef7f Mon Sep 17 00:00:00 2001
From: Andrei Elovikov <andrei.elovikov at sifive.com>
Date: Mon, 13 Apr 2026 11:07:18 -0700
Subject: [PATCH 3/8] [LAA] Switch safe-distance APIs to operate in elements
instead of bits
The only client (LoopVectorizer) immediately converts the returned
values to operate in number of elements instead of bits, so it makes
sense to just operate in elements directly to simplify logic.
While doing this refactoring I've faced a multiplication by eight in
`couldPreventStoreLoadForward` that I couldn't explain. From what I see
it just "cancels out" with the same in an `if` later and is unnecessary.
I'm dropping it in this PR, but I'm splitting it into two commits to
ease review of that part.
---
.../llvm/Analysis/LoopAccessAnalysis.h | 30 ++++++--------
.../Vectorize/LoopVectorizationLegality.h | 8 ++--
llvm/lib/Analysis/LoopAccessAnalysis.cpp | 41 +++++++++----------
.../Vectorize/LoopVectorizationPlanner.cpp | 7 ++--
.../accesses-completely-before-or-after.ll | 2 +-
.../LoopAccessAnalysis/depend_diff_types.ll | 2 +-
...es-safe-dep-due-to-backedge-taken-count.ll | 2 +-
.../max_safe_dep_dist_non_unit_stride.ll | 2 +-
.../multiple-strides-rt-memory-checks.ll | 2 +-
.../non-constant-distance-backward.ll | 8 ++--
.../non-constant-strides-backward.ll | 2 +-
.../safe-with-dep-distance-non-power-of-2.ll | 6 +--
.../safe-with-dep-distance.ll | 2 +-
.../stride-access-dependence.ll | 8 ++--
14 files changed, 57 insertions(+), 65 deletions(-)
diff --git a/llvm/include/llvm/Analysis/LoopAccessAnalysis.h b/llvm/include/llvm/Analysis/LoopAccessAnalysis.h
index 392321448c895..a50cfde8cd4c7 100644
--- a/llvm/include/llvm/Analysis/LoopAccessAnalysis.h
+++ b/llvm/include/llvm/Analysis/LoopAccessAnalysis.h
@@ -220,28 +220,25 @@ class MemoryDepChecker {
/// Return true if the number of elements that are safe to operate on
/// simultaneously is not bounded.
bool isSafeForAnyVectorWidth() const {
- return MaxSafeVectorWidthInBits == UINT_MAX;
+ return MaxSafeNumElements == UINT_MAX;
}
/// Return the number of elements that are safe to operate on
- /// simultaneously, multiplied by the size of the element in bits.
- uint64_t getMaxSafeVectorWidthInBits() const {
- return MaxSafeVectorWidthInBits;
- }
+ /// simultaneously.
+ uint64_t getMaxSafeNumElements() const { return MaxSafeNumElements; }
/// Return true if there are no store-load forwarding dependencies.
bool isSafeForAnyStoreLoadForwardDistances() const {
- return MaxStoreLoadForwardSafeDistanceInBits ==
- std::numeric_limits<uint64_t>::max();
+ return MaxStoreLoadForwardSafeNumElements == UINT_MAX;
}
/// Return safe power-of-2 number of elements, which do not prevent store-load
- /// forwarding, multiplied by the size of the elements in bits.
- uint64_t getStoreLoadForwardSafeDistanceInBits() const {
+ /// forwarding.
+ uint64_t getStoreLoadForwardSafeNumElements() const {
assert(!isSafeForAnyStoreLoadForwardDistances() &&
"Expected the distance, that prevent store-load forwarding, to be "
"set.");
- return MaxStoreLoadForwardSafeDistanceInBits;
+ return MaxStoreLoadForwardSafeNumElements;
}
/// In same cases when the dependency check fails we can still
@@ -339,16 +336,13 @@ class MemoryDepChecker {
/// simultaneously.
uint64_t MinDepDistBytes = 0;
- /// Number of elements (from consecutive iterations) that are safe to
- /// operate on simultaneously, multiplied by the size of the element in bits.
- /// The size of the element is taken from the memory access that is most
- /// restrictive.
- uint64_t MaxSafeVectorWidthInBits = -1U;
+ /// Number of elements (from consecutive iterations) that are safe to operate
+ /// on simultaneously.
+ uint64_t MaxSafeNumElements = -1U;
/// Maximum power-of-2 number of elements, which do not prevent store-load
- /// forwarding, multiplied by the size of the elements in bits.
- uint64_t MaxStoreLoadForwardSafeDistanceInBits =
- std::numeric_limits<uint64_t>::max();
+ /// forwarding.
+ uint64_t MaxStoreLoadForwardSafeNumElements = -1U;
/// Whether we should try to vectorize the loop with runtime checks, if the
/// dependencies are not safe.
diff --git a/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h b/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h
index 3e8db73fd79d2..b1710769f905d 100644
--- a/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h
+++ b/llvm/include/llvm/Transforms/Vectorize/LoopVectorizationLegality.h
@@ -415,8 +415,8 @@ class LoopVectorizationLegality {
LAI->getDepChecker().isSafeForAnyStoreLoadForwardDistances();
}
- uint64_t getMaxSafeVectorWidthInBits() const {
- return LAI->getDepChecker().getMaxSafeVectorWidthInBits();
+ uint64_t getMaxSafeNumElements() const {
+ return LAI->getDepChecker().getMaxSafeNumElements();
}
/// Returns information about whether this loop contains at least one
@@ -447,8 +447,8 @@ class LoopVectorizationLegality {
/// Return safe power-of-2 number of elements, which do not prevent store-load
/// forwarding and safe to operate simultaneously.
- uint64_t getMaxStoreLoadForwardSafeDistanceInBits() const {
- return LAI->getDepChecker().getStoreLoadForwardSafeDistanceInBits();
+ uint64_t getMaxStoreLoadForwardSafeNumElements() const {
+ return LAI->getDepChecker().getStoreLoadForwardSafeNumElements();
}
/// Returns true if instruction \p I requires a mask for vectorization.
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index 3c2d65da94b3c..1971aa636032e 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -1926,22 +1926,22 @@ bool MemoryDepChecker::couldPreventStoreLoadForward(uint64_t Distance,
// cause any slowdowns.
const uint64_t NumItersForStoreLoadThroughMemory = 8 * TypeByteSize;
// Maximum vector factor.
- uint64_t MaxVFWithoutSLForwardIssuesPowerOf2 =
- std::min(VectorizerParams::MaxVectorWidth * TypeByteSize,
- MaxStoreLoadForwardSafeDistanceInBits);
+ // TODO: This "8" doesn't make any sense:
+ uint64_t MaxVFWithoutSLForwardIssuesPowerOf2 = std::min<uint64_t>(
+ VectorizerParams::MaxVectorWidth, MaxStoreLoadForwardSafeNumElements * 8);
// Compute the smallest VF at which the store and load would be misaligned.
- for (uint64_t VF = 2 * TypeByteSize;
- VF <= MaxVFWithoutSLForwardIssuesPowerOf2; VF *= 2) {
+ for (uint64_t VF = 2; VF <= MaxVFWithoutSLForwardIssuesPowerOf2; VF *= 2) {
// If the number of vector iteration between the store and the load are
// small we could incur conflicts.
- if (Distance % VF && Distance / VF < NumItersForStoreLoadThroughMemory) {
+ if (Distance % (VF * TypeByteSize) &&
+ Distance / (VF * TypeByteSize) < NumItersForStoreLoadThroughMemory) {
MaxVFWithoutSLForwardIssuesPowerOf2 = (VF >> 1);
break;
}
}
- if (MaxVFWithoutSLForwardIssuesPowerOf2 < 2 * TypeByteSize) {
+ if (MaxVFWithoutSLForwardIssuesPowerOf2 < 2) {
LLVM_DEBUG(
dbgs() << "LAA: Distance " << Distance
<< " that could cause a store-load forwarding conflict\n");
@@ -1950,14 +1950,12 @@ bool MemoryDepChecker::couldPreventStoreLoadForward(uint64_t Distance,
if (CommonStride &&
MaxVFWithoutSLForwardIssuesPowerOf2 <
- MaxStoreLoadForwardSafeDistanceInBits &&
- MaxVFWithoutSLForwardIssuesPowerOf2 !=
- VectorizerParams::MaxVectorWidth * TypeByteSize) {
- uint64_t MaxVF =
- bit_floor(MaxVFWithoutSLForwardIssuesPowerOf2 / CommonStride);
- uint64_t MaxVFInBits = MaxVF * TypeByteSize * 8;
- MaxStoreLoadForwardSafeDistanceInBits =
- std::min(MaxStoreLoadForwardSafeDistanceInBits, MaxVFInBits);
+ MaxStoreLoadForwardSafeNumElements * 8 &&
+ MaxVFWithoutSLForwardIssuesPowerOf2 != VectorizerParams::MaxVectorWidth) {
+ uint64_t MaxVF = bit_floor(MaxVFWithoutSLForwardIssuesPowerOf2 *
+ TypeByteSize / CommonStride);
+ MaxStoreLoadForwardSafeNumElements =
+ std::min(MaxStoreLoadForwardSafeNumElements, MaxVF);
if (MaxVF == 1) {
LLVM_DEBUG(
@@ -2442,7 +2440,7 @@ MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
if (CheckCompletelyBeforeOrAfter())
return Dependence::NoDep;
- MaxSafeVectorWidthInBits = std::min(MaxSafeVectorWidthInBits, MaxVFInBits);
+ MaxSafeNumElements = std::min(MaxSafeNumElements, MaxVF);
return Dependence::BackwardVectorizable;
}
@@ -3203,12 +3201,13 @@ void LoopAccessInfo::print(raw_ostream &OS, unsigned Depth) const {
OS.indent(Depth) << "Memory dependences are safe";
const MemoryDepChecker &DC = getDepChecker();
if (!DC.isSafeForAnyVectorWidth())
- OS << " with a maximum safe vector width of "
- << DC.getMaxSafeVectorWidthInBits() << " bits";
+ OS << " with a maximum safe number of elements to operate on equal to "
+ << DC.getMaxSafeNumElements();
if (!DC.isSafeForAnyStoreLoadForwardDistances()) {
- uint64_t SLDist = DC.getStoreLoadForwardSafeDistanceInBits();
- OS << ", with a maximum safe store-load forward width of " << SLDist
- << " bits";
+ uint64_t SLDist = DC.getStoreLoadForwardSafeNumElements();
+ OS << ", with a maximum safe store-load forward number of elements to "
+ "operate on equal to "
+ << SLDist;
}
if (PtrRtChecking->Need)
OS << " with run-time checks";
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.cpp
index dbb5ad28fb4ed..7b228e3594d02 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.cpp
@@ -402,11 +402,10 @@ FixedScalableVFPair VFSelectionContext::computeFeasibleMaxVF(
// the memory accesses that is most restrictive (involved in the smallest
// dependence distance).
unsigned MaxSafeElementsPowerOf2 =
- llvm::bit_floor(Legal->getMaxSafeVectorWidthInBits() / WidestType);
+ llvm::bit_floor(Legal->getMaxSafeNumElements());
if (!Legal->isSafeForAnyStoreLoadForwardDistances()) {
- unsigned SLDist = Legal->getMaxStoreLoadForwardSafeDistanceInBits();
- MaxSafeElementsPowerOf2 =
- std::min(MaxSafeElementsPowerOf2, SLDist / WidestType);
+ unsigned SLDist = Legal->getMaxStoreLoadForwardSafeNumElements();
+ MaxSafeElementsPowerOf2 = std::min(MaxSafeElementsPowerOf2, SLDist);
}
auto MaxSafeFixedVF = ElementCount::getFixed(MaxSafeElementsPowerOf2);
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/accesses-completely-before-or-after.ll b/llvm/test/Analysis/LoopAccessAnalysis/accesses-completely-before-or-after.ll
index 9a329b70338bd..e224408f60c3e 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/accesses-completely-before-or-after.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/accesses-completely-before-or-after.ll
@@ -254,7 +254,7 @@ exit:
define void @accesses_may_overlap_backwards_vectorizable(ptr dereferenceable(800) %dst) {
; CHECK-LABEL: 'accesses_may_overlap_backwards_vectorizable'
; CHECK-NEXT: loop:
-; CHECK-NEXT: Memory dependences are safe with a maximum safe vector width of 128 bits
+; CHECK-NEXT: Memory dependences are safe with a maximum safe number of elements to operate on equal to 8
; CHECK-NEXT: Dependences:
; CHECK-NEXT: BackwardVectorizable:
; CHECK-NEXT: store i16 0, ptr %gep.mul.2, align 2 ->
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/depend_diff_types.ll b/llvm/test/Analysis/LoopAccessAnalysis/depend_diff_types.ll
index 5d59660a68e90..55f916a3ab8a7 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/depend_diff_types.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/depend_diff_types.ll
@@ -11,7 +11,7 @@
define void @backdep_type_size_equivalence(ptr nocapture %vec, i64 %n) {
; CHECK-LABEL: 'backdep_type_size_equivalence'
; CHECK-NEXT: loop:
-; CHECK-NEXT: Memory dependences are safe with a maximum safe vector width of 3200 bits
+; CHECK-NEXT: Memory dependences are safe with a maximum safe number of elements to operate on equal to 100
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Forward:
; CHECK-NEXT: %ld.f32 = load float, ptr %gep.iv, align 8 ->
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/different-strides-safe-dep-due-to-backedge-taken-count.ll b/llvm/test/Analysis/LoopAccessAnalysis/different-strides-safe-dep-due-to-backedge-taken-count.ll
index 311de84993001..506a13194a1e2 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/different-strides-safe-dep-due-to-backedge-taken-count.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/different-strides-safe-dep-due-to-backedge-taken-count.ll
@@ -142,7 +142,7 @@ exit:
define void @backward_dep_known_distance_less_than_btc(ptr %A) {
; CHECK-LABEL: 'backward_dep_known_distance_less_than_btc'
; CHECK-NEXT: loop:
-; CHECK-NEXT: Memory dependences are safe with a maximum safe vector width of 4064 bits
+; CHECK-NEXT: Memory dependences are safe with a maximum safe number of elements to operate on equal to 127
; CHECK-NEXT: Dependences:
; CHECK-NEXT: BackwardVectorizable:
; CHECK-NEXT: %l = load i32, ptr %gep, align 4 ->
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/max_safe_dep_dist_non_unit_stride.ll b/llvm/test/Analysis/LoopAccessAnalysis/max_safe_dep_dist_non_unit_stride.ll
index 54445c0182435..01c00bf09fa45 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/max_safe_dep_dist_non_unit_stride.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/max_safe_dep_dist_non_unit_stride.ll
@@ -11,7 +11,7 @@
define void @foo(i64 %len, ptr %a) {
; CHECK-LABEL: 'foo'
; CHECK-NEXT: loop:
-; CHECK-NEXT: Memory dependences are safe with a maximum safe vector width of 64 bits
+; CHECK-NEXT: Memory dependences are safe with a maximum safe number of elements to operate on equal to 2
; CHECK-NEXT: Dependences:
; CHECK-NEXT: BackwardVectorizable:
; CHECK-NEXT: store i32 %0, ptr %arrayidx2, align 4 ->
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/multiple-strides-rt-memory-checks.ll b/llvm/test/Analysis/LoopAccessAnalysis/multiple-strides-rt-memory-checks.ll
index a338a339575a4..20da3ac6a2923 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/multiple-strides-rt-memory-checks.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/multiple-strides-rt-memory-checks.ll
@@ -29,7 +29,7 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
define void @Test(ptr nocapture %obj, i64 %z) #0 {
; CHECK-LABEL: 'Test'
; CHECK-NEXT: .inner:
-; CHECK-NEXT: Memory dependences are safe with a maximum safe vector width of 2048 bits with run-time checks
+; CHECK-NEXT: Memory dependences are safe with a maximum safe number of elements to operate on equal to 64 with run-time checks
; CHECK-NEXT: Dependences:
; CHECK-NEXT: Run-time memory checks:
; CHECK-NEXT: Check 0:
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/non-constant-distance-backward.ll b/llvm/test/Analysis/LoopAccessAnalysis/non-constant-distance-backward.ll
index b444c061c2632..a1045cf59175e 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/non-constant-distance-backward.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/non-constant-distance-backward.ll
@@ -79,7 +79,7 @@ exit:
define void @backward_min_distance_120(ptr %A, i64 %N) {
; CHECK-LABEL: 'backward_min_distance_120'
; CHECK-NEXT: loop:
-; CHECK-NEXT: Memory dependences are safe with a maximum safe vector width of 120 bits
+; CHECK-NEXT: Memory dependences are safe with a maximum safe number of elements to operate on equal to 15
; CHECK-NEXT: Dependences:
; CHECK-NEXT: BackwardVectorizable:
; CHECK-NEXT: %l = load i8, ptr %gep, align 4 ->
@@ -200,7 +200,7 @@ exit:
define void @backward_min_distance_128(ptr %A, i64 %N) {
; CHECK-LABEL: 'backward_min_distance_128'
; CHECK-NEXT: loop:
-; CHECK-NEXT: Memory dependences are safe with a maximum safe vector width of 128 bits
+; CHECK-NEXT: Memory dependences are safe with a maximum safe number of elements to operate on equal to 16
; CHECK-NEXT: Dependences:
; CHECK-NEXT: BackwardVectorizable:
; CHECK-NEXT: %l = load i8, ptr %gep, align 4 ->
@@ -321,7 +321,7 @@ exit:
define void @backward_min_distance_256(ptr %A, i64 %N) {
; CHECK-LABEL: 'backward_min_distance_256'
; CHECK-NEXT: loop:
-; CHECK-NEXT: Memory dependences are safe with a maximum safe vector width of 256 bits
+; CHECK-NEXT: Memory dependences are safe with a maximum safe number of elements to operate on equal to 32
; CHECK-NEXT: Dependences:
; CHECK-NEXT: BackwardVectorizable:
; CHECK-NEXT: %l = load i8, ptr %gep, align 4 ->
@@ -347,7 +347,7 @@ define void @backward_min_distance_256(ptr %A, i64 %N) {
;
; VW128-LABEL: 'backward_min_distance_256'
; VW128-NEXT: loop:
-; VW128-NEXT: Memory dependences are safe with a maximum safe vector width of 256 bits
+; VW128-NEXT: Memory dependences are safe with a maximum safe number of elements to operate on equal to 32
; VW128-NEXT: Dependences:
; VW128-NEXT: BackwardVectorizable:
; VW128-NEXT: %l = load i8, ptr %gep, align 4 ->
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/non-constant-strides-backward.ll b/llvm/test/Analysis/LoopAccessAnalysis/non-constant-strides-backward.ll
index 76e2d30dcdc25..31d2c071885bb 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/non-constant-strides-backward.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/non-constant-strides-backward.ll
@@ -78,7 +78,7 @@ exit:
define void @different_non_constant_strides_known_backward_min_distance_16(ptr %A) {
; CHECK-LABEL: 'different_non_constant_strides_known_backward_min_distance_16'
; CHECK-NEXT: loop:
-; CHECK-NEXT: Memory dependences are safe with a maximum safe vector width of 64 bits
+; CHECK-NEXT: Memory dependences are safe with a maximum safe number of elements to operate on equal to 2
; CHECK-NEXT: Dependences:
; CHECK-NEXT: BackwardVectorizable:
; CHECK-NEXT: %l = load i32, ptr %gep, align 4 ->
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll b/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll
index 0ad4d1b7bf3b9..40e70ea13520f 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll
@@ -43,7 +43,7 @@ exit:
define void @test_may_clobber1(ptr %p) {
; CHECK-LABEL: 'test_may_clobber1'
; CHECK-NEXT: loop:
-; CHECK-NEXT: Memory dependences are safe with a maximum safe vector width of 6400 bits, with a maximum safe store-load forward width of 256 bits
+; CHECK-NEXT: Memory dependences are safe with a maximum safe number of elements to operate on equal to 100, with a maximum safe store-load forward number of elements to operate on equal to 4
; CHECK-NEXT: Dependences:
; CHECK-NEXT: BackwardVectorizable:
; CHECK-NEXT: %v = load i64, ptr %a1, align 32 ->
@@ -114,7 +114,7 @@ exit:
define void @test_may_clobber3(ptr %p) {
; CHECK-LABEL: 'test_may_clobber3'
; CHECK-NEXT: loop:
-; CHECK-NEXT: Memory dependences are safe with a maximum safe vector width of 640 bits, with a maximum safe store-load forward width of 128 bits
+; CHECK-NEXT: Memory dependences are safe with a maximum safe number of elements to operate on equal to 10, with a maximum safe store-load forward number of elements to operate on equal to 2
; CHECK-NEXT: Dependences:
; CHECK-NEXT: BackwardVectorizable:
; CHECK-NEXT: %v = load i64, ptr %a1, align 32 ->
@@ -182,7 +182,7 @@ exit:
define void @no_high_lmul_or_interleave(ptr %p) {
; CHECK-LABEL: 'no_high_lmul_or_interleave'
; CHECK-NEXT: loop:
-; CHECK-NEXT: Memory dependences are safe with a maximum safe vector width of 65536 bits
+; CHECK-NEXT: Memory dependences are safe with a maximum safe number of elements to operate on equal to 1024
; CHECK-NEXT: Dependences:
; CHECK-NEXT: BackwardVectorizable:
; CHECK-NEXT: %v = load i64, ptr %a1, align 32 ->
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance.ll b/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance.ll
index 8e249b36f6445..d716df1f5ae76 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance.ll
@@ -4,7 +4,7 @@
; for (i = 0; i < n; i++)
; A[i + 4] = A[i] * 2;
-; CHECK: Memory dependences are safe with a maximum safe vector width of 64 bits, with a maximum safe store-load forward width of 64 bits
+; CHECK: Memory dependences are safe with a maximum safe number of elements to operate on equal to 4, with a maximum safe store-load forward number of elements to operate on equal to 4
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.10.0"
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/stride-access-dependence.ll b/llvm/test/Analysis/LoopAccessAnalysis/stride-access-dependence.ll
index 335ad67faee04..d80955f1afadd 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/stride-access-dependence.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/stride-access-dependence.ll
@@ -276,7 +276,7 @@ for.body: ; preds = %entry, %for.body
define void @vectorizable_Read_Write(ptr nocapture %A) {
; CHECK-LABEL: 'vectorizable_Read_Write'
; CHECK-NEXT: for.body:
-; CHECK-NEXT: Memory dependences are safe with a maximum safe vector width of 64 bits, with a maximum safe store-load forward width of 64 bits
+; CHECK-NEXT: Memory dependences are safe with a maximum safe number of elements to operate on equal to 2, with a maximum safe store-load forward number of elements to operate on equal to 2
; CHECK-NEXT: Dependences:
; CHECK-NEXT: BackwardVectorizable:
; CHECK-NEXT: %0 = load i32, ptr %arrayidx, align 4 ->
@@ -323,7 +323,7 @@ for.body: ; preds = %entry, %for.body
define i32 @vectorizable_Write_Read(ptr nocapture %A) {
; CHECK-LABEL: 'vectorizable_Write_Read'
; CHECK-NEXT: for.body:
-; CHECK-NEXT: Memory dependences are safe with a maximum safe vector width of 64 bits
+; CHECK-NEXT: Memory dependences are safe with a maximum safe number of elements to operate on equal to 2
; CHECK-NEXT: Dependences:
; CHECK-NEXT: BackwardVectorizable:
; CHECK-NEXT: store i32 %0, ptr %arrayidx, align 4 ->
@@ -369,7 +369,7 @@ for.body: ; preds = %entry, %for.body
define void @vectorizable_Write_Write(ptr nocapture %A) {
; CHECK-LABEL: 'vectorizable_Write_Write'
; CHECK-NEXT: for.body:
-; CHECK-NEXT: Memory dependences are safe with a maximum safe vector width of 64 bits
+; CHECK-NEXT: Memory dependences are safe with a maximum safe number of elements to operate on equal to 2
; CHECK-NEXT: Dependences:
; CHECK-NEXT: BackwardVectorizable:
; CHECK-NEXT: store i32 %0, ptr %arrayidx, align 4 ->
@@ -464,7 +464,7 @@ for.body: ; preds = %entry, %for.body
define i32 @vectorizable_unscaled_Write_Read(ptr nocapture %A) {
; CHECK-LABEL: 'vectorizable_unscaled_Write_Read'
; CHECK-NEXT: for.body:
-; CHECK-NEXT: Memory dependences are safe with a maximum safe vector width of 64 bits
+; CHECK-NEXT: Memory dependences are safe with a maximum safe number of elements to operate on equal to 2
; CHECK-NEXT: Dependences:
; CHECK-NEXT: BackwardVectorizable:
; CHECK-NEXT: store i32 %0, ptr %arrayidx, align 4 ->
>From 62e406a5b7eac32f76c705148351b9df168e2055 Mon Sep 17 00:00:00 2001
From: Andrei Elovikov <andrei.elovikov at sifive.com>
Date: Mon, 13 Apr 2026 11:13:18 -0700
Subject: [PATCH 4/8] Drop unexplainable "* 8"
---
llvm/lib/Analysis/LoopAccessAnalysis.cpp | 5 ++---
.../safe-with-dep-distance-non-power-of-2.ll | 2 +-
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index 1971aa636032e..85a1cf93d975b 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -1926,9 +1926,8 @@ bool MemoryDepChecker::couldPreventStoreLoadForward(uint64_t Distance,
// cause any slowdowns.
const uint64_t NumItersForStoreLoadThroughMemory = 8 * TypeByteSize;
// Maximum vector factor.
- // TODO: This "8" doesn't make any sense:
uint64_t MaxVFWithoutSLForwardIssuesPowerOf2 = std::min<uint64_t>(
- VectorizerParams::MaxVectorWidth, MaxStoreLoadForwardSafeNumElements * 8);
+ VectorizerParams::MaxVectorWidth, MaxStoreLoadForwardSafeNumElements);
// Compute the smallest VF at which the store and load would be misaligned.
for (uint64_t VF = 2; VF <= MaxVFWithoutSLForwardIssuesPowerOf2; VF *= 2) {
@@ -1950,7 +1949,7 @@ bool MemoryDepChecker::couldPreventStoreLoadForward(uint64_t Distance,
if (CommonStride &&
MaxVFWithoutSLForwardIssuesPowerOf2 <
- MaxStoreLoadForwardSafeNumElements * 8 &&
+ MaxStoreLoadForwardSafeNumElements &&
MaxVFWithoutSLForwardIssuesPowerOf2 != VectorizerParams::MaxVectorWidth) {
uint64_t MaxVF = bit_floor(MaxVFWithoutSLForwardIssuesPowerOf2 *
TypeByteSize / CommonStride);
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll b/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll
index 40e70ea13520f..e618401c90758 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll
@@ -269,7 +269,7 @@ define void @two_store_load_forward_deps(ptr %A, ptr %B) {
; CHECK-NEXT: %vb = load i32, ptr %b.ld, align 4 ->
; CHECK-NEXT: store i32 %vb, ptr %b.st, align 4
; CHECK-EMPTY:
-; CHECK-NEXT: BackwardVectorizable:
+; CHECK-NEXT: BackwardVectorizableButPreventsForwarding:
; CHECK-NEXT: %va = load i32, ptr %a.ld, align 4 ->
; CHECK-NEXT: store i32 %va, ptr %a.st, align 4
; CHECK-EMPTY:
>From 9a313c055bd78130c8580cca028a82fa6b558380 Mon Sep 17 00:00:00 2001
From: Andrei Elovikov <andrei.elovikov at sifive.com>
Date: Mon, 3 Aug 2026 09:59:07 -0700
Subject: [PATCH 5/8] Revert "Drop unexplainable "* 8""
This reverts commit 62e406a5b7eac32f76c705148351b9df168e2055.
---
llvm/lib/Analysis/LoopAccessAnalysis.cpp | 5 +++--
.../safe-with-dep-distance-non-power-of-2.ll | 2 +-
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index 6c492fe5bf8ac..7408d13cba3cb 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -1938,8 +1938,9 @@ bool MemoryDepChecker::couldPreventStoreLoadForward(uint64_t Distance,
// cause any slowdowns.
const uint64_t NumItersForStoreLoadThroughMemory = 8 * TypeByteSize;
// Maximum vector factor.
+ // TODO: This "8" doesn't make any sense:
uint64_t MaxVFWithoutSLForwardIssuesPowerOf2 = std::min<uint64_t>(
- VectorizerParams::MaxVectorWidth, MaxStoreLoadForwardSafeNumElements);
+ VectorizerParams::MaxVectorWidth, MaxStoreLoadForwardSafeNumElements * 8);
// Compute the smallest VF at which the store and load would be misaligned.
for (uint64_t VF = 2; VF <= MaxVFWithoutSLForwardIssuesPowerOf2; VF *= 2) {
@@ -1961,7 +1962,7 @@ bool MemoryDepChecker::couldPreventStoreLoadForward(uint64_t Distance,
if (CommonStride &&
MaxVFWithoutSLForwardIssuesPowerOf2 <
- MaxStoreLoadForwardSafeNumElements &&
+ MaxStoreLoadForwardSafeNumElements * 8 &&
MaxVFWithoutSLForwardIssuesPowerOf2 != VectorizerParams::MaxVectorWidth) {
uint64_t MaxVF = bit_floor(MaxVFWithoutSLForwardIssuesPowerOf2 *
TypeByteSize / CommonStride);
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll b/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll
index e618401c90758..40e70ea13520f 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll
@@ -269,7 +269,7 @@ define void @two_store_load_forward_deps(ptr %A, ptr %B) {
; CHECK-NEXT: %vb = load i32, ptr %b.ld, align 4 ->
; CHECK-NEXT: store i32 %vb, ptr %b.st, align 4
; CHECK-EMPTY:
-; CHECK-NEXT: BackwardVectorizableButPreventsForwarding:
+; CHECK-NEXT: BackwardVectorizable:
; CHECK-NEXT: %va = load i32, ptr %a.ld, align 4 ->
; CHECK-NEXT: store i32 %va, ptr %a.st, align 4
; CHECK-EMPTY:
>From ea76e01ca1f8b1cb507067f8564ab991e0875589 Mon Sep 17 00:00:00 2001
From: Andrei Elovikov <andrei.elovikov at sifive.com>
Date: Mon, 3 Aug 2026 10:24:36 -0700
Subject: [PATCH 6/8] Drop the test from the incorrect place, going to add in a
separate PR
---
.../safe-with-dep-distance-non-power-of-2.ll | 61 -------------------
1 file changed, 61 deletions(-)
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll b/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll
index 40e70ea13520f..7f479b3f8c5f9 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/safe-with-dep-distance-non-power-of-2.ll
@@ -258,64 +258,3 @@ loop:
exit:
ret void
}
-
-define void @two_store_load_forward_deps(ptr %A, ptr %B) {
-; CHECK-LABEL: 'two_store_load_forward_deps'
-; 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: %vb = load i32, ptr %b.ld, align 4 ->
-; CHECK-NEXT: store i32 %vb, ptr %b.st, align 4
-; CHECK-EMPTY:
-; CHECK-NEXT: BackwardVectorizable:
-; CHECK-NEXT: %va = load i32, ptr %a.ld, align 4 ->
-; CHECK-NEXT: store i32 %va, ptr %a.st, align 4
-; CHECK-EMPTY:
-; CHECK-NEXT: Run-time memory checks:
-; CHECK-NEXT: Check 0:
-; CHECK-NEXT: Comparing group GRP0:
-; CHECK-NEXT: %a.ld = getelementptr i32, ptr %A, i64 %iv
-; CHECK-NEXT: %a.st = getelementptr i32, ptr %A, i64 %a.off
-; CHECK-NEXT: Against group GRP1:
-; CHECK-NEXT: %b.ld = getelementptr i32, ptr %B, i64 %ib
-; CHECK-NEXT: %b.st = getelementptr i32, ptr %B, i64 %b.off
-; CHECK-NEXT: Grouped accesses:
-; CHECK-NEXT: Group GRP0:
-; CHECK-NEXT: (Low: %A High: (4132 + %A))
-; CHECK-NEXT: Member: {%A,+,4}<nw><%loop>
-; CHECK-NEXT: Member: {(32 + %A),+,4}<nw><%loop>
-; CHECK-NEXT: Group GRP1:
-; CHECK-NEXT: (Low: %B High: (8220 + %B))
-; CHECK-NEXT: Member: {%B,+,8}<nw><%loop>
-; CHECK-NEXT: Member: {(24 + %B),+,8}<nw><%loop>
-; 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:
- br label %loop
-
-loop:
- %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
- %a.ld = getelementptr i32, ptr %A, i64 %iv
- %va = load i32, ptr %a.ld, align 4
- %a.off = add i64 %iv, 8
- %a.st = getelementptr i32, ptr %A, i64 %a.off
- store i32 %va, ptr %a.st, align 4
- %ib = shl i64 %iv, 1
- %b.ld = getelementptr i32, ptr %B, i64 %ib
- %vb = load i32, ptr %b.ld, align 4
- %b.off = add i64 %ib, 6
- %b.st = getelementptr i32, ptr %B, i64 %b.off
- store i32 %vb, ptr %b.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
-}
>From e74255f7e3b13ed3506f7cd8c1c79d2dc18aa971 Mon Sep 17 00:00:00 2001
From: Andrei Elovikov <andrei.elovikov at sifive.com>
Date: Mon, 3 Aug 2026 10:20:00 -0700
Subject: [PATCH 7/8] [LAA][NFC] Add a test for #191867
---
.../num-iters-for-store-load-conflict.ll | 100 ++++++++++++++++++
1 file changed, 100 insertions(+)
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 71eaa0ed2341e..4f76f07fe63ec 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
@@ -348,6 +348,106 @@ exit:
ret void
}
+; Same as above but with an unrelated store-to-load forwarding deps that do have
+; a safe VF. Make sure those aren't reported as ;
+; `BackwardVectorizableButPreventsForwarding`. We provide two of those (%B and
+; %C) becase the order of processing matters, so we have one lexically before %A
+; and another after ti.
+define void @fwd_conflict_dep_should_not_affect_another_dep(ptr %A, ptr %B, ptr %C) {
+; CHECK-LABEL: 'fwd_conflict_dep_should_not_affect_another_dep'
+; 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: BackwardVectorizable:
+; CHECK-NEXT: %ld.C = load i32, ptr %gep.C.ld, align 4 ->
+; CHECK-NEXT: store i32 %ld.C, ptr %gep.C.st, align 4
+; CHECK-EMPTY:
+; CHECK-NEXT: BackwardVectorizable:
+; CHECK-NEXT: %ld.B = load i32, ptr %gep.B.ld, align 4 ->
+; CHECK-NEXT: store i32 %ld.B, ptr %gep.B.st, align 4
+; CHECK-EMPTY:
+; CHECK-NEXT: Run-time memory checks:
+; CHECK-NEXT: Check 0:
+; CHECK-NEXT: Comparing group GRP0:
+; CHECK-NEXT: %gep.B.ld = getelementptr i32, ptr %B, i64 %iv
+; CHECK-NEXT: %gep.B.st = getelementptr i32, ptr %B.offset, i64 %iv
+; CHECK-NEXT: Against group GRP1:
+; CHECK-NEXT: %gep.ld = getelementptr i32, ptr %A, i64 %iv.x2
+; CHECK-NEXT: %gep.st = getelementptr i32, ptr %A.offset, i64 %iv.x2
+; CHECK-NEXT: Check 1:
+; CHECK-NEXT: Comparing group GRP0:
+; CHECK-NEXT: %gep.B.ld = getelementptr i32, ptr %B, i64 %iv
+; CHECK-NEXT: %gep.B.st = getelementptr i32, ptr %B.offset, i64 %iv
+; CHECK-NEXT: Against group GRP2:
+; CHECK-NEXT: %gep.C.ld = getelementptr i32, ptr %C, i64 %iv
+; CHECK-NEXT: %gep.C.st = getelementptr i32, ptr %C.offset, i64 %iv
+; CHECK-NEXT: Check 2:
+; CHECK-NEXT: Comparing group GRP1:
+; CHECK-NEXT: %gep.ld = getelementptr i32, ptr %A, i64 %iv.x2
+; CHECK-NEXT: %gep.st = getelementptr i32, ptr %A.offset, i64 %iv.x2
+; CHECK-NEXT: Against group GRP2:
+; CHECK-NEXT: %gep.C.ld = getelementptr i32, ptr %C, i64 %iv
+; CHECK-NEXT: %gep.C.st = getelementptr i32, ptr %C.offset, i64 %iv
+; CHECK-NEXT: Grouped accesses:
+; CHECK-NEXT: Group GRP0:
+; CHECK-NEXT: (Low: %B High: (4132 + %B))
+; CHECK-NEXT: Member: {%B,+,4}<nw><%loop>
+; CHECK-NEXT: Member: {(32 + %B),+,4}<nw><%loop>
+; CHECK-NEXT: Group GRP1:
+; CHECK-NEXT: (Low: %A High: (8220 + %A))
+; CHECK-NEXT: Member: {%A,+,8}<nw><%loop>
+; CHECK-NEXT: Member: {(24 + %A),+,8}<nw><%loop>
+; CHECK-NEXT: Group GRP2:
+; CHECK-NEXT: (Low: %C High: (4132 + %C))
+; CHECK-NEXT: Member: {%C,+,4}<nw><%loop>
+; CHECK-NEXT: Member: {(32 + %C),+,4}<nw><%loop>
+; 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
+ %B.offset = getelementptr i32, ptr %B, i64 8
+ %C.offset = getelementptr i32, ptr %C, i64 8
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+
+ ; VF <= 8 is safe for this dependency:
+ %gep.B.ld = getelementptr i32, ptr %B, i64 %iv
+ %ld.B = load i32, ptr %gep.B.ld, align 4
+ %gep.B.st = getelementptr i32, ptr %B.offset, i64 %iv
+ store i32 %ld.B, ptr %gep.B.st
+
+ ; Same as in `@stride2_store_load_preventing_forwarding`.
+ %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
+
+ ; VF <= 8 is safe for this dependency:
+ %gep.C.ld = getelementptr i32, ptr %C, i64 %iv
+ %ld.C = load i32, ptr %gep.C.ld, align 4
+ %gep.C.st = getelementptr i32, ptr %C.offset, i64 %iv
+ store i32 %ld.C, ptr %gep.C.st
+
+ %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 | | | | | | | | | | | | | | | |
>From 1d5711517d7ed48dbefebebe335102b6d9bcf281 Mon Sep 17 00:00:00 2001
From: Andrei Elovikov <andrei.elovikov at sifive.com>
Date: Mon, 3 Aug 2026 10:44:19 -0700
Subject: [PATCH 8/8] Drop unexplainable "* 8"
---
llvm/lib/Analysis/LoopAccessAnalysis.cpp | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index 7408d13cba3cb..d7b1f749f12c1 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -1938,12 +1938,11 @@ bool MemoryDepChecker::couldPreventStoreLoadForward(uint64_t Distance,
// cause any slowdowns.
const uint64_t NumItersForStoreLoadThroughMemory = 8 * TypeByteSize;
// Maximum vector factor.
- // TODO: This "8" doesn't make any sense:
uint64_t MaxVFWithoutSLForwardIssuesPowerOf2 = std::min<uint64_t>(
- VectorizerParams::MaxVectorWidth, MaxStoreLoadForwardSafeNumElements * 8);
+ VectorizerParams::MaxVectorWidth, MaxStoreLoadForwardSafeNumElements);
// Compute the smallest VF at which the store and load would be misaligned.
- for (uint64_t VF = 2; VF <= MaxVFWithoutSLForwardIssuesPowerOf2; VF *= 2) {
+ for (uint64_t VF = 2; VF <= VectorizerParams::MaxVectorWidth; VF *= 2) {
// If the number of vector iteration between the store and the load are
// small we could incur conflicts.
if (Distance % (VF * TypeByteSize) &&
@@ -1962,7 +1961,7 @@ bool MemoryDepChecker::couldPreventStoreLoadForward(uint64_t Distance,
if (CommonStride &&
MaxVFWithoutSLForwardIssuesPowerOf2 <
- MaxStoreLoadForwardSafeNumElements * 8 &&
+ MaxStoreLoadForwardSafeNumElements &&
MaxVFWithoutSLForwardIssuesPowerOf2 != VectorizerParams::MaxVectorWidth) {
uint64_t MaxVF = bit_floor(MaxVFWithoutSLForwardIssuesPowerOf2 *
TypeByteSize / CommonStride);
More information about the llvm-commits
mailing list