[llvm] [polly] [delinearize] use SCEV exprs in getIndexExpressionsFromGEP (PR #162888)
Sebastian Pop via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 3 19:20:19 PST 2025
https://github.com/sebpop updated https://github.com/llvm/llvm-project/pull/162888
>From 12bdde54346700ce5bf2564d08bf56f09070ab85 Mon Sep 17 00:00:00 2001
From: Sebastian Pop <spop at nvidia.com>
Date: Fri, 10 Oct 2025 12:01:57 -0500
Subject: [PATCH 1/2] [delinearize] use SCEV exprs in
getIndexExpressionsFromGEP
---
llvm/include/llvm/Analysis/Delinearization.h | 12 ++++++------
llvm/lib/Analysis/Delinearization.cpp | 5 +++--
llvm/lib/Analysis/DependenceAnalysis.cpp | 2 +-
polly/lib/Analysis/ScopBuilder.cpp | 10 +++-------
4 files changed, 13 insertions(+), 16 deletions(-)
diff --git a/llvm/include/llvm/Analysis/Delinearization.h b/llvm/include/llvm/Analysis/Delinearization.h
index b9fc0bcf47430..8fb30925b1ba7 100644
--- a/llvm/include/llvm/Analysis/Delinearization.h
+++ b/llvm/include/llvm/Analysis/Delinearization.h
@@ -154,15 +154,15 @@ bool validateDelinearizationResult(ScalarEvolution &SE,
///
/// This function optimistically assumes the GEP references into a fixed size
/// array. If this is actually true, this function returns a list of array
-/// subscript expressions in \p Subscripts and a list of integers describing
-/// the size of the individual array dimensions in \p Sizes. Both lists have
-/// either equal length or the size list is one element shorter in case there
-/// is no known size available for the outermost array dimension. Returns true
-/// if successful and false otherwise.
+/// subscript expressions in \p Subscripts and a list of SCEV expressions
+/// describing the size of the individual array dimensions in \p Sizes. Both
+/// lists have either equal length or the size list is one element shorter in
+/// case there is no known size available for the outermost array dimension.
+/// Returns true if successful and false otherwise.
bool getIndexExpressionsFromGEP(ScalarEvolution &SE,
const GetElementPtrInst *GEP,
SmallVectorImpl<const SCEV *> &Subscripts,
- SmallVectorImpl<int> &Sizes);
+ SmallVectorImpl<const SCEV *> &Sizes);
struct DelinearizationPrinterPass
: public PassInfoMixin<DelinearizationPrinterPass> {
diff --git a/llvm/lib/Analysis/Delinearization.cpp b/llvm/lib/Analysis/Delinearization.cpp
index 686622feec477..c2a429ffdfe9a 100644
--- a/llvm/lib/Analysis/Delinearization.cpp
+++ b/llvm/lib/Analysis/Delinearization.cpp
@@ -824,7 +824,7 @@ bool llvm::validateDelinearizationResult(ScalarEvolution &SE,
bool llvm::getIndexExpressionsFromGEP(ScalarEvolution &SE,
const GetElementPtrInst *GEP,
SmallVectorImpl<const SCEV *> &Subscripts,
- SmallVectorImpl<int> &Sizes) {
+ SmallVectorImpl<const SCEV *> &Sizes) {
assert(Subscripts.empty() && Sizes.empty() &&
"Expected output lists to be empty on entry to this function.");
assert(GEP && "getIndexExpressionsFromGEP called with a null GEP");
@@ -855,7 +855,8 @@ bool llvm::getIndexExpressionsFromGEP(ScalarEvolution &SE,
Subscripts.push_back(Expr);
if (!(DroppedFirstDim && i == 2))
- Sizes.push_back(ArrayTy->getNumElements());
+ Sizes.push_back(SE.getConstant(Expr->getType(),
+ ArrayTy->getNumElements()));
Ty = ArrayTy->getElementType();
}
diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
index fe07b7edb6713..b0cfaf6e5272b 100644
--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
+++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
@@ -3265,7 +3265,7 @@ bool DependenceInfo::tryDelinearizeFixedSize(
return false;
// Check that the two size arrays are non-empty and equal in length and
- // value.
+ // value. SCEV expressions are uniqued, so we can compare pointers.
if (SrcSizes.size() != DstSizes.size() ||
!std::equal(SrcSizes.begin(), SrcSizes.end(), DstSizes.begin())) {
SrcSubscripts.clear();
diff --git a/polly/lib/Analysis/ScopBuilder.cpp b/polly/lib/Analysis/ScopBuilder.cpp
index 60a1e00916750..0f96c89232499 100644
--- a/polly/lib/Analysis/ScopBuilder.cpp
+++ b/polly/lib/Analysis/ScopBuilder.cpp
@@ -1464,7 +1464,7 @@ bool ScopBuilder::buildAccessMultiDimFixed(MemAccInst Inst, ScopStmt *Stmt) {
return false;
SmallVector<const SCEV *, 4> Subscripts;
- SmallVector<int, 4> Sizes;
+ SmallVector<const SCEV *, 4> Sizes;
getIndexExpressionsFromGEP(SE, GEP, Subscripts, Sizes);
auto *BasePtr = GEP->getOperand(0);
@@ -1476,8 +1476,6 @@ bool ScopBuilder::buildAccessMultiDimFixed(MemAccInst Inst, ScopStmt *Stmt) {
if (BasePtr != BasePointer->getValue())
return false;
- std::vector<const SCEV *> SizesSCEV;
-
const InvariantLoadsSetTy &ScopRIL = scop->getRequiredInvariantLoads();
Loop *SurroundingLoop = Stmt->getSurroundingLoop();
@@ -1495,11 +1493,9 @@ bool ScopBuilder::buildAccessMultiDimFixed(MemAccInst Inst, ScopStmt *Stmt) {
if (Sizes.empty())
return false;
+ std::vector<const SCEV *> SizesSCEV;
SizesSCEV.push_back(nullptr);
-
- for (auto V : Sizes)
- SizesSCEV.push_back(SE.getSCEV(
- ConstantInt::get(IntegerType::getInt64Ty(BasePtr->getContext()), V)));
+ SizesSCEV.insert(SizesSCEV.end(), Sizes.begin(), Sizes.end());
addArrayAccess(Stmt, Inst, AccType, BasePointer->getValue(), ElementType,
true, Subscripts, SizesSCEV, Val);
>From 3399008cc6e0af5822df38beec98d26ae6e1a5dd Mon Sep 17 00:00:00 2001
From: Sebastian Pop <spop at nvidia.com>
Date: Wed, 3 Dec 2025 21:16:04 -0600
Subject: [PATCH 2/2] [delinearize] use DataLayout index type in
getIndexExpressionsFromGEP
Use SE.getEffectiveSCEVType(GEP->getPointerOperandType()) to get the
correct pointer index sized integer type for the SCEV constant sizes,
instead of using the type of the expression. This ensures the sizes
have the correct type for the target's address space.
---
...SCEV-exprs-in-getIndexExpressionsFro.patch | 200 ++++++++++++++++++
llvm/lib/Analysis/Delinearization.cpp | 4 +-
2 files changed, 202 insertions(+), 2 deletions(-)
create mode 100644 0001-delinearize-use-SCEV-exprs-in-getIndexExpressionsFro.patch
diff --git a/0001-delinearize-use-SCEV-exprs-in-getIndexExpressionsFro.patch b/0001-delinearize-use-SCEV-exprs-in-getIndexExpressionsFro.patch
new file mode 100644
index 0000000000000..e2d4329929f00
--- /dev/null
+++ b/0001-delinearize-use-SCEV-exprs-in-getIndexExpressionsFro.patch
@@ -0,0 +1,200 @@
+From 7f9239030a10aa26d7002cc05ec92d935c43c45a Mon Sep 17 00:00:00 2001
+From: Sebastian Pop <spop at nvidia.com>
+Date: Fri, 10 Oct 2025 12:01:57 -0500
+Subject: [PATCH] [delinearize] use SCEV exprs in getIndexExpressionsFromGEP
+
+---
+ llvm/include/llvm/Analysis/Delinearization.h | 14 +++++-----
+ llvm/lib/Analysis/Delinearization.cpp | 7 ++---
+ llvm/lib/Analysis/DependenceAnalysis.cpp | 27 +++++++++-----------
+ llvm/lib/Analysis/LoopCacheAnalysis.cpp | 5 ++--
+ polly/lib/Analysis/ScopBuilder.cpp | 10 +++-----
+ 5 files changed, 28 insertions(+), 35 deletions(-)
+
+diff --git a/llvm/include/llvm/Analysis/Delinearization.h b/llvm/include/llvm/Analysis/Delinearization.h
+index 434cfb61699d..9c729b5cf18c 100644
+--- a/llvm/include/llvm/Analysis/Delinearization.h
++++ b/llvm/include/llvm/Analysis/Delinearization.h
+@@ -145,15 +145,15 @@ bool delinearizeFixedSizeArray(ScalarEvolution &SE, const SCEV *Expr,
+ ///
+ /// This function optimistically assumes the GEP references into a fixed size
+ /// array. If this is actually true, this function returns a list of array
+-/// subscript expressions in \p Subscripts and a list of integers describing
+-/// the size of the individual array dimensions in \p Sizes. Both lists have
+-/// either equal length or the size list is one element shorter in case there
+-/// is no known size available for the outermost array dimension. Returns true
+-/// if successful and false otherwise.
++/// subscript expressions in \p Subscripts and a list of SCEV expressions
++/// describing the size of the individual array dimensions in \p Sizes. Both
++/// lists have either equal length or the size list is one element shorter in
++/// case there is no known size available for the outermost array dimension.
++/// Returns true if successful and false otherwise.
+ bool getIndexExpressionsFromGEP(ScalarEvolution &SE,
+ const GetElementPtrInst *GEP,
+ SmallVectorImpl<const SCEV *> &Subscripts,
+- SmallVectorImpl<int> &Sizes);
++ SmallVectorImpl<const SCEV *> &Sizes);
+
+ /// Implementation of fixed size array delinearization. Try to delinearize
+ /// access function for a fixed size multi-dimensional array, by deriving
+@@ -164,7 +164,7 @@ bool getIndexExpressionsFromGEP(ScalarEvolution &SE,
+ bool tryDelinearizeFixedSizeImpl(ScalarEvolution *SE, Instruction *Inst,
+ const SCEV *AccessFn,
+ SmallVectorImpl<const SCEV *> &Subscripts,
+- SmallVectorImpl<int> &Sizes);
++ SmallVectorImpl<const SCEV *> &Sizes);
+
+ struct DelinearizationPrinterPass
+ : public PassInfoMixin<DelinearizationPrinterPass> {
+diff --git a/llvm/lib/Analysis/Delinearization.cpp b/llvm/lib/Analysis/Delinearization.cpp
+index 4064b25d9d4e..f438a9bd9ecd 100644
+--- a/llvm/lib/Analysis/Delinearization.cpp
++++ b/llvm/lib/Analysis/Delinearization.cpp
+@@ -659,7 +659,7 @@ bool llvm::delinearizeFixedSizeArray(ScalarEvolution &SE, const SCEV *Expr,
+ bool llvm::getIndexExpressionsFromGEP(ScalarEvolution &SE,
+ const GetElementPtrInst *GEP,
+ SmallVectorImpl<const SCEV *> &Subscripts,
+- SmallVectorImpl<int> &Sizes) {
++ SmallVectorImpl<const SCEV *> &Sizes) {
+ assert(Subscripts.empty() && Sizes.empty() &&
+ "Expected output lists to be empty on entry to this function.");
+ assert(GEP && "getIndexExpressionsFromGEP called with a null GEP");
+@@ -690,7 +690,8 @@ bool llvm::getIndexExpressionsFromGEP(ScalarEvolution &SE,
+
+ Subscripts.push_back(Expr);
+ if (!(DroppedFirstDim && i == 2))
+- Sizes.push_back(ArrayTy->getNumElements());
++ Sizes.push_back(SE.getConstant(Expr->getType(),
++ ArrayTy->getNumElements()));
+
+ Ty = ArrayTy->getElementType();
+ }
+@@ -706,7 +707,7 @@ bool llvm::getIndexExpressionsFromGEP(ScalarEvolution &SE,
+
+ bool llvm::tryDelinearizeFixedSizeImpl(
+ ScalarEvolution *SE, Instruction *Inst, const SCEV *AccessFn,
+- SmallVectorImpl<const SCEV *> &Subscripts, SmallVectorImpl<int> &Sizes) {
++ SmallVectorImpl<const SCEV *> &Subscripts, SmallVectorImpl<const SCEV *> &Sizes) {
+ Value *SrcPtr = getLoadStorePointerOperand(Inst);
+
+ // Check the simple case where the array dimensions are fixed size.
+diff --git a/llvm/lib/Analysis/DependenceAnalysis.cpp b/llvm/lib/Analysis/DependenceAnalysis.cpp
+index 8d20b0e10305..7dd0bea75c84 100644
+--- a/llvm/lib/Analysis/DependenceAnalysis.cpp
++++ b/llvm/lib/Analysis/DependenceAnalysis.cpp
+@@ -3504,8 +3504,8 @@ bool DependenceInfo::tryDelinearizeFixedSize(
+ "expected src and dst scev unknowns to be equal");
+ });
+
+- SmallVector<int, 4> SrcSizes;
+- SmallVector<int, 4> DstSizes;
++ SmallVector<const SCEV *, 4> SrcSizes;
++ SmallVector<const SCEV *, 4> DstSizes;
+ if (!tryDelinearizeFixedSizeImpl(SE, Src, SrcAccessFn, SrcSubscripts,
+ SrcSizes) ||
+ !tryDelinearizeFixedSizeImpl(SE, Dst, DstAccessFn, DstSubscripts,
+@@ -3513,7 +3513,7 @@ bool DependenceInfo::tryDelinearizeFixedSize(
+ return false;
+
+ // Check that the two size arrays are non-empty and equal in length and
+- // value.
++ // value. SCEV expressions are uniqued, so we can compare pointers.
+ if (SrcSizes.size() != DstSizes.size() ||
+ !std::equal(SrcSizes.begin(), SrcSizes.end(), DstSizes.begin())) {
+ SrcSubscripts.clear();
+@@ -3535,7 +3535,7 @@ bool DependenceInfo::tryDelinearizeFixedSize(
+ // iff the subscripts are positive and are less than the range of the
+ // dimension.
+ if (!DisableDelinearizationChecks) {
+- auto AllIndicesInRange = [&](SmallVector<int, 4> &DimensionSizes,
++ auto AllIndicesInRange = [&](SmallVector<const SCEV *, 4> &DimensionSizes,
+ SmallVectorImpl<const SCEV *> &Subscripts,
+ Value *Ptr) {
+ size_t SSize = Subscripts.size();
+@@ -3548,17 +3548,14 @@ bool DependenceInfo::tryDelinearizeFixedSize(
+ });
+ return false;
+ }
+- if (auto *SType = dyn_cast<IntegerType>(S->getType())) {
+- const SCEV *Range = SE->getConstant(
+- ConstantInt::get(SType, DimensionSizes[I - 1], false));
+- if (!isKnownLessThan(S, Range)) {
+- LLVM_DEBUG({
+- dbgs() << "Check failed: !isKnownLessThan(S, Range)\n";
+- dbgs() << " S: " << *S << "\n"
+- << " Range: " << *Range << "\n";
+- });
+- return false;
+- }
++ const SCEV *Range = DimensionSizes[I - 1];
++ if (!isKnownLessThan(S, Range)) {
++ LLVM_DEBUG({
++ dbgs() << "Check failed: !isKnownLessThan(S, Range)\n";
++ dbgs() << " S: " << *S << "\n"
++ << " Range: " << *Range << "\n";
++ });
++ return false;
+ }
+ }
+ return true;
+diff --git a/llvm/lib/Analysis/LoopCacheAnalysis.cpp b/llvm/lib/Analysis/LoopCacheAnalysis.cpp
+index 050c32707596..74bcce8f51a4 100644
+--- a/llvm/lib/Analysis/LoopCacheAnalysis.cpp
++++ b/llvm/lib/Analysis/LoopCacheAnalysis.cpp
+@@ -356,15 +356,14 @@ CacheCostTy IndexedReference::computeRefCost(const Loop &L,
+
+ bool IndexedReference::tryDelinearizeFixedSize(
+ const SCEV *AccessFn, SmallVectorImpl<const SCEV *> &Subscripts) {
+- SmallVector<int, 4> ArraySizes;
++ SmallVector<const SCEV *, 4> ArraySizes;
+ if (!tryDelinearizeFixedSizeImpl(&SE, &StoreOrLoadInst, AccessFn, Subscripts,
+ ArraySizes))
+ return false;
+
+ // Populate Sizes with scev expressions to be used in calculations later.
+ for (auto Idx : seq<unsigned>(1, Subscripts.size()))
+- Sizes.push_back(
+- SE.getConstant(Subscripts[Idx]->getType(), ArraySizes[Idx - 1]));
++ Sizes.push_back(ArraySizes[Idx - 1]);
+
+ LLVM_DEBUG({
+ dbgs() << "Delinearized subscripts of fixed-size array\n"
+diff --git a/polly/lib/Analysis/ScopBuilder.cpp b/polly/lib/Analysis/ScopBuilder.cpp
+index 67a4c4345580..ec77b15ddd76 100644
+--- a/polly/lib/Analysis/ScopBuilder.cpp
++++ b/polly/lib/Analysis/ScopBuilder.cpp
+@@ -1463,7 +1463,7 @@ bool ScopBuilder::buildAccessMultiDimFixed(MemAccInst Inst, ScopStmt *Stmt) {
+ return false;
+
+ SmallVector<const SCEV *, 4> Subscripts;
+- SmallVector<int, 4> Sizes;
++ SmallVector<const SCEV *, 4> Sizes;
+ getIndexExpressionsFromGEP(SE, GEP, Subscripts, Sizes);
+ auto *BasePtr = GEP->getOperand(0);
+
+@@ -1475,8 +1475,6 @@ bool ScopBuilder::buildAccessMultiDimFixed(MemAccInst Inst, ScopStmt *Stmt) {
+ if (BasePtr != BasePointer->getValue())
+ return false;
+
+- std::vector<const SCEV *> SizesSCEV;
+-
+ const InvariantLoadsSetTy &ScopRIL = scop->getRequiredInvariantLoads();
+
+ Loop *SurroundingLoop = Stmt->getSurroundingLoop();
+@@ -1494,11 +1492,9 @@ bool ScopBuilder::buildAccessMultiDimFixed(MemAccInst Inst, ScopStmt *Stmt) {
+ if (Sizes.empty())
+ return false;
+
++ std::vector<const SCEV *> SizesSCEV;
+ SizesSCEV.push_back(nullptr);
+-
+- for (auto V : Sizes)
+- SizesSCEV.push_back(SE.getSCEV(
+- ConstantInt::get(IntegerType::getInt64Ty(BasePtr->getContext()), V)));
++ SizesSCEV.insert(SizesSCEV.end(), Sizes.begin(), Sizes.end());
+
+ addArrayAccess(Stmt, Inst, AccType, BasePointer->getValue(), ElementType,
+ true, Subscripts, SizesSCEV, Val);
+--
+2.45.2
+
diff --git a/llvm/lib/Analysis/Delinearization.cpp b/llvm/lib/Analysis/Delinearization.cpp
index c2a429ffdfe9a..31dab99c91f29 100644
--- a/llvm/lib/Analysis/Delinearization.cpp
+++ b/llvm/lib/Analysis/Delinearization.cpp
@@ -830,6 +830,7 @@ bool llvm::getIndexExpressionsFromGEP(ScalarEvolution &SE,
assert(GEP && "getIndexExpressionsFromGEP called with a null GEP");
LLVM_DEBUG(dbgs() << "\nGEP to delinearize: " << *GEP << "\n");
Type *Ty = nullptr;
+ Type *IndexTy = SE.getEffectiveSCEVType(GEP->getPointerOperandType());
bool DroppedFirstDim = false;
for (unsigned i = 1; i < GEP->getNumOperands(); i++) {
const SCEV *Expr = SE.getSCEV(GEP->getOperand(i));
@@ -855,8 +856,7 @@ bool llvm::getIndexExpressionsFromGEP(ScalarEvolution &SE,
Subscripts.push_back(Expr);
if (!(DroppedFirstDim && i == 2))
- Sizes.push_back(SE.getConstant(Expr->getType(),
- ArrayTy->getNumElements()));
+ Sizes.push_back(SE.getConstant(IndexTy, ArrayTy->getNumElements()));
Ty = ArrayTy->getElementType();
}
More information about the llvm-commits
mailing list