[llvm] [LAA] Give the symbolic strides map a named type (NFC) (PR #216731)
Guy David via llvm-commits
llvm-commits at lists.llvm.org
Sat Aug 29 14:02:19 PDT 2026
https://github.com/guy-david updated https://github.com/llvm/llvm-project/pull/216731
>From 1011b97b8f4f1780684ba9163855b2809518ceb8 Mon Sep 17 00:00:00 2001
From: Guy David <guyda96 at gmail.com>
Date: Mon, 17 Aug 2026 15:52:28 +0300
Subject: [PATCH 1/2] [LAA] Give the symbolic strides map a named type (NFC)
LoopAccessInfo collects SCEVUnknown strides, collectStridedAccess casts
to it when inserting, but the map was typed as holding a plain SCEV, so
the invariant had to be restated at each use.
---
.../llvm/Analysis/LoopAccessAnalysis.h | 21 ++++---
llvm/include/llvm/Analysis/VectorUtils.h | 2 +-
llvm/lib/Analysis/LoopAccessAnalysis.cpp | 59 +++++++++----------
llvm/lib/Analysis/VectorUtils.cpp | 2 +-
.../AArch64/AArch64TargetTransformInfo.cpp | 2 +-
.../Vectorize/LoopVectorizationLegality.cpp | 2 +-
.../Transforms/Vectorize/VPlanTransforms.cpp | 7 +--
.../Transforms/Vectorize/VPlanTransforms.h | 8 +--
8 files changed, 52 insertions(+), 51 deletions(-)
diff --git a/llvm/include/llvm/Analysis/LoopAccessAnalysis.h b/llvm/include/llvm/Analysis/LoopAccessAnalysis.h
index 392321448c895..897a85ae91ec8 100644
--- a/llvm/include/llvm/Analysis/LoopAccessAnalysis.h
+++ b/llvm/include/llvm/Analysis/LoopAccessAnalysis.h
@@ -55,6 +55,11 @@ struct VectorizerParams {
LLVM_ABI static bool HoistRuntimeChecks;
};
+/// Maps a pointer accessed with a symbolic (non-constant) stride to that
+/// stride. Users rely on the stride being loop invariant- only SCEVUnknown
+/// strides are ever collected, which is a conservative proxy for that.
+using SymbolicStrideMap = DenseMap<Value *, const SCEVUnknown *>;
+
/// Checks memory dependences among accesses to the same underlying
/// object to determine whether there vectorization is legal or not (and at
/// which vectorization factor).
@@ -188,7 +193,7 @@ class MemoryDepChecker {
MemoryDepChecker(PredicatedScalarEvolution &PSE, AssumptionCache *AC,
DominatorTree *DT, const Loop *L,
- const DenseMap<Value *, const SCEV *> &SymbolicStrides,
+ const SymbolicStrideMap &SymbolicStrides,
unsigned MaxTargetVectorWidthInBits,
std::optional<ScalarEvolution::LoopGuards> &LoopGuards)
: PSE(PSE), AC(AC), DT(DT), InnermostLoop(L),
@@ -323,7 +328,7 @@ class MemoryDepChecker {
/// Reference to map of pointer values to
/// their stride symbols, if they have a symbolic stride.
- const DenseMap<Value *, const SCEV *> &SymbolicStrides;
+ const SymbolicStrideMap &SymbolicStrides;
/// Maps access locations (ptr, read/write) to program order.
DenseMap<MemAccessInfo, std::vector<unsigned> > Accesses;
@@ -754,7 +759,7 @@ class LoopAccessInfo {
/// If an access has a symbolic strides, this maps the pointer value to
/// the stride symbol.
- const DenseMap<Value *, const SCEV *> &getSymbolicStrides() const {
+ const SymbolicStrideMap &getSymbolicStrides() const {
return SymbolicStrides;
}
@@ -862,7 +867,7 @@ class LoopAccessInfo {
/// If an access has a symbolic strides, this maps the pointer value to
/// the stride symbol.
- DenseMap<Value *, const SCEV *> SymbolicStrides;
+ SymbolicStrideMap SymbolicStrides;
};
/// Return the SCEV corresponding to a pointer with the symbolic stride
@@ -876,8 +881,7 @@ class LoopAccessInfo {
/// stride as collected by LoopVectorizationLegality::collectStridedAccess.
LLVM_ABI const SCEV *
replaceSymbolicStrideSCEV(PredicatedScalarEvolution &PSE,
- const DenseMap<Value *, const SCEV *> &PtrToStride,
- Value *Ptr);
+ const SymbolicStrideMap &PtrToStride, Value *Ptr);
/// If \p AR is an affine AddRec for \p Lp with a constant step, return the
/// step in units of \p AccessTy's allocation size. Returns std::nullopt if the
@@ -905,8 +909,7 @@ getStrideFromAddRec(const SCEVAddRecExpr *AR, const Loop *Lp, Type *AccessTy,
LLVM_ABI std::optional<int64_t>
getPtrStride(PredicatedScalarEvolution &PSE, Type *AccessTy, Value *Ptr,
const Loop *Lp, const DominatorTree &DT,
- const DenseMap<Value *, const SCEV *> &StridesMap =
- DenseMap<Value *, const SCEV *>(),
+ const SymbolicStrideMap &StridesMap = SymbolicStrideMap(),
bool ShouldCheckWrap = true,
SmallVectorImpl<const SCEVPredicate *> *Predicates = nullptr);
@@ -916,7 +919,7 @@ getPtrStride(PredicatedScalarEvolution &PSE, Type *AccessTy, Value *Ptr,
LLVM_ABI std::optional<int64_t>
getPtrStride(PredicatedScalarEvolution &PSE, Type *AccessTy, Value *Ptr,
const Loop *Lp, const DominatorTree &DT,
- const DenseMap<Value *, const SCEV *> &StridesMap, bool Assume,
+ const SymbolicStrideMap &StridesMap, bool Assume,
bool ShouldCheckWrap = true);
/// Returns the distance between the pointers \p PtrA and \p PtrB iff they are
diff --git a/llvm/include/llvm/Analysis/VectorUtils.h b/llvm/include/llvm/Analysis/VectorUtils.h
index f70ae3ff57f88..b177d9eec2189 100644
--- a/llvm/include/llvm/Analysis/VectorUtils.h
+++ b/llvm/include/llvm/Analysis/VectorUtils.h
@@ -812,7 +812,7 @@ class InterleavedAccessInfo {
/// Predicates if it is not nullptr.
void collectConstStrideAccesses(
MapVector<Instruction *, StrideDescriptor> &AccessStrideInfo,
- const DenseMap<Value *, const SCEV *> &Strides,
+ const SymbolicStrideMap &Strides,
SmallVectorImpl<const SCEVPredicate *> *Predicates);
/// Returns true if \p Stride is allowed in an interleaved group.
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index 9b407b1ca4729..97ce5a9a358aa 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -153,24 +153,19 @@ bool VectorizerParams::isInterleaveForced() {
return ::VectorizationInterleave.getNumOccurrences() > 0;
}
-const SCEV *llvm::replaceSymbolicStrideSCEV(PredicatedScalarEvolution &PSE,
- const DenseMap<Value *, const SCEV *> &PtrToStride,
- Value *Ptr) {
+const SCEV *
+llvm::replaceSymbolicStrideSCEV(PredicatedScalarEvolution &PSE,
+ const SymbolicStrideMap &PtrToStride,
+ Value *Ptr) {
const SCEV *OrigSCEV = PSE.getSCEV(Ptr);
// If there is an entry in the map return the SCEV of the pointer with the
// symbolic stride replaced by one.
- const SCEV *StrideSCEV = PtrToStride.lookup(Ptr);
+ const SCEVUnknown *StrideSCEV = PtrToStride.lookup(Ptr);
if (!StrideSCEV)
// For a non-symbolic stride, just return the original expression.
return OrigSCEV;
- // Note: This assert is both overly strong and overly weak. The actual
- // invariant here is that StrideSCEV should be loop invariant. The only
- // such invariant strides we happen to speculate right now are unknowns
- // and thus this is a reasonable proxy of the actual invariant.
- assert(isa<SCEVUnknown>(StrideSCEV) && "shouldn't be in map");
-
ScalarEvolution *SE = PSE.getSE();
const SCEV *CT = SE->getOne(StrideSCEV->getType());
PSE.addPredicate(*SE->getEqualPredicate(StrideSCEV, CT));
@@ -862,7 +857,7 @@ class AccessAnalysis {
/// the bounds of the pointer.
bool createCheckForAccess(RuntimePointerChecking &RtCheck,
MemAccessInfo Access, Type *AccessTy,
- const DenseMap<Value *, const SCEV *> &Strides,
+ const SymbolicStrideMap &Strides,
DenseMap<Value *, unsigned> &DepSetId,
Loop *TheLoop, unsigned &RunningDepId,
unsigned ASId, bool Assume);
@@ -877,7 +872,7 @@ class AccessAnalysis {
/// pointers we could analyze. \p DepChecker is used to remove unknown
/// dependences from DepCands.
bool canCheckPtrAtRT(RuntimePointerChecking &RtCheck, Loop *TheLoop,
- const DenseMap<Value *, const SCEV *> &Strides,
+ const SymbolicStrideMap &Strides,
Value *&UncomputablePtr, bool AllowPartial,
const MemoryDepChecker &DepChecker);
@@ -1281,11 +1276,12 @@ static void findForkedSCEVs(
}
}
-bool AccessAnalysis::createCheckForAccess(
- RuntimePointerChecking &RtCheck, MemAccessInfo Access, Type *AccessTy,
- const DenseMap<Value *, const SCEV *> &StridesMap,
- DenseMap<Value *, unsigned> &DepSetId, Loop *TheLoop,
- unsigned &RunningDepId, unsigned ASId, bool Assume) {
+bool AccessAnalysis::createCheckForAccess(RuntimePointerChecking &RtCheck,
+ MemAccessInfo Access, Type *AccessTy,
+ const SymbolicStrideMap &StridesMap,
+ DenseMap<Value *, unsigned> &DepSetId,
+ Loop *TheLoop, unsigned &RunningDepId,
+ unsigned ASId, bool Assume) {
Value *Ptr = Access.getPointer();
ScalarEvolution *SE = PSE.getSE();
assert(SE->isSCEVable(Ptr->getType()) && "Value is not SCEVable!");
@@ -1366,10 +1362,11 @@ bool AccessAnalysis::createCheckForAccess(
return true;
}
-bool AccessAnalysis::canCheckPtrAtRT(
- RuntimePointerChecking &RtCheck, Loop *TheLoop,
- const DenseMap<Value *, const SCEV *> &StridesMap, Value *&UncomputablePtr,
- bool AllowPartial, const MemoryDepChecker &DepChecker) {
+bool AccessAnalysis::canCheckPtrAtRT(RuntimePointerChecking &RtCheck,
+ Loop *TheLoop,
+ const SymbolicStrideMap &StridesMap,
+ Value *&UncomputablePtr, bool AllowPartial,
+ const MemoryDepChecker &DepChecker) {
// Find pointers with computable bounds. We are going to use this information
// to place a runtime bound check.
bool CanDoRT = true;
@@ -1670,10 +1667,11 @@ void AccessAnalysis::buildDependenceSets() {
}
/// Check whether the access through \p Ptr has a constant stride.
-std::optional<int64_t> llvm::getPtrStride(
- PredicatedScalarEvolution &PSE, Type *AccessTy, Value *Ptr, const Loop *Lp,
- const DominatorTree &DT, const DenseMap<Value *, const SCEV *> &StridesMap,
- bool ShouldCheckWrap, SmallVectorImpl<const SCEVPredicate *> *Predicates) {
+std::optional<int64_t>
+llvm::getPtrStride(PredicatedScalarEvolution &PSE, Type *AccessTy, Value *Ptr,
+ const Loop *Lp, const DominatorTree &DT,
+ const SymbolicStrideMap &StridesMap, bool ShouldCheckWrap,
+ SmallVectorImpl<const SCEVPredicate *> *Predicates) {
const SCEV *PtrScev = replaceSymbolicStrideSCEV(PSE, StridesMap, Ptr);
if (PSE.getSE()->isLoopInvariant(PtrScev, Lp))
return 0;
@@ -1707,11 +1705,12 @@ std::optional<int64_t> llvm::getPtrStride(
}
/// Check whether the access through \p Ptr has a constant stride.
-std::optional<int64_t>
-llvm::getPtrStride(PredicatedScalarEvolution &PSE, Type *AccessTy, Value *Ptr,
- const Loop *Lp, const DominatorTree &DT,
- const DenseMap<Value *, const SCEV *> &StridesMap,
- bool Assume, bool ShouldCheckWrap) {
+std::optional<int64_t> llvm::getPtrStride(PredicatedScalarEvolution &PSE,
+ Type *AccessTy, Value *Ptr,
+ const Loop *Lp,
+ const DominatorTree &DT,
+ const SymbolicStrideMap &StridesMap,
+ bool Assume, bool ShouldCheckWrap) {
SmallVector<const SCEVPredicate *> Predicates;
std::optional<int64_t> Stride =
getPtrStride(PSE, AccessTy, Ptr, Lp, DT, StridesMap, ShouldCheckWrap,
diff --git a/llvm/lib/Analysis/VectorUtils.cpp b/llvm/lib/Analysis/VectorUtils.cpp
index 251bf0d5f04be..f28fc4afc70ef 100644
--- a/llvm/lib/Analysis/VectorUtils.cpp
+++ b/llvm/lib/Analysis/VectorUtils.cpp
@@ -1290,7 +1290,7 @@ bool InterleavedAccessInfo::isStrided(int Stride) {
void InterleavedAccessInfo::collectConstStrideAccesses(
MapVector<Instruction *, StrideDescriptor> &AccessStrideInfo,
- const DenseMap<Value *, const SCEV *> &Strides,
+ const SymbolicStrideMap &Strides,
SmallVectorImpl<const SCEVPredicate *> *Predicates) {
auto &DL = TheLoop->getHeader()->getDataLayout();
diff --git a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
index 67659ad6814f5..23ae28623936f 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetTransformInfo.cpp
@@ -7230,7 +7230,7 @@ AArch64TTIImpl::getShuffleCost(TTI::ShuffleKind Kind, VectorType *DstTy,
static bool containsDecreasingPointers(Loop *TheLoop,
PredicatedScalarEvolution *PSE,
const DominatorTree &DT) {
- const auto &Strides = DenseMap<Value *, const SCEV *>();
+ const auto &Strides = SymbolicStrideMap();
for (BasicBlock *BB : TheLoop->blocks()) {
// Scan the instructions in the block and look for addresses that are
// consecutive and decreasing.
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
index f1d785b571367..e05147ab7a3e5 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
@@ -462,7 +462,7 @@ int LoopVectorizationLegality::isConsecutivePtr(Type *AccessTy,
// the symbolic strides when runtime SCEV checks are permitted.
const auto &Strides = LAI && AllowRuntimeSCEVChecks
? LAI->getSymbolicStrides()
- : DenseMap<Value *, const SCEV *>();
+ : SymbolicStrideMap();
SmallVector<const SCEVPredicate *> Predicates;
int Stride = getPtrStride(PSE, AccessTy, Ptr, TheLoop, *DT, Strides, false,
AllowRuntimeSCEVChecks ? &Predicates : nullptr)
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
index dd85eeaa8592c..eb2be8f0af826 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp
@@ -2603,8 +2603,7 @@ void VPlanTransforms::simplifyLiveInsWithSCEV(VPlan &Plan,
void VPlanTransforms::replaceSymbolicStrides(
VPlan &Plan, PredicatedScalarEvolution &PSE,
- const DenseMap<Value *, const SCEV *> &StridesMap,
- const VPDominatorTree &VPDT) {
+ const SymbolicStrideMap &StridesMap, const VPDominatorTree &VPDT) {
// Replace VPValues for known constant strides guaranteed by predicated scalar
// evolution that are guaranteed to be guarded by the runtime checks; that is,
// blocks dominated by the vector header.
@@ -2621,8 +2620,8 @@ void VPlanTransforms::replaceSymbolicStrides(
return VPDT.dominates(Header, R->getParent());
};
ValueToSCEVMapTy RewriteMap;
- for (const SCEV *Stride : StridesMap.values()) {
- Value *StrideV = cast<SCEVUnknown>(Stride)->getValue();
+ for (const SCEVUnknown *Stride : StridesMap.values()) {
+ Value *StrideV = Stride->getValue();
const APInt *StrideConst;
const SCEV *StrideExpr = PSE.getSCEV(StrideV);
if (!match(StrideExpr, m_scev_APInt(StrideConst)))
diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
index a3922a858a3f5..006f3a2d1aa1b 100644
--- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
+++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.h
@@ -317,10 +317,10 @@ struct VPlanTransforms {
/// Replace symbolic strides from \p StridesMap in \p Plan with constants when
/// possible.
- static void
- replaceSymbolicStrides(VPlan &Plan, PredicatedScalarEvolution &PSE,
- const DenseMap<Value *, const SCEV *> &StridesMap,
- const VPDominatorTree &VPDT);
+ static void replaceSymbolicStrides(VPlan &Plan,
+ PredicatedScalarEvolution &PSE,
+ const SymbolicStrideMap &StridesMap,
+ const VPDominatorTree &VPDT);
/// Drop poison flags from recipes that may generate a poison value that is
/// used after vectorization, even when their operands are not poison. Those
>From c4914ff386500de28c8754a88a58da205305490f Mon Sep 17 00:00:00 2001
From: Guy David <guyda96 at gmail.com>
Date: Tue, 18 Aug 2026 13:12:33 +0300
Subject: [PATCH 2/2] Address comments 1
---
llvm/include/llvm/Analysis/LoopAccessAnalysis.h | 5 ++---
llvm/lib/Analysis/LoopAccessAnalysis.cpp | 2 ++
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/Analysis/LoopAccessAnalysis.h b/llvm/include/llvm/Analysis/LoopAccessAnalysis.h
index 897a85ae91ec8..a0f4f45f66b13 100644
--- a/llvm/include/llvm/Analysis/LoopAccessAnalysis.h
+++ b/llvm/include/llvm/Analysis/LoopAccessAnalysis.h
@@ -55,9 +55,8 @@ struct VectorizerParams {
LLVM_ABI static bool HoistRuntimeChecks;
};
-/// Maps a pointer accessed with a symbolic (non-constant) stride to that
-/// stride. Users rely on the stride being loop invariant- only SCEVUnknown
-/// strides are ever collected, which is a conservative proxy for that.
+/// Maps a pointer to its symbolic (non-constant) stride. Strides are loop
+/// invariant, which collectStridedAccess checks before inserting.
using SymbolicStrideMap = DenseMap<Value *, const SCEVUnknown *>;
/// Checks memory dependences among accesses to the same underlying
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index 97ce5a9a358aa..3d763a452267e 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -3186,6 +3186,8 @@ void LoopAccessInfo::collectStridedAccess(Value *MemAccess) {
const SCEV *StrideBase = StrideExpr;
if (const auto *C = dyn_cast<SCEVIntegralCastExpr>(StrideBase))
StrideBase = C->getOperand();
+ assert(SE->isLoopInvariant(StrideBase, TheLoop) &&
+ "users of the map rely on the stride being loop invariant");
SymbolicStrides[Ptr] = cast<SCEVUnknown>(StrideBase);
}
More information about the llvm-commits
mailing list