Skip to content

Commit 1f39c61

Browse files
committed
[delinearize] do not rely on GEP for delinearization
This finishes removing the code of GEP delinearization. Follow up patches will clean the interface, in particular Sizes array of ints will be rewritten as an array of SCEVs to avoid unnecessary translations. Another painful point to be addressed in subsequent patches is unifying the delinearize() interface to avoid users directly hit in the internals of delinearize. The many uses of delinearization internals makes changes to the core delinearization algorithm hard to modify.
1 parent 65e9cfc commit 1f39c61

File tree

4 files changed

+15
-198
lines changed

4 files changed

+15
-198
lines changed

llvm/include/llvm/Analysis/Delinearization.h

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -139,29 +139,11 @@ bool findFixedSizeArrayDimensions(ScalarEvolution &SE, const SCEV *Expr,
139139
/// Different from the normal delinearization, this function assumes that NO
140140
/// terms exist in the \p Expr. In other words, it assumes that the all step
141141
/// values are constant.
142-
///
143-
/// This function is intended to replace getIndexExpressionsFromGEP and
144-
/// tryDelinearizeFixedSizeImpl. They rely on the GEP source element type so
145-
/// that they will be removed in the future.
146142
bool delinearizeFixedSizeArray(ScalarEvolution &SE, const SCEV *Expr,
147143
SmallVectorImpl<const SCEV *> &Subscripts,
148144
SmallVectorImpl<const SCEV *> &Sizes,
149145
const SCEV *ElementSize);
150146

151-
/// Gathers the individual index expressions from a GEP instruction.
152-
///
153-
/// This function optimistically assumes the GEP references into a fixed size
154-
/// array. If this is actually true, this function returns a list of array
155-
/// subscript expressions in \p Subscripts and a list of integers describing
156-
/// the size of the individual array dimensions in \p Sizes. Both lists have
157-
/// either equal length or the size list is one element shorter in case there
158-
/// is no known size available for the outermost array dimension. Returns true
159-
/// if successful and false otherwise.
160-
bool getIndexExpressionsFromGEP(ScalarEvolution &SE,
161-
const GetElementPtrInst *GEP,
162-
SmallVectorImpl<const SCEV *> &Subscripts,
163-
SmallVectorImpl<int> &Sizes);
164-
165147
/// Compute access functions for each subscript in a delinearized array access.
166148
void computeAccessFunctions(ScalarEvolution &SE, const SCEV *Expr,
167149
SmallVectorImpl<const SCEV *> &Subscripts,

llvm/lib/Analysis/Delinearization.cpp

Lines changed: 4 additions & 176 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,6 @@ static cl::opt<bool> UseFixedSizeArrayHeuristic(
4141
cl::desc("When printing analysis, use the heuristic for fixed-size arrays "
4242
"if the default delinearizetion fails."));
4343

44-
static cl::opt<bool> useGEPToDelinearize(
45-
"use-gep-to-delinearize", cl::init(true), cl::Hidden,
46-
cl::desc("validate both delinearization methods match."));
47-
4844
// Return true when S contains at least an undef value.
4945
static inline bool containsUndefs(const SCEV *S) {
5046
return SCEVExprContains(S, [](const SCEV *S) {
@@ -848,56 +844,6 @@ bool llvm::delinearizeFixedSizeArray(ScalarEvolution &SE, const SCEV *Expr,
848844
return !Subscripts.empty();
849845
}
850846

851-
bool llvm::getIndexExpressionsFromGEP(ScalarEvolution &SE,
852-
const GetElementPtrInst *GEP,
853-
SmallVectorImpl<const SCEV *> &Subscripts,
854-
SmallVectorImpl<int> &Sizes) {
855-
assert(Subscripts.empty() && Sizes.empty() &&
856-
"Expected output lists to be empty on entry to this function.");
857-
assert(GEP && "getIndexExpressionsFromGEP called with a null GEP");
858-
LLVM_DEBUG(dbgs() << "\nGEP to delinearize: " << *GEP << "\n");
859-
Type *Ty = nullptr;
860-
bool DroppedFirstDim = false;
861-
for (unsigned i = 1; i < GEP->getNumOperands(); i++) {
862-
const SCEV *Expr = SE.getSCEV(GEP->getOperand(i));
863-
if (i == 1) {
864-
Ty = GEP->getSourceElementType();
865-
if (auto *Const = dyn_cast<SCEVConstant>(Expr))
866-
if (Const->getValue()->isZero()) {
867-
DroppedFirstDim = true;
868-
continue;
869-
}
870-
Subscripts.push_back(Expr);
871-
LLVM_DEBUG(dbgs() << "Subscripts push_back: " << *Expr << "\n");
872-
continue;
873-
}
874-
875-
auto *ArrayTy = dyn_cast<ArrayType>(Ty);
876-
if (!ArrayTy) {
877-
LLVM_DEBUG(dbgs() << "GEP delinearize failed: " << *Ty
878-
<< " is not an array type.\n");
879-
Subscripts.clear();
880-
Sizes.clear();
881-
return false;
882-
}
883-
884-
Subscripts.push_back(Expr);
885-
LLVM_DEBUG(dbgs() << "Subscripts push_back: " << *Expr << "\n");
886-
if (!(DroppedFirstDim && i == 2))
887-
Sizes.push_back(ArrayTy->getNumElements());
888-
889-
Ty = ArrayTy->getElementType();
890-
}
891-
LLVM_DEBUG({
892-
dbgs() << "Subscripts:\n";
893-
for (const SCEV *S : Subscripts)
894-
dbgs() << *S << "\n";
895-
dbgs() << "\n";
896-
});
897-
898-
return !Subscripts.empty();
899-
}
900-
901847
bool llvm::tryDelinearizeFixedSizeImpl(
902848
ScalarEvolution *SE, Instruction *Inst, const SCEV *AccessFn,
903849
SmallVectorImpl<const SCEV *> &Subscripts, SmallVectorImpl<int> &Sizes) {
@@ -943,133 +889,15 @@ bool llvm::tryDelinearizeFixedSizeImpl(
943889
// Array_info delinearization.
944890
SmallVector<const SCEV *, 4> SCEVSizes;
945891
const SCEV *ElementSize = SE->getElementSize(Inst);
946-
bool ArrayInfoSuccess = delinearizeUsingArrayInfo(
947-
*SE, AccessFn, ArrayInfoSubscripts, SCEVSizes, ElementSize);
892+
if (!delinearizeUsingArrayInfo(*SE, AccessFn, Subscripts, SCEVSizes,
893+
ElementSize))
894+
return false;
948895

949896
// TODO: Remove the following code. Convert SCEV sizes to int sizes. This
950897
// conversion is only needed as long as getIndexExpressionsFromGEP is still
951898
// around. Remove this code and change the interface of
952899
// tryDelinearizeFixedSizeImpl to take a SmallVectorImpl<const SCEV *> &Sizes.
953-
if (ArrayInfoSuccess)
954-
convertSCEVSizesToIntSizes(SCEVSizes, ArrayInfoSizes);
955-
956-
// Validate consistency between methods.
957-
if (GEPSuccess && ArrayInfoSuccess) {
958-
// If both methods succeeded, validate they produce the same results.
959-
// Compare sizes arrays.
960-
if (GEPSizes.size() + 2 != ArrayInfoSizes.size()) {
961-
LLVM_DEBUG({
962-
dbgs() << "WARN: Size arrays have different lengths!\n";
963-
dbgs() << "GEP sizes count: " << GEPSizes.size() << "\n"
964-
<< "ArrayInfo sizes count: " << ArrayInfoSizes.size() << "\n";
965-
});
966-
}
967-
968-
for (size_t i = 0; i < GEPSizes.size(); ++i) {
969-
if (GEPSizes[i] != ArrayInfoSizes[i + 1]) {
970-
LLVM_DEBUG({
971-
dbgs() << "WARN: Size arrays differ at index " << i << "!\n";
972-
dbgs() << "GEP size[" << i << "]: " << GEPSizes[i] << "\n"
973-
<< "ArrayInfo size[" << i + 1 << "]: " << ArrayInfoSizes[i + 1]
974-
<< "\n";
975-
});
976-
}
977-
}
978-
979-
// Compare subscripts arrays.
980-
if (GEPSubscripts.size() != ArrayInfoSubscripts.size()) {
981-
LLVM_DEBUG({
982-
dbgs() << "WARN: Subscript arrays have different lengths!\n";
983-
dbgs() << " GEP subscripts count: " << GEPSubscripts.size() << "\n"
984-
<< " ArrayInfo subscripts count: " << ArrayInfoSubscripts.size()
985-
<< "\n";
986-
987-
dbgs() << " GEP subscripts:\n";
988-
for (size_t i = 0; i < GEPSubscripts.size(); ++i)
989-
dbgs() << " subscript[" << i << "]: " << *GEPSubscripts[i] << "\n";
990-
991-
dbgs() << " ArrayInfo subscripts:\n";
992-
for (size_t i = 0; i < ArrayInfoSubscripts.size(); ++i)
993-
dbgs() << " subscript[" << i << "]: " << *ArrayInfoSubscripts[i]
994-
<< "\n";
995-
});
996-
}
997-
998-
for (size_t i = 0; i < GEPSubscripts.size(); ++i) {
999-
const SCEV *GEPS = GEPSubscripts[i];
1000-
const SCEV *AIS = ArrayInfoSubscripts[i];
1001-
// FIXME: there's no good way to compare two scevs: don't abort, warn.
1002-
if (GEPS != AIS || !SE->getMinusSCEV(GEPS, AIS)->isZero()) {
1003-
LLVM_DEBUG({
1004-
dbgs() << "WARN: Subscript arrays differ at index " << i << "!\n";
1005-
dbgs() << " GEP subscript[" << i << "]: " << *GEPSubscripts[i]
1006-
<< "\n"
1007-
<< " ArrayInfo subscript[" << i
1008-
<< "]: " << *ArrayInfoSubscripts[i] << "\n";
1009-
});
1010-
}
1011-
}
1012-
1013-
LLVM_DEBUG(dbgs() << "SUCCESS: Both delinearization methods produced "
1014-
"identical results\n");
1015-
} else if (GEPSuccess && !ArrayInfoSuccess) {
1016-
LLVM_DEBUG({
1017-
dbgs() << "WARNING: array_info failed and GEP analysis succeeded.\n";
1018-
dbgs() << " Instruction: " << *Inst << "\n";
1019-
dbgs() << " Using GEP analysis results despite array_info failure\n";
1020-
});
1021-
} else if (!GEPSuccess && ArrayInfoSuccess) {
1022-
LLVM_DEBUG({
1023-
dbgs() << "WARNING: GEP failed and array_info analysis succeeded.\n";
1024-
dbgs() << " Instruction: " << *Inst << "\n";
1025-
dbgs() << " Using array_info analysis results despite GEP failure\n";
1026-
});
1027-
} else if (!GEPSuccess && !ArrayInfoSuccess) {
1028-
LLVM_DEBUG({
1029-
dbgs() << "WARNING: both GEP and array_info analysis failed.\n";
1030-
dbgs() << " Instruction: " << *Inst << "\n";
1031-
});
1032-
}
1033-
1034-
// Choose which result to use.
1035-
// Prefer array_info when available.
1036-
if (ArrayInfoSuccess) {
1037-
Subscripts = std::move(ArrayInfoSubscripts);
1038-
Sizes = std::move(ArrayInfoSizes);
1039-
return true;
1040-
}
1041-
1042-
// Both failed.
1043-
if (!GEPSuccess)
1044-
return false;
1045-
1046-
// Return GEP-based delinearization.
1047-
Subscripts = std::move(GEPSubscripts);
1048-
Sizes = std::move(GEPSizes);
1049-
1050-
// Check that the two size arrays are non-empty and equal in length and
1051-
// value.
1052-
// TODO: it would be better to let the caller to clear Subscripts, similar
1053-
// to how we handle Sizes.
1054-
if (Sizes.empty() || Subscripts.size() <= 1) {
1055-
Subscripts.clear();
1056-
return false;
1057-
}
1058-
1059-
// Check that for identical base pointers we do not miss index offsets
1060-
// that have been added before this GEP is applied.
1061-
Value *SrcBasePtr = SrcGEP->getOperand(0)->stripPointerCasts();
1062-
const SCEVUnknown *SrcBase =
1063-
dyn_cast<SCEVUnknown>(SE->getPointerBase(AccessFn));
1064-
if (!SrcBase || SrcBasePtr != SrcBase->getValue()) {
1065-
Subscripts.clear();
1066-
return false;
1067-
}
1068-
1069-
assert(Subscripts.size() == Sizes.size() + 1 &&
1070-
"Expected equal number of entries in the list of size and "
1071-
"subscript.");
1072-
900+
convertSCEVSizesToIntSizes(SCEVSizes, Sizes);
1073901
return true;
1074902
}
1075903

llvm/test/Analysis/DependenceAnalysis/DifferentOffsets.ll

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,18 @@ define void @multidim_accesses(ptr %A) {
149149
; CHECK-NEXT: Src: store i32 1, ptr %idx0, align 4 --> Dst: store i32 1, ptr %idx0, align 4
150150
; CHECK-NEXT: da analyze - none!
151151
; CHECK-NEXT: Src: store i32 1, ptr %idx0, align 4 --> Dst: store i32 1, ptr %idx1, align 4
152-
; CHECK-NEXT: da analyze - consistent output [0 0 0|<]!
152+
; CHECK-NEXT: da analyze - output [<= * *|<]!
153153
; CHECK-NEXT: Src: store i32 1, ptr %idx1, align 4 --> Dst: store i32 1, ptr %idx1, align 4
154154
; CHECK-NEXT: da analyze - none!
155155
;
156-
; FIXME: the dependence distance is not constant. Distance vector should be [* * *|<]!
156+
; NOTE: the dependence distance between the two stores at idx0 and idx1 is not constant.
157+
; The dependence direction vector should be "[<= * *|<]!"
158+
;
159+
; The memory accesses used to be GEP-delinearized leading to 32b and 64b stores
160+
; with the same subscript access functions to the same array A, leading the
161+
; dependence analysis to incorrect constant distance "[0 0 0|<]!" dependences.
162+
; The distance is not constant: 64b store's strides in memory is twice the 32b store.
163+
;
157164
; for (i = 0; i < 256; i++)
158165
; for (j = 0; j < 256; j++)
159166
; for (k = 0; k < 256; k++) {

llvm/test/Analysis/LoopCacheAnalysis/interchange-cost-beneficial.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
; E[j] = 1
2424
; }
2525

26-
; CHECK: Loop 'for.j' has cost = 18
27-
; CHECK-NEXT: Loop 'for.i' has cost = 10
26+
; CHECK: Loop 'for.j' has cost = 12
27+
; CHECK-NEXT: Loop 'for.i' has cost = 8
2828

2929
define void @test() {
3030

0 commit comments

Comments
 (0)