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."));
53struct SCEVCollectStrides {
55 SmallVectorImpl<const SCEV *> &Strides;
57 SCEVCollectStrides(ScalarEvolution &SE, SmallVectorImpl<const SCEV *> &S)
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 {
71 SmallVectorImpl<const SCEV *> &Terms;
73 SCEVCollectTerms(SmallVectorImpl<const SCEV *> &
T) : Terms(
T) {}
75 bool follow(
const SCEV *S) {
89 bool isDone()
const {
return false; }
96 SCEVHasAddRec(
bool &ContainsAddRec) : ContainsAddRec(ContainsAddRec) {
97 ContainsAddRec =
false;
100 bool follow(
const SCEV *S) {
102 ContainsAddRec =
true;
112 bool isDone()
const {
return false; }
127struct SCEVCollectAddRecMultiplies {
128 SmallVectorImpl<const SCEV *> &Terms;
131 SCEVCollectAddRecMultiplies(SmallVectorImpl<const SCEV *> &
T,
133 : Terms(
T), SE(SE) {}
135 bool follow(
const SCEV *S) {
137 bool HasAddRec =
false;
139 for (
const SCEV *
Op :
Mul->operands()) {
146 bool ContainsAddRec =
false;
147 SCEVHasAddRec ContiansAddRec(ContainsAddRec);
149 HasAddRec |= ContainsAddRec;
152 if (Operands.
size() == 0)
158 Terms.push_back(SE.getMulExpr(Operands));
167 bool isDone()
const {
return false; }
179 SCEVCollectStrides StrideCollector(SE, Strides);
183 dbgs() <<
"Strides:\n";
184 for (
const SCEV *S : Strides)
188 for (
const SCEV *S : Strides) {
189 SCEVCollectTerms TermCollector(Terms);
194 dbgs() <<
"Terms:\n";
195 for (
const SCEV *
T : Terms)
199 SCEVCollectAddRecMultiplies MulCollector(Terms, SE);
213 for (
const SCEV *
Op : M->operands())
220 Sizes.push_back(Step);
224 for (
const SCEV *&Term : Terms) {
239 if (Terms.
size() > 0)
243 Sizes.push_back(Step);
249 for (
const SCEV *
T : Terms)
259 return Expr->getNumOperands();
272 for (
const SCEV *
Op : M->operands())
285 const SCEV *ElementSize) {
286 if (Terms.
size() < 1 || !ElementSize)
295 dbgs() <<
"Terms:\n";
296 for (
const SCEV *
T : Terms)
311 for (
const SCEV *&Term : Terms) {
321 for (
const SCEV *
T : Terms)
326 dbgs() <<
"Terms after sorting:\n";
327 for (
const SCEV *
T : NewTerms)
337 Sizes.push_back(ElementSize);
340 dbgs() <<
"Sizes:\n";
341 for (
const SCEV *S : Sizes)
361 <<
"Memory Access Function: " << *Expr <<
"\n");
363 const SCEV *Res = Expr;
364 int Last = Sizes.size() - 1;
366 for (
int i =
Last; i >= 0; i--) {
373 dbgs() <<
"Computing 'MemAccFn / Sizes[" << i <<
"]':\n";
374 dbgs() <<
" MemAccFn: " << *Res <<
"\n";
375 dbgs() <<
" Sizes[" << i <<
"]: " << *
Size <<
"\n";
376 dbgs() <<
" Quotient (Leftover): " << *Q <<
"\n";
377 dbgs() <<
" Remainder (Subscript Access Function): " << *R <<
"\n";
404 std::reverse(Subscripts.
begin(), Subscripts.
end());
407 dbgs() <<
"Subscripts:\n";
408 for (
const SCEV *S : Subscripts)
466 const SCEV *ElementSize) {
490 return Const->getAPInt();
504 const uint64_t Mod = Const->getAPInt().urem(ElementSize);
534 const SCEV *ElementSize) {
538 std::optional<APInt> ElementSizeAPInt =
tryIntoAPInt(ElementSize);
539 if (!ElementSizeAPInt || *ElementSizeAPInt == 0)
542 std::optional<uint64_t> ElementSizeConst = ElementSizeAPInt->tryZExtValue();
545 if (!ElementSizeConst)
576 assert(Sizes.back() != 0 &&
"Unexpected zero size in Sizes.");
579 for (
unsigned I = 0;
I + 1 < Sizes.size();
I++) {
581 if (Sizes[
I] % PrevSize) {
585 Sizes[
I] /= PrevSize;
589 Sizes.back() = *ElementSizeConst;
647 const SCEV *ElementSize) {
666 return !Subscripts.
empty();
671 bool Inbounds =
false;
673 Inbounds = SrcGEP->isInBounds();
676 if (AddRec->isAffine()) {
700 if (!SType || !SizeType)
703 (SType->getBitWidth() >= SizeType->getBitWidth()) ? SType : SizeType;
707 auto CollectUpperBound = [&](
const Loop *L,
Type *
T) ->
const SCEV * {
715 auto CheckAddRecBECount = [&]() {
719 const SCEV *BECount = CollectUpperBound(AddRec->
getLoop(), MaxType);
748 if (CheckAddRecBECount())
780 for (
size_t I = 1;
I < Sizes.size(); ++
I) {
782 const SCEV *Subscript = Subscripts[
I];
839 "Expected output lists to be empty on entry to this function.");
840 assert(
GEP &&
"getIndexExpressionsFromGEP called with a null GEP");
844 bool DroppedFirstDim =
false;
845 for (
unsigned i = 1; i <
GEP->getNumOperands(); i++) {
848 Ty =
GEP->getSourceElementType();
850 if (Const->getValue()->isZero()) {
851 DroppedFirstDim =
true;
861 <<
" is not an array type.\n");
868 if (!(DroppedFirstDim && i == 2))
869 Sizes.push_back(SE.
getConstant(IndexTy, ArrayTy->getNumElements()));
871 Ty = ArrayTy->getElementType();
874 dbgs() <<
"Subscripts:\n";
875 for (
const SCEV *S : Subscripts)
876 dbgs() << *S <<
"\n";
880 return !Subscripts.
empty();
887 O <<
"Printing analysis 'Delinearization' for function '" <<
F->getName()
911 O <<
"Inst:" << Inst <<
"\n";
912 O <<
"AccessFunction: " << *AccessFn <<
"\n";
916 auto IsDelinearizationFailed = [&]() {
917 return Subscripts.
size() == 0 || Sizes.size() == 0 ||
918 Subscripts.
size() != Sizes.size();
929 if (IsDelinearizationFailed()) {
930 O <<
"failed to delinearize\n";
934 O <<
"Base offset: " << *BasePointer <<
"\n";
935 O <<
"ArrayDecl[UnknownSize]";
937 for (
int i = 0; i <
Size - 1; i++)
938 O <<
"[" << *Sizes[i] <<
"]";
939 O <<
" with elements of " << *
Sizes[
Size - 1] <<
" bytes.\n";
942 for (
int i = 0; i <
Size; i++)
943 O <<
"[" << *Subscripts[i] <<
"]";
948 O <<
"Delinearization validation: " << (IsValid ?
"Succeeded" :
"Failed")
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Expand Atomic instructions
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
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 bool isKnownLessThan(ScalarEvolution *SE, const SCEV *S, const SCEV *Size)
Compare to see if S is less than Size, using.
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.
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
static SymbolRef::Type getType(const Symbol *Sym)
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.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
LLVM Basic Block Representation.
const Function * getParent() const
Return the enclosing method, or null if none.
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
LLVM_ABI const SCEV * evaluateAtIteration(const SCEV *It, ScalarEvolution &SE) const
Return the value of this chain of recurrences at the specified iteration number.
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.
const Loop * getLoop() const
This node represents multiplication of some number of SCEVs.
bool hasNoSignedWrap() const
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 bool isKnownNonNegative(const SCEV *S)
Test if the given expression is known to be non-negative.
LLVM_ABI bool isKnownNonPositive(const SCEV *S)
Test if the given expression is known to be non-positive.
LLVM_ABI bool isKnownNegative(const SCEV *S)
Test if the given expression is known to be negative.
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 * getBackedgeTakenCount(const Loop *L, ExitCountKind Kind=Exact)
If the specified loop has a predictable backedge-taken count, return it, otherwise return a SCEVCould...
LLVM_ABI bool willNotOverflow(Instruction::BinaryOps BinOp, bool Signed, const SCEV *LHS, const SCEV *RHS, const Instruction *CtxI=nullptr)
Is operation BinOp between LHS and RHS provably does not have a signed/unsigned overflow (Signed)?
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.
const SCEV * getOne(Type *Ty)
Return a SCEV for the constant 1 of a specific type.
LLVM_ABI Type * getEffectiveSCEVType(Type *Ty) const
Return a type with the same bitwidth as the given type and which represents how SCEV will treat the g...
LLVM_ABI const SCEV * getMinusSCEV(const SCEV *LHS, const SCEV *RHS, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)
Return LHS-RHS.
LLVM_ABI bool hasLoopInvariantBackedgeTakenCount(const Loop *L)
Return true if the specified loop has an analyzable loop-invariant backedge-taken count.
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.
LLVM_ABI const SCEV * getTruncateOrZeroExtend(const SCEV *V, Type *Ty, unsigned Depth=0)
Return a SCEV corresponding to a conversion of the input value to the specified type.
LLVM_ABI const SCEV * getAddExpr(SmallVectorImpl< const SCEV * > &Ops, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)
Get a canonical add expression, or something simpler if possible.
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.
This class implements an extremely fast bulk output stream that can only output to a stream.
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
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.
std::enable_if_t< std::is_signed_v< T >, T > MulOverflow(T X, T Y, T &Result)
Multiply two signed integers, computing the two's complement truncated result, returning true if an o...
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...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
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.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
@ Mul
Product of integers.
DWARFExpression::Operation Op
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...
std::enable_if_t< std::is_signed_v< T >, T > AddOverflow(T X, T Y, T &Result)
Add two signed integers, computing the two's complement truncated result, returning true if overflow ...
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
void array_pod_sort(IteratorTy Start, IteratorTy End)
array_pod_sort - This sorts an array with the specified start and end extent.
bool validateDelinearizationResult(ScalarEvolution &SE, ArrayRef< const SCEV * > Sizes, ArrayRef< const SCEV * > Subscripts, const Value *Ptr=nullptr)
Check that each subscript in Subscripts is within the corresponding size in Sizes.
LLVM_ABI bool isKnownNonNegative(const Value *V, const SimplifyQuery &SQ, unsigned Depth=0)
Returns true if the give value is known to be non-negative.
bool getIndexExpressionsFromGEP(ScalarEvolution &SE, const GetElementPtrInst *GEP, SmallVectorImpl< const SCEV * > &Subscripts, SmallVectorImpl< const SCEV * > &Sizes)
Gathers the individual index expressions from a GEP instruction.
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.