33#define DL_NAME "delinearize"
34#define DEBUG_TYPE DL_NAME
38 cl::desc(
"When printing analysis, use the heuristic for fixed-size arrays "
39 "if the default delinearizetion fails."));
44 if (
const auto *SU = dyn_cast<SCEVUnknown>(S))
45 return isa<UndefValue>(SU->getValue());
53struct SCEVCollectStrides {
58 : SE(SE), Strides(S) {}
60 bool follow(
const SCEV *S) {
62 Strides.
push_back(AR->getStepRecurrence(SE));
66 bool isDone()
const {
return false; }
70struct SCEVCollectTerms {
75 bool follow(
const SCEV *S) {
76 if (isa<SCEVUnknown>(S) || isa<SCEVMulExpr>(S) ||
77 isa<SCEVSignExtendExpr>(S)) {
89 bool isDone()
const {
return false; }
96 SCEVHasAddRec(
bool &ContainsAddRec) : ContainsAddRec(ContainsAddRec) {
97 ContainsAddRec =
false;
100 bool follow(
const SCEV *S) {
101 if (isa<SCEVAddRecExpr>(S)) {
102 ContainsAddRec =
true;
112 bool isDone()
const {
return false; }
127struct SCEVCollectAddRecMultiplies {
133 : Terms(
T), SE(SE) {}
135 bool follow(
const SCEV *S) {
136 if (
auto *
Mul = dyn_cast<SCEVMulExpr>(S)) {
137 bool HasAddRec =
false;
146 bool ContainsAddRec =
false;
147 SCEVHasAddRec ContiansAddRec(ContainsAddRec);
149 HasAddRec |= ContainsAddRec;
167 bool isDone()
const {
return false; }
179 SCEVCollectStrides StrideCollector(SE, Strides);
183 dbgs() <<
"Strides:\n";
184 for (
const SCEV *S : Strides)
185 dbgs() << *S <<
"\n";
188 for (
const SCEV *S : Strides) {
189 SCEVCollectTerms TermCollector(Terms);
194 dbgs() <<
"Terms:\n";
195 for (
const SCEV *
T : Terms)
196 dbgs() << *
T <<
"\n";
199 SCEVCollectAddRecMultiplies MulCollector(Terms, SE);
211 if (
const SCEVMulExpr *M = dyn_cast<SCEVMulExpr>(Step)) {
213 for (
const SCEV *
Op : M->operands())
214 if (!isa<SCEVConstant>(
Op))
220 Sizes.push_back(Step);
224 for (
const SCEV *&Term : Terms) {
237 erase_if(Terms, [](
const SCEV *E) {
return isa<SCEVConstant>(E); });
239 if (Terms.
size() > 0)
243 Sizes.push_back(Step);
249 for (
const SCEV *
T : Terms)
258 if (
const SCEVMulExpr *Expr = dyn_cast<SCEVMulExpr>(S))
259 return Expr->getNumOperands();
264 if (isa<SCEVConstant>(
T))
267 if (isa<SCEVUnknown>(
T))
272 for (
const SCEV *
Op : M->operands())
273 if (!isa<SCEVConstant>(
Op))
285 const SCEV *ElementSize) {
286 if (Terms.
size() < 1 || !ElementSize)
295 dbgs() <<
"Terms:\n";
296 for (
const SCEV *
T : Terms)
297 dbgs() << *
T <<
"\n";
311 for (
const SCEV *&Term : Terms) {
321 for (
const SCEV *
T : Terms)
326 dbgs() <<
"Terms after sorting:\n";
327 for (
const SCEV *
T : NewTerms)
328 dbgs() << *
T <<
"\n";
337 Sizes.push_back(ElementSize);
340 dbgs() <<
"Sizes:\n";
341 for (
const SCEV *S : Sizes)
342 dbgs() << *S <<
"\n";
353 if (
auto *AR = dyn_cast<SCEVAddRecExpr>(Expr))
357 const SCEV *Res = Expr;
358 int Last = Sizes.size() - 1;
359 for (
int i =
Last; i >= 0; i--) {
364 dbgs() <<
"Res: " << *Res <<
"\n";
365 dbgs() <<
"Sizes[i]: " << *Sizes[i] <<
"\n";
366 dbgs() <<
"Res divided by Sizes[i]:\n";
367 dbgs() <<
"Quotient: " << *Q <<
"\n";
368 dbgs() <<
"Remainder: " << *R <<
"\n";
395 std::reverse(Subscripts.
begin(), Subscripts.
end());
398 dbgs() <<
"Subscripts:\n";
399 for (
const SCEV *S : Subscripts)
400 dbgs() << *S <<
"\n";
456 const SCEV *ElementSize) {
473 if (Subscripts.
empty())
477 dbgs() <<
"succeeded to delinearize " << *Expr <<
"\n";
478 dbgs() <<
"ArrayDecl[UnknownSize]";
479 for (
const SCEV *S : Sizes)
480 dbgs() <<
"[" << *S <<
"]";
482 dbgs() <<
"\nArrayRef";
483 for (
const SCEV *S : Subscripts)
484 dbgs() <<
"[" << *S <<
"]";
490 if (
const auto *Const = dyn_cast<SCEVConstant>(S))
491 return Const->getAPInt();
504 if (
const auto *Const = dyn_cast<SCEVConstant>(Expr)) {
505 const uint64_t Mod = Const->getAPInt().urem(ElementSize);
535 const SCEV *ElementSize) {
539 std::optional<APInt> ElementSizeAPInt =
tryIntoAPInt(ElementSize);
540 if (!ElementSizeAPInt || *ElementSizeAPInt == 0)
543 std::optional<uint64_t> ElementSizeConst = ElementSizeAPInt->tryZExtValue();
546 if (!ElementSizeConst)
577 assert(Sizes.back() != 0 &&
"Unexpected zero size in Sizes.");
580 for (
unsigned I = 0;
I + 1 < Sizes.size();
I++) {
582 if (Sizes[
I] % PrevSize) {
586 Sizes[
I] /= PrevSize;
590 Sizes.back() = *ElementSizeConst;
648 const SCEV *ElementSize) {
664 return !Subscripts.
empty();
672 "Expected output lists to be empty on entry to this function.");
673 assert(
GEP &&
"getIndexExpressionsFromGEP called with a null GEP");
675 bool DroppedFirstDim =
false;
676 for (
unsigned i = 1; i <
GEP->getNumOperands(); i++) {
679 Ty =
GEP->getSourceElementType();
680 if (
auto *Const = dyn_cast<SCEVConstant>(Expr))
681 if (Const->getValue()->isZero()) {
682 DroppedFirstDim =
true;
689 auto *ArrayTy = dyn_cast<ArrayType>(Ty);
697 if (!(DroppedFirstDim && i == 2))
698 Sizes.push_back(ArrayTy->getNumElements());
700 Ty = ArrayTy->getElementType();
702 return !Subscripts.
empty();
711 auto *SrcGEP = dyn_cast<GetElementPtrInst>(SrcPtr);
721 if (Sizes.empty() || Subscripts.
size() <= 1) {
731 if (!SrcBase || SrcBasePtr != SrcBase->
getValue()) {
736 assert(Subscripts.
size() == Sizes.size() + 1 &&
737 "Expected equal number of entries in the list of size and "
747 O <<
"Printing analysis 'Delinearization' for function '" <<
F->getName()
751 if (!isa<StoreInst>(&Inst) && !isa<LoadInst>(&Inst))
771 O <<
"Inst:" << Inst <<
"\n";
772 O <<
"In Loop with Header: " << L->getHeader()->getName() <<
"\n";
773 O <<
"AccessFunction: " << *AccessFn <<
"\n";
777 auto IsDelinearizationFailed = [&]() {
778 return Subscripts.
size() == 0 || Sizes.size() == 0 ||
779 Subscripts.
size() != Sizes.size();
790 if (IsDelinearizationFailed()) {
791 O <<
"failed to delinearize\n";
795 O <<
"Base offset: " << *BasePointer <<
"\n";
796 O <<
"ArrayDecl[UnknownSize]";
798 for (
int i = 0; i <
Size - 1; i++)
799 O <<
"[" << *Sizes[i] <<
"]";
800 O <<
" with elements of " << *
Sizes[
Size - 1] <<
" bytes.\n";
803 for (
int i = 0; i <
Size; i++)
804 O <<
"[" << *Subscripts[i] <<
"]";
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Expand Atomic instructions
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static const SCEV * removeConstantFactors(ScalarEvolution &SE, const SCEV *T)
static bool collectConstantAbsSteps(ScalarEvolution &SE, const SCEV *Expr, SmallVectorImpl< uint64_t > &Steps, uint64_t ElementSize)
Collects the absolute values of constant steps for all induction variables.
static cl::opt< bool > UseFixedSizeArrayHeuristic("delinearize-use-fixed-size-array-heuristic", cl::init(false), cl::Hidden, cl::desc("When printing analysis, use the heuristic for fixed-size arrays " "if the default delinearizetion fails."))
static bool findArrayDimensionsRec(ScalarEvolution &SE, SmallVectorImpl< const SCEV * > &Terms, SmallVectorImpl< const SCEV * > &Sizes)
static bool containsUndefs(const SCEV *S)
static std::optional< APInt > tryIntoAPInt(const SCEV *S)
static bool containsParameters(SmallVectorImpl< const SCEV * > &Terms)
static int numberOfTerms(const SCEV *S)
This header defines various interfaces for pass management in LLVM.
mir Rename Register Operands
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
Class for arbitrary precision integers.
std::optional< uint64_t > tryZExtValue() const
Get zero extended value if possible.
static LLVM_ABI void udivrem(const APInt &LHS, const APInt &RHS, APInt &Quotient, APInt &Remainder)
Dual division/remainder interface.
A container for analyses that lazily runs them and caches their results.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
LLVM Basic Block Representation.
const Function * getParent() const
Return the enclosing method, or null if none.
This class represents an Operation in the Expression.
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
Analysis pass that exposes the LoopInfo for a function.
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
Represents a single loop in the control flow graph.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
This node represents a polynomial recurrence on the trip count of the specified loop.
const SCEV * getStart() const
const SCEV * getStepRecurrence(ScalarEvolution &SE) const
Constructs and returns the recurrence indicating how much this expression steps by.
bool isAffine() const
Return true if this represents an expression A + B*x where A and B are loop invariant values.
This node represents multiplication of some number of SCEVs.
This means that we are dealing with an entirely unknown SCEV value, and only represent it as its LLVM...
This class represents an analyzed expression in the program.
LLVM_ABI bool isZero() const
Return true if the expression is a constant zero.
LLVM_ABI Type * getType() const
Return the LLVM type of this SCEV expression.
Analysis pass that exposes the ScalarEvolution for a function.
The main scalar evolution driver.
LLVM_ABI const SCEV * getSCEVAtScope(const SCEV *S, const Loop *L)
Return a SCEV expression for the specified value at the specified scope in the program.
LLVM_ABI const SCEV * getConstant(ConstantInt *V)
LLVM_ABI const SCEV * getSCEV(Value *V)
Return a SCEV expression for the full generality of the specified expression.
LLVM_ABI const SCEV * getMinusSCEV(const SCEV *LHS, const SCEV *RHS, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)
Return LHS-RHS.
LLVM_ABI const SCEV * getPointerBase(const SCEV *V)
Transitively follow the chain of pointer-type operands until reaching a SCEV that does not have a sin...
LLVM_ABI const SCEV * getMulExpr(SmallVectorImpl< const SCEV * > &Ops, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)
Get a canonical multiply expression, or something simpler if possible.
LLVM_ABI const SCEV * getElementSize(Instruction *Inst)
Return the size of an element read or written by Inst.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
iterator erase(const_iterator CI)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM Value Representation.
LLVM_ABI const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
This class implements an extremely fast bulk output stream that can only output to a stream.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
void visitAll(const SCEV *Root, SV &Visitor)
Use SCEVTraversal to visit all nodes in the given expression tree.
void collectParametricTerms(ScalarEvolution &SE, const SCEV *Expr, SmallVectorImpl< const SCEV * > &Terms)
Collect parametric terms occurring in step expressions (first step of delinearization).
void findArrayDimensions(ScalarEvolution &SE, SmallVectorImpl< const SCEV * > &Terms, SmallVectorImpl< const SCEV * > &Sizes, const SCEV *ElementSize)
Compute the array dimensions Sizes from the set of Terms extracted from the memory access function of...
const Value * getLoadStorePointerOperand(const Value *V)
A helper function that returns the pointer operand of a load or store instruction.
auto unique(Range &&R, Predicate P)
const Value * getPointerOperand(const Value *V)
A helper function that returns the pointer operand of a load, store or GEP instruction.
void computeAccessFunctions(ScalarEvolution &SE, const SCEV *Expr, SmallVectorImpl< const SCEV * > &Subscripts, SmallVectorImpl< const SCEV * > &Sizes)
Return in Subscripts the access functions for each dimension in Sizes (third step of delinearization)...
bool delinearizeFixedSizeArray(ScalarEvolution &SE, const SCEV *Expr, SmallVectorImpl< const SCEV * > &Subscripts, SmallVectorImpl< const SCEV * > &Sizes, const SCEV *ElementSize)
Split this SCEVAddRecExpr into two vectors of SCEVs representing the subscripts and sizes of an acces...
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool getIndexExpressionsFromGEP(ScalarEvolution &SE, const GetElementPtrInst *GEP, SmallVectorImpl< const SCEV * > &Subscripts, SmallVectorImpl< int > &Sizes)
Gathers the individual index expressions from a GEP instruction.
bool tryDelinearizeFixedSizeImpl(ScalarEvolution *SE, Instruction *Inst, const SCEV *AccessFn, SmallVectorImpl< const SCEV * > &Subscripts, SmallVectorImpl< int > &Sizes)
Implementation of fixed size array delinearization.
void delinearize(ScalarEvolution &SE, const SCEV *Expr, SmallVectorImpl< const SCEV * > &Subscripts, SmallVectorImpl< const SCEV * > &Sizes, const SCEV *ElementSize)
Split this SCEVAddRecExpr into two vectors of SCEVs representing the subscripts and sizes of an array...
bool findFixedSizeArrayDimensions(ScalarEvolution &SE, const SCEV *Expr, SmallVectorImpl< uint64_t > &Sizes, const SCEV *ElementSize)
Compute the dimensions of fixed size array from \Expr and save the results in Sizes.
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
void array_pod_sort(IteratorTy Start, IteratorTy End)
array_pod_sort - This sorts an array with the specified start and end extent.
bool SCEVExprContains(const SCEV *Root, PredTy Pred)
Return true if any node in Root satisfies the predicate Pred.
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
DelinearizationPrinterPass(raw_ostream &OS)
static void divide(ScalarEvolution &SE, const SCEV *Numerator, const SCEV *Denominator, const SCEV **Quotient, const SCEV **Remainder)
Computes the Quotient and Remainder of the division of Numerator by Denominator.