Skip to content

Commit 4c77d02

Browse files
[Delinearization] Refactoring of fixed-size array delinearization
This is a follow-up patch to D122857 where we added delinearization of fixed-size arrays to loop cache analysis, which resulted in some duplicate code, i.e., "tryDelinearizeFixedSize()", in LoopCacheCost.cpp and DependenceAnalysis.cpp. Refactoring is done in this patch. This patch refactors out the main logic of "tryDelinearizeFixedSize()" as "tryDelinearizeFixedSizeImpl()" and moves it to Delinearization.cpp, such that clients can reuse "llvm::tryDelinearizeFixedSizeImpl()" wherever they would like to delinearize fixed-size arrays. Currently it has two users, i.e., DependenceAnalysis.cpp and LoopCacheCost.cpp. Reviewed By: Meinersbur, #loopoptwg Differential Revision: https://reviews.llvm.org/D124745
1 parent a9dccb0 commit 4c77d02

File tree

6 files changed

+83
-71
lines changed

6 files changed

+83
-71
lines changed

Diff for: llvm/include/llvm/Analysis/Delinearization.h

+11
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,17 @@ bool getIndexExpressionsFromGEP(ScalarEvolution &SE,
125125
SmallVectorImpl<const SCEV *> &Subscripts,
126126
SmallVectorImpl<int> &Sizes);
127127

