1 //===---- Delinearization.cpp - MultiDimensional Index Delinearization ----===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This implements an analysis pass that tries to delinearize all GEP
10 // instructions in all loops using the SCEV analysis functionality. This pass is
11 // only used for testing purposes: if your pass needs delinearization, please
12 // use the on-demand SCEVAddRecExpr::delinearize() function.
14 //===----------------------------------------------------------------------===//
16 #include "llvm/Analysis/Delinearization.h"
17 #include "llvm/Analysis/LoopInfo.h"
18 #include "llvm/Analysis/Passes.h"
19 #include "llvm/Analysis/ScalarEvolution.h"
20 #include "llvm/Analysis/ScalarEvolutionDivision.h"
21 #include "llvm/Analysis/ScalarEvolutionExpressions.h"
22 #include "llvm/IR/Constants.h"
23 #include "llvm/IR/DerivedTypes.h"
24 #include "llvm/IR/Function.h"
25 #include "llvm/IR/InstIterator.h"
26 #include "llvm/IR/Instructions.h"
27 #include "llvm/IR/PassManager.h"
28 #include "llvm/InitializePasses.h"
29 #include "llvm/Pass.h"
30 #include "llvm/Support/Debug.h"
31 #include "llvm/Support/raw_ostream.h"
35 #define DL_NAME "delinearize"
36 #define DEBUG_TYPE DL_NAME
38 // Return true when S contains at least an undef value.
39 static inline bool containsUndefs(const SCEV
*S
) {
40 return SCEVExprContains(S
, [](const SCEV
*S
) {
41 if (const auto *SU
= dyn_cast
<SCEVUnknown
>(S
))
42 return isa
<UndefValue
>(SU
->getValue());
49 // Collect all steps of SCEV expressions.
50 struct SCEVCollectStrides
{
52 SmallVectorImpl
<const SCEV
*> &Strides
;
54 SCEVCollectStrides(ScalarEvolution
&SE
, SmallVectorImpl
<const SCEV
*> &S
)
55 : SE(SE
), Strides(S
) {}
57 bool follow(const SCEV
*S
) {
58 if (const SCEVAddRecExpr
*AR
= dyn_cast
<SCEVAddRecExpr
>(S
))
59 Strides
.push_back(AR
->getStepRecurrence(SE
));
63 bool isDone() const { return false; }
66 // Collect all SCEVUnknown and SCEVMulExpr expressions.
67 struct SCEVCollectTerms
{
68 SmallVectorImpl
<const SCEV
*> &Terms
;
70 SCEVCollectTerms(SmallVectorImpl
<const SCEV
*> &T
) : Terms(T
) {}
72 bool follow(const SCEV
*S
) {
73 if (isa
<SCEVUnknown
>(S
) || isa
<SCEVMulExpr
>(S
) ||
74 isa
<SCEVSignExtendExpr
>(S
)) {
75 if (!containsUndefs(S
))
78 // Stop recursion: once we collected a term, do not walk its operands.
86 bool isDone() const { return false; }
89 // Check if a SCEV contains an AddRecExpr.
90 struct SCEVHasAddRec
{
93 SCEVHasAddRec(bool &ContainsAddRec
) : ContainsAddRec(ContainsAddRec
) {
94 ContainsAddRec
= false;
97 bool follow(const SCEV
*S
) {
98 if (isa
<SCEVAddRecExpr
>(S
)) {
99 ContainsAddRec
= true;
101 // Stop recursion: once we collected a term, do not walk its operands.
109 bool isDone() const { return false; }
112 // Find factors that are multiplied with an expression that (possibly as a
113 // subexpression) contains an AddRecExpr. In the expression:
115 // 8 * (100 + %p * %q * (%a + {0, +, 1}_loop))
117 // "%p * %q" are factors multiplied by the expression "(%a + {0, +, 1}_loop)"
118 // that contains the AddRec {0, +, 1}_loop. %p * %q are likely to be array size
119 // parameters as they form a product with an induction variable.
121 // This collector expects all array size parameters to be in the same MulExpr.
122 // It might be necessary to later add support for collecting parameters that are
123 // spread over different nested MulExpr.
124 struct SCEVCollectAddRecMultiplies
{
125 SmallVectorImpl
<const SCEV
*> &Terms
;
128 SCEVCollectAddRecMultiplies(SmallVectorImpl
<const SCEV
*> &T
,
130 : Terms(T
), SE(SE
) {}
132 bool follow(const SCEV
*S
) {
133 if (auto *Mul
= dyn_cast
<SCEVMulExpr
>(S
)) {
134 bool HasAddRec
= false;
135 SmallVector
<const SCEV
*, 0> Operands
;
136 for (const auto *Op
: Mul
->operands()) {
137 const SCEVUnknown
*Unknown
= dyn_cast
<SCEVUnknown
>(Op
);
138 if (Unknown
&& !isa
<CallInst
>(Unknown
->getValue())) {
139 Operands
.push_back(Op
);
140 } else if (Unknown
) {
143 bool ContainsAddRec
= false;
144 SCEVHasAddRec
ContiansAddRec(ContainsAddRec
);
145 visitAll(Op
, ContiansAddRec
);
146 HasAddRec
|= ContainsAddRec
;
149 if (Operands
.size() == 0)
155 Terms
.push_back(SE
.getMulExpr(Operands
));
156 // Stop recursion: once we collected a term, do not walk its operands.
164 bool isDone() const { return false; }
167 } // end anonymous namespace
169 /// Find parametric terms in this SCEVAddRecExpr. We first for parameters in
171 /// 1) The strides of AddRec expressions.
172 /// 2) Unknowns that are multiplied with AddRec expressions.
173 void llvm::collectParametricTerms(ScalarEvolution
&SE
, const SCEV
*Expr
,
174 SmallVectorImpl
<const SCEV
*> &Terms
) {
175 SmallVector
<const SCEV
*, 4> Strides
;
176 SCEVCollectStrides
StrideCollector(SE
, Strides
);
177 visitAll(Expr
, StrideCollector
);
180 dbgs() << "Strides:\n";
181 for (const SCEV
*S
: Strides
)
182 dbgs() << *S
<< "\n";
185 for (const SCEV
*S
: Strides
) {
186 SCEVCollectTerms
TermCollector(Terms
);
187 visitAll(S
, TermCollector
);
191 dbgs() << "Terms:\n";
192 for (const SCEV
*T
: Terms
)
193 dbgs() << *T
<< "\n";
196 SCEVCollectAddRecMultiplies
MulCollector(Terms
, SE
);
197 visitAll(Expr
, MulCollector
);
200 static bool findArrayDimensionsRec(ScalarEvolution
&SE
,
201 SmallVectorImpl
<const SCEV
*> &Terms
,
202 SmallVectorImpl
<const SCEV
*> &Sizes
) {
203 int Last
= Terms
.size() - 1;
204 const SCEV
*Step
= Terms
[Last
];
208 if (const SCEVMulExpr
*M
= dyn_cast
<SCEVMulExpr
>(Step
)) {
209 SmallVector
<const SCEV
*, 2> Qs
;
210 for (const SCEV
*Op
: M
->operands())
211 if (!isa
<SCEVConstant
>(Op
))
214 Step
= SE
.getMulExpr(Qs
);
217 Sizes
.push_back(Step
);
221 for (const SCEV
*&Term
: Terms
) {
222 // Normalize the terms before the next call to findArrayDimensionsRec.
224 SCEVDivision::divide(SE
, Term
, Step
, &Q
, &R
);
226 // Bail out when GCD does not evenly divide one of the terms.
233 // Remove all SCEVConstants.
234 erase_if(Terms
, [](const SCEV
*E
) { return isa
<SCEVConstant
>(E
); });
236 if (Terms
.size() > 0)
237 if (!findArrayDimensionsRec(SE
, Terms
, Sizes
))
240 Sizes
.push_back(Step
);
244 // Returns true when one of the SCEVs of Terms contains a SCEVUnknown parameter.
245 static inline bool containsParameters(SmallVectorImpl
<const SCEV
*> &Terms
) {
246 for (const SCEV
*T
: Terms
)
247 if (SCEVExprContains(T
, [](const SCEV
*S
) { return isa
<SCEVUnknown
>(S
); }))
253 // Return the number of product terms in S.
254 static inline int numberOfTerms(const SCEV
*S
) {
255 if (const SCEVMulExpr
*Expr
= dyn_cast
<SCEVMulExpr
>(S
))
256 return Expr
->getNumOperands();
260 static const SCEV
*removeConstantFactors(ScalarEvolution
&SE
, const SCEV
*T
) {
261 if (isa
<SCEVConstant
>(T
))
264 if (isa
<SCEVUnknown
>(T
))
267 if (const SCEVMulExpr
*M
= dyn_cast
<SCEVMulExpr
>(T
)) {
268 SmallVector
<const SCEV
*, 2> Factors
;
269 for (const SCEV
*Op
: M
->operands())
270 if (!isa
<SCEVConstant
>(Op
))
271 Factors
.push_back(Op
);
273 return SE
.getMulExpr(Factors
);
279 void llvm::findArrayDimensions(ScalarEvolution
&SE
,
280 SmallVectorImpl
<const SCEV
*> &Terms
,
281 SmallVectorImpl
<const SCEV
*> &Sizes
,
282 const SCEV
*ElementSize
) {
283 if (Terms
.size() < 1 || !ElementSize
)
286 // Early return when Terms do not contain parameters: we do not delinearize
287 // non parametric SCEVs.
288 if (!containsParameters(Terms
))
292 dbgs() << "Terms:\n";
293 for (const SCEV
*T
: Terms
)
294 dbgs() << *T
<< "\n";
297 // Remove duplicates.
298 array_pod_sort(Terms
.begin(), Terms
.end());
299 Terms
.erase(std::unique(Terms
.begin(), Terms
.end()), Terms
.end());
301 // Put larger terms first.
302 llvm::sort(Terms
, [](const SCEV
*LHS
, const SCEV
*RHS
) {
303 return numberOfTerms(LHS
) > numberOfTerms(RHS
);
306 // Try to divide all terms by the element size. If term is not divisible by
307 // element size, proceed with the original term.
308 for (const SCEV
*&Term
: Terms
) {
310 SCEVDivision::divide(SE
, Term
, ElementSize
, &Q
, &R
);
315 SmallVector
<const SCEV
*, 4> NewTerms
;
317 // Remove constant factors.
318 for (const SCEV
*T
: Terms
)
319 if (const SCEV
*NewT
= removeConstantFactors(SE
, T
))
320 NewTerms
.push_back(NewT
);
323 dbgs() << "Terms after sorting:\n";
324 for (const SCEV
*T
: NewTerms
)
325 dbgs() << *T
<< "\n";
328 if (NewTerms
.empty() || !findArrayDimensionsRec(SE
, NewTerms
, Sizes
)) {
333 // The last element to be pushed into Sizes is the size of an element.
334 Sizes
.push_back(ElementSize
);
337 dbgs() << "Sizes:\n";
338 for (const SCEV
*S
: Sizes
)
339 dbgs() << *S
<< "\n";
343 void llvm::computeAccessFunctions(ScalarEvolution
&SE
, const SCEV
*Expr
,
344 SmallVectorImpl
<const SCEV
*> &Subscripts
,
345 SmallVectorImpl
<const SCEV
*> &Sizes
) {
346 // Early exit in case this SCEV is not an affine multivariate function.
350 if (auto *AR
= dyn_cast
<SCEVAddRecExpr
>(Expr
))
354 const SCEV
*Res
= Expr
;
355 int Last
= Sizes
.size() - 1;
356 for (int i
= Last
; i
>= 0; i
--) {
358 SCEVDivision::divide(SE
, Res
, Sizes
[i
], &Q
, &R
);
361 dbgs() << "Res: " << *Res
<< "\n";
362 dbgs() << "Sizes[i]: " << *Sizes
[i
] << "\n";
363 dbgs() << "Res divided by Sizes[i]:\n";
364 dbgs() << "Quotient: " << *Q
<< "\n";
365 dbgs() << "Remainder: " << *R
<< "\n";
370 // Do not record the last subscript corresponding to the size of elements in
374 // Bail out if the byte offset is non-zero.
384 // Record the access function for the current subscript.
385 Subscripts
.push_back(R
);
388 // Also push in last position the remainder of the last division: it will be
389 // the access function of the innermost dimension.
390 Subscripts
.push_back(Res
);
392 std::reverse(Subscripts
.begin(), Subscripts
.end());
395 dbgs() << "Subscripts:\n";
396 for (const SCEV
*S
: Subscripts
)
397 dbgs() << *S
<< "\n";
401 /// Splits the SCEV into two vectors of SCEVs representing the subscripts and
402 /// sizes of an array access. Returns the remainder of the delinearization that
403 /// is the offset start of the array. The SCEV->delinearize algorithm computes
404 /// the multiples of SCEV coefficients: that is a pattern matching of sub
405 /// expressions in the stride and base of a SCEV corresponding to the
406 /// computation of a GCD (greatest common divisor) of base and stride. When
407 /// SCEV->delinearize fails, it returns the SCEV unchanged.
409 /// For example: when analyzing the memory access A[i][j][k] in this loop nest
411 /// void foo(long n, long m, long o, double A[n][m][o]) {
413 /// for (long i = 0; i < n; i++)
414 /// for (long j = 0; j < m; j++)
415 /// for (long k = 0; k < o; k++)
416 /// A[i][j][k] = 1.0;
419 /// the delinearization input is the following AddRec SCEV:
421 /// AddRec: {{{%A,+,(8 * %m * %o)}<%for.i>,+,(8 * %o)}<%for.j>,+,8}<%for.k>
423 /// From this SCEV, we are able to say that the base offset of the access is %A
424 /// because it appears as an offset that does not divide any of the strides in
427 /// CHECK: Base offset: %A
429 /// and then SCEV->delinearize determines the size of some of the dimensions of
430 /// the array as these are the multiples by which the strides are happening:
432 /// CHECK: ArrayDecl[UnknownSize][%m][%o] with elements of sizeof(double)
435 /// Note that the outermost dimension remains of UnknownSize because there are
436 /// no strides that would help identifying the size of the last dimension: when
437 /// the array has been statically allocated, one could compute the size of that
438 /// dimension by dividing the overall size of the array by the size of the known
439 /// dimensions: %m * %o * 8.
441 /// Finally delinearize provides the access functions for the array reference
442 /// that does correspond to A[i][j][k] of the above C testcase:
444 /// CHECK: ArrayRef[{0,+,1}<%for.i>][{0,+,1}<%for.j>][{0,+,1}<%for.k>]
446 /// The testcases are checking the output of a function pass:
447 /// DelinearizationPass that walks through all loads and stores of a function
448 /// asking for the SCEV of the memory access with respect to all enclosing
449 /// loops, calling SCEV->delinearize on that and printing the results.
450 void llvm::delinearize(ScalarEvolution
&SE
, const SCEV
*Expr
,
451 SmallVectorImpl
<const SCEV
*> &Subscripts
,
452 SmallVectorImpl
<const SCEV
*> &Sizes
,
453 const SCEV
*ElementSize
) {
454 // First step: collect parametric terms.
455 SmallVector
<const SCEV
*, 4> Terms
;
456 collectParametricTerms(SE
, Expr
, Terms
);
461 // Second step: find subscript sizes.
462 findArrayDimensions(SE
, Terms
, Sizes
, ElementSize
);
467 // Third step: compute the access functions for each subscript.
468 computeAccessFunctions(SE
, Expr
, Subscripts
, Sizes
);
470 if (Subscripts
.empty())
474 dbgs() << "succeeded to delinearize " << *Expr
<< "\n";
475 dbgs() << "ArrayDecl[UnknownSize]";
476 for (const SCEV
*S
: Sizes
)
477 dbgs() << "[" << *S
<< "]";
479 dbgs() << "\nArrayRef";
480 for (const SCEV
*S
: Subscripts
)
481 dbgs() << "[" << *S
<< "]";
486 bool llvm::getIndexExpressionsFromGEP(ScalarEvolution
&SE
,
487 const GetElementPtrInst
*GEP
,
488 SmallVectorImpl
<const SCEV
*> &Subscripts
,
489 SmallVectorImpl
<int> &Sizes
) {
490 assert(Subscripts
.empty() && Sizes
.empty() &&
491 "Expected output lists to be empty on entry to this function.");
492 assert(GEP
&& "getIndexExpressionsFromGEP called with a null GEP");
494 bool DroppedFirstDim
= false;
495 for (unsigned i
= 1; i
< GEP
->getNumOperands(); i
++) {
496 const SCEV
*Expr
= SE
.getSCEV(GEP
->getOperand(i
));
498 Ty
= GEP
->getSourceElementType();
499 if (auto *Const
= dyn_cast
<SCEVConstant
>(Expr
))
500 if (Const
->getValue()->isZero()) {
501 DroppedFirstDim
= true;
504 Subscripts
.push_back(Expr
);
508 auto *ArrayTy
= dyn_cast
<ArrayType
>(Ty
);
515 Subscripts
.push_back(Expr
);
516 if (!(DroppedFirstDim
&& i
== 2))
517 Sizes
.push_back(ArrayTy
->getNumElements());
519 Ty
= ArrayTy
->getElementType();
521 return !Subscripts
.empty();
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
);
529 // Check the simple case where the array dimensions are fixed size.
530 auto *SrcGEP
= dyn_cast
<GetElementPtrInst
>(SrcPtr
);
534 getIndexExpressionsFromGEP(*SE
, SrcGEP
, Subscripts
, Sizes
);
536 // Check that the two size arrays are non-empty and equal in length and
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) {
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()) {
555 assert(Subscripts
.size() == Sizes
.size() + 1 &&
556 "Expected equal number of entries in the list of size and "
564 class Delinearization
: public FunctionPass
{
565 Delinearization(const Delinearization
&); // do not implement
572 static char ID
; // Pass identification, replacement for typeid
574 Delinearization() : FunctionPass(ID
) {
575 initializeDelinearizationPass(*PassRegistry::getPassRegistry());
577 bool runOnFunction(Function
&F
) override
;
578 void getAnalysisUsage(AnalysisUsage
&AU
) const override
;
579 void print(raw_ostream
&O
, const Module
*M
= nullptr) const override
;
582 void printDelinearization(raw_ostream
&O
, Function
*F
, LoopInfo
*LI
,
583 ScalarEvolution
*SE
) {
584 O
<< "Delinearization on function " << F
->getName() << ":\n";
585 for (Instruction
&Inst
: instructions(F
)) {
586 // Only analyze loads and stores.
587 if (!isa
<StoreInst
>(&Inst
) && !isa
<LoadInst
>(&Inst
) &&
588 !isa
<GetElementPtrInst
>(&Inst
))
591 const BasicBlock
*BB
= Inst
.getParent();
592 // Delinearize the memory access as analyzed in all the surrounding loops.
593 // Do not analyze memory accesses outside loops.
594 for (Loop
*L
= LI
->getLoopFor(BB
); L
!= nullptr; L
= L
->getParentLoop()) {
595 const SCEV
*AccessFn
= SE
->getSCEVAtScope(getPointerOperand(&Inst
), L
);
597 const SCEVUnknown
*BasePointer
=
598 dyn_cast
<SCEVUnknown
>(SE
->getPointerBase(AccessFn
));
599 // Do not delinearize if we cannot find the base pointer.
602 AccessFn
= SE
->getMinusSCEV(AccessFn
, BasePointer
);
605 O
<< "Inst:" << Inst
<< "\n";
606 O
<< "In Loop with Header: " << L
->getHeader()->getName() << "\n";
607 O
<< "AccessFunction: " << *AccessFn
<< "\n";
609 SmallVector
<const SCEV
*, 3> Subscripts
, Sizes
;
610 delinearize(*SE
, AccessFn
, Subscripts
, Sizes
, SE
->getElementSize(&Inst
));
611 if (Subscripts
.size() == 0 || Sizes
.size() == 0 ||
612 Subscripts
.size() != Sizes
.size()) {
613 O
<< "failed to delinearize\n";
617 O
<< "Base offset: " << *BasePointer
<< "\n";
618 O
<< "ArrayDecl[UnknownSize]";
619 int Size
= Subscripts
.size();
620 for (int i
= 0; i
< Size
- 1; i
++)
621 O
<< "[" << *Sizes
[i
] << "]";
622 O
<< " with elements of " << *Sizes
[Size
- 1] << " bytes.\n";
625 for (int i
= 0; i
< Size
; i
++)
626 O
<< "[" << *Subscripts
[i
] << "]";
632 } // end anonymous namespace
634 void Delinearization::getAnalysisUsage(AnalysisUsage
&AU
) const {
635 AU
.setPreservesAll();
636 AU
.addRequired
<LoopInfoWrapperPass
>();
637 AU
.addRequired
<ScalarEvolutionWrapperPass
>();
640 bool Delinearization::runOnFunction(Function
&F
) {
642 SE
= &getAnalysis
<ScalarEvolutionWrapperPass
>().getSE();
643 LI
= &getAnalysis
<LoopInfoWrapperPass
>().getLoopInfo();
647 void Delinearization::print(raw_ostream
&O
, const Module
*) const {
648 printDelinearization(O
, F
, LI
, SE
);
651 char Delinearization::ID
= 0;
652 static const char delinearization_name
[] = "Delinearization";
653 INITIALIZE_PASS_BEGIN(Delinearization
, DL_NAME
, delinearization_name
, true,
655 INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass
)
656 INITIALIZE_PASS_END(Delinearization
, DL_NAME
, delinearization_name
, true, true)
658 FunctionPass
*llvm::createDelinearizationPass() { return new Delinearization
; }
660 DelinearizationPrinterPass::DelinearizationPrinterPass(raw_ostream
&OS
)
662 PreservedAnalyses
DelinearizationPrinterPass::run(Function
&F
,
663 FunctionAnalysisManager
&AM
) {
664 printDelinearization(OS
, &F
, &AM
.getResult
<LoopAnalysis
>(F
),
665 &AM
.getResult
<ScalarEvolutionAnalysis
>(F
));
666 return PreservedAnalyses::all();