128+
/// Implementation of fixed size array delinearization. Try to delinearize
129+
/// access function for a fixed size multi-dimensional array, by deriving
130+
/// subscripts from GEP instructions. Returns true upon success and false
131+
/// otherwise. \p Inst is the load/store instruction whose pointer operand is
132+
/// the one we want to delinearize. \p AccessFn is its corresponding SCEV
133+
/// expression w.r.t. the surrounding loop.
134+
bool tryDelinearizeFixedSizeImpl(ScalarEvolution *SE, Instruction *Inst,
135+
const SCEV *AccessFn,
136+
SmallVectorImpl<const SCEV *> &Subscripts,
137+
SmallVectorImpl<int> &Sizes);
138+
128139
struct DelinearizationPrinterPass
129140
: public PassInfoMixin<DelinearizationPrinterPass> {
130141
explicit DelinearizationPrinterPass(raw_ostream &OS);

Diff for: llvm/include/llvm/Analysis/DependenceAnalysis.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -927,9 +927,9 @@ namespace llvm {
927927
bool tryDelinearize(Instruction *Src, Instruction *Dst,
928928
SmallVectorImpl<Subscript> &Pair);
929929

930-
/// Tries to delinearize access function for a fixed size multi-dimensional
931-
/// array, by deriving subscripts from GEP instructions. Returns true upon
932-
/// success and false otherwise.
930+
/// Tries to delinearize \p Src and \p Dst access functions for a fixed size
931+
/// multi-dimensional array. Calls tryDelinearizeFixedSizeImpl() to
932+
/// delinearize \p Src and \p Dst separately,
933933
bool tryDelinearizeFixedSize(Instruction *Src, Instruction *Dst,
934934
const SCEV *SrcAccessFn,
935935
const SCEV *DstAccessFn,

Diff for: llvm/include/llvm/Analysis/LoopCacheAnalysis.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,9 @@ class IndexedReference {
9898
/// Attempt to delinearize the indexed reference.
9999
bool delinearize(const LoopInfo &LI);
100100

101-
bool tryDelinearizeFixedSize(ScalarEvolution *SE, Instruction *Src,
102-
const SCEV *SrcAccessFn,
103-
SmallVectorImpl<const SCEV *> &SrcSubscripts);
101+
/// Attempt to delinearize \p AccessFn for fixed-size arrays.
102+
bool tryDelinearizeFixedSize(const SCEV *AccessFn,
103+
SmallVectorImpl<const SCEV *> &Subscripts);
104104

105105
/// Return true if the index reference is invariant with respect to loop \p L.
106106
bool isLoopInvariant(const Loop &L) const;

Diff for: llvm/lib/Analysis/Delinearization.cpp

+38
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,44 @@ bool llvm::getIndexExpressionsFromGEP(ScalarEvolution &SE,
521521
return !Subscripts.empty();
522522
}
523523

524+
bool llvm::tryDelinearizeFixedSizeImpl(
525+
ScalarEvolution *SE, Instruction *Inst, const SCEV *AccessFn,
526+
SmallVectorImpl<const SCEV *> &Subscripts, SmallVectorImpl<int> &Sizes) {
527+
Value *SrcPtr = getLoadStorePointerOperand(Inst);
528+
529+
// Check the simple case where the array dimensions are fixed size.
530+
auto *SrcGEP = dyn_cast<GetElementPtrInst>(SrcPtr);
531+
if (!SrcGEP)
532+
return false;
533+
534+
getIndexExpressionsFromGEP(*SE, SrcGEP, Subscripts, Sizes);
535+
536+
// Check that the two size arrays are non-empty and equal in length and
537+
// value.
538+
// TODO: it would be better to let the caller to clear Subscripts, similar
539+
// to how we handle Sizes.
540+
if (Sizes.empty() || Subscripts.size() <= 1) {
541+
Subscripts.clear();
542+
return false;
543+
}
544+
545+
// Check that for identical base pointers we do not miss index offsets
546+
// that have been added before this GEP is applied.
547+
Value *SrcBasePtr = SrcGEP->getOperand(0)->stripPointerCasts();
548+
const SCEVUnknown *SrcBase =
549+
dyn_cast<SCEVUnknown>(SE->getPointerBase(AccessFn));
550+
if (!SrcBase || SrcBasePtr != SrcBase->getValue()) {
551+
Subscripts.clear();
552+
return false;
553+
}
554+
555+
assert(Subscripts.size() == Sizes.size() + 1 &&
556+
"Expected equal number of entries in the list of size and "
557+
"subscript.");
558+
559+
return true;
560+
}
561+
524562
namespace {
525563

526564
class Delinearization : public FunctionPass {

Diff for: llvm/lib/Analysis/DependenceAnalysis.cpp

+17-29
Original file line numberDiff line numberDiff line change
@@ -3334,55 +3334,43 @@ bool DependenceInfo::tryDelinearize(Instruction *Src, Instruction *Dst,
33343334
return true;
33353335
}
33363336

3337+
/// Try to delinearize \p SrcAccessFn and \p DstAccessFn if the underlying
3338+
/// arrays accessed are fixed-size arrays. Return true if delinearization was
3339+
/// successful.
33373340
bool DependenceInfo::tryDelinearizeFixedSize(
33383341
Instruction *Src, Instruction *Dst, const SCEV *SrcAccessFn,
33393342
const SCEV *DstAccessFn, SmallVectorImpl<const SCEV *> &SrcSubscripts,
33403343
SmallVectorImpl<const SCEV *> &DstSubscripts) {
3341-
3342-
Value *SrcPtr = getLoadStorePointerOperand(Src);
3343-
Value *DstPtr = getLoadStorePointerOperand(Dst);
33443344
const SCEVUnknown *SrcBase =
33453345
dyn_cast<SCEVUnknown>(SE->getPointerBase(SrcAccessFn));
33463346
const SCEVUnknown *DstBase =
33473347
dyn_cast<SCEVUnknown>(SE->getPointerBase(DstAccessFn));
33483348
assert(SrcBase && DstBase && SrcBase == DstBase &&
33493349
"expected src and dst scev unknowns to be equal");
33503350

3351-
// Check the simple case where the array dimensions are fixed size.
3352-
auto *SrcGEP = dyn_cast<GetElementPtrInst>(SrcPtr);
3353-
auto *DstGEP = dyn_cast<GetElementPtrInst>(DstPtr);
3354-
if (!SrcGEP || !DstGEP)
3351+
SmallVector<int, 4> SrcSizes;
3352+
SmallVector<int, 4> DstSizes;
3353+
if (!tryDelinearizeFixedSizeImpl(SE, Src, SrcAccessFn, SrcSubscripts,
3354+
SrcSizes) ||
3355+
!tryDelinearizeFixedSizeImpl(SE, Dst, DstAccessFn, DstSubscripts,
3356+
DstSizes))
33553357
return false;
33563358

3357-
SmallVector<int, 4> SrcSizes, DstSizes;
3358-
getIndexExpressionsFromGEP(*SE, SrcGEP, SrcSubscripts, SrcSizes);
3359-
getIndexExpressionsFromGEP(*SE, DstGEP, DstSubscripts, DstSizes);
3360-
33613359
// Check that the two size arrays are non-empty and equal in length and
33623360
// value.
3363-
if (SrcSizes.empty() || SrcSubscripts.size() <= 1 ||
3364-
SrcSizes.size() != DstSizes.size() ||
3361+
if (SrcSizes.size() != DstSizes.size() ||
33653362
!std::equal(SrcSizes.begin(), SrcSizes.end(), DstSizes.begin())) {
33663363
SrcSubscripts.clear();
33673364
DstSubscripts.clear();
33683365
return false;
33693366
}
33703367

3371-
Value *SrcBasePtr = SrcGEP->getOperand(0)->stripPointerCasts();
3372-
Value *DstBasePtr = DstGEP->getOperand(0)->stripPointerCasts();
3373-
3374-
// Check that for identical base pointers we do not miss index offsets
3375-
// that have been added before this GEP is applied.
3376-
if (SrcBasePtr != SrcBase->getValue() || DstBasePtr != DstBase->getValue()) {
3377-
SrcSubscripts.clear();
3378-
DstSubscripts.clear();
3379-
return false;
3380-
}
3381-
33823368
assert(SrcSubscripts.size() == DstSubscripts.size() &&
3383-
SrcSubscripts.size() == SrcSizes.size() + 1 &&
3384-
"Expected equal number of entries in the list of sizes and "
3385-
"subscripts.");
3369+
"Expected equal number of entries in the list of SrcSubscripts and "
3370+
"DstSubscripts.");
3371+
3372+
Value *SrcPtr = getLoadStorePointerOperand(Src);
3373+
Value *DstPtr = getLoadStorePointerOperand(Dst);
33863374

33873375
// In general we cannot safely assume that the subscripts recovered from GEPs
33883376
// are in the range of values defined for their corresponding array
@@ -3418,8 +3406,8 @@ bool DependenceInfo::tryDelinearizeFixedSize(
34183406
}
34193407
LLVM_DEBUG({
34203408
dbgs() << "Delinearized subscripts of fixed-size array\n"
3421-
<< "SrcGEP:" << *SrcGEP << "\n"
3422-
<< "DstGEP:" << *DstGEP << "\n";
3409+
<< "SrcGEP:" << *SrcPtr << "\n"
3410+
<< "DstGEP:" << *DstPtr << "\n";
34233411
});
34243412
return true;
34253413
}

Diff for: llvm/lib/Analysis/LoopCacheAnalysis.cpp

+11-36
Original file line numberDiff line numberDiff line change
@@ -349,46 +349,21 @@ CacheCostTy IndexedReference::computeRefCost(const Loop &L,
349349
}
350350

351351
bool IndexedReference::tryDelinearizeFixedSize(
352-
ScalarEvolution *SE, Instruction *Src, const SCEV *SrcAccessFn,
353-
SmallVectorImpl<const SCEV *> &SrcSubscripts) {
354-
Value *SrcPtr = getLoadStorePointerOperand(Src);
355-
const SCEVUnknown *SrcBase =
356-
dyn_cast<SCEVUnknown>(SE->getPointerBase(SrcAccessFn));
357-
358-
// Check the simple case where the array dimensions are fixed size.
359-
auto *SrcGEP = dyn_cast<GetElementPtrInst>(SrcPtr);
360-
if (!SrcGEP)
352+
const SCEV *AccessFn, SmallVectorImpl<const SCEV *> &Subscripts) {
353+
SmallVector<int, 4> ArraySizes;
354+
if (!tryDelinearizeFixedSizeImpl(&SE, &StoreOrLoadInst, AccessFn, Subscripts,
355+
ArraySizes))
361356
return false;
362357

363-
SmallVector<int, 4> SrcSizes;
364-
getIndexExpressionsFromGEP(*SE, SrcGEP, SrcSubscripts, SrcSizes);
365-
366-
// Check that the two size arrays are non-empty and equal in length and
367-
// value.
368-
if (SrcSizes.empty() || SrcSubscripts.size() <= 1) {
369-
SrcSubscripts.clear();
370-
return false;
371-
}
372-
373-
Value *SrcBasePtr = SrcGEP->getOperand(0)->stripPointerCasts();
374-
375-
// Check that for identical base pointers we do not miss index offsets
376-
// that have been added before this GEP is applied.
377-
if (SrcBasePtr != SrcBase->getValue()) {
378-
SrcSubscripts.clear();
379-
return false;
380-
}
381-
382-
assert(SrcSubscripts.size() == SrcSizes.size() + 1 &&
383-
"Expected equal number of entries in the list of size and "
384-
"subscript.");
385-
358+
// Populate Sizes with scev expressions to be used in calculations later.
386359
for (auto Idx : seq<unsigned>(1, Subscripts.size()))
387-
Sizes.push_back(SE->getConstant(Subscripts[Idx]->getType(), SrcSizes[Idx - 1]));
360+
Sizes.push_back(
361+
SE.getConstant(Subscripts[Idx]->getType(), ArraySizes[Idx - 1]));
388362

389363
LLVM_DEBUG({
390364
dbgs() << "Delinearized subscripts of fixed-size array\n"
391-
<< "SrcGEP:" << *SrcGEP << "\n";
365+
<< "GEP:" << *getLoadStorePointerOperand(&StoreOrLoadInst)
366+
<< "\n";
392367
});
393368
return true;
394369
}
@@ -416,9 +391,9 @@ bool IndexedReference::delinearize(const LoopInfo &LI) {
416391

417392
bool IsFixedSize = false;
418393
// Try to delinearize fixed-size arrays.
419-
if (tryDelinearizeFixedSize(&SE, &StoreOrLoadInst, AccessFn, Subscripts)) {
394+
if (tryDelinearizeFixedSize(AccessFn, Subscripts)) {
420395
IsFixedSize = true;
421-
/// The last element of \p Sizes is the element size.
396+
// The last element of Sizes is the element size.
422397
Sizes.push_back(ElemSize);
423398
LLVM_DEBUG(dbgs().indent(2) << "In Loop '" << L->getName()
424399
<< "', AccessFn: " << *AccessFn << "\n");

0 commit comments

Comments
 (0)