1//===- LoopCacheAnalysis.cpp - Loop Cache Analysis -------------------------==// 3// The LLVM Compiler Infrastructure 5// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 6// See https://llvm.org/LICENSE.txt for license information. 7// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 9//===----------------------------------------------------------------------===// 12/// This file defines the implementation for the loop cache analysis. 13/// The implementation is largely based on the following paper: 15/// Compiler Optimizations for Improving Data Locality 16/// By: Steve Carr, Katherine S. McKinley, Chau-Wen Tseng 17/// http://www.cs.utexas.edu/users/mckinley/papers/asplos-1994.pdf 19/// The general approach taken to estimate the number of cache lines used by the 20/// memory references in an inner loop is: 21/// 1. Partition memory references that exhibit temporal or spacial reuse 22/// into reference groups. 23/// 2. For each loop L in the a loop nest LN: 24/// a. Compute the cost of the reference group 25/// b. Compute the loop cost by summing up the reference groups costs 26//===----------------------------------------------------------------------===// 43#define DEBUG_TYPE "loop-cache-cost" 47cl::desc(
"Use this to specify the default trip count of a loop"));
49// In this analysis two array references are considered to exhibit temporal 50// reuse if they access either the same memory location, or a memory location 51// with distance smaller than a configurable threshold. 54cl::desc(
"Use this to specify the max. distance between array elements " 55"accessed in a loop so that the elements are classified to have " 58/// Retrieve the innermost loop in the given loop nest \p Loops. It returns a 59/// nullptr if any loops in the loop vector supplied has more than one sibling. 60/// The loop vector is expected to contain loops collected in breadth-first 63assert(!
Loops.empty() &&
"Expecting a non-empy loop vector");
68if (ParentLoop ==
nullptr) {
69assert(
Loops.size() == 1 &&
"Expecting a single loop");
89// Check that start and increment are not add recurrences. 92if (isa<SCEVAddRecExpr>(Start) || isa<SCEVAddRecExpr>(Step))
95// Check that start and increment are both invariant in the loop. 103return StepRec == &ElemSize;
106/// Compute the trip count for the given loop \p L or assume a default value if 107/// it is not a compile time constant. Return the SCEV expression for the trip 112constSCEV *TripCount = (!isa<SCEVCouldNotCompute>(BackedgeTakenCount) &&
113 isa<SCEVConstant>(BackedgeTakenCount))
119 <<
" could not be computed, using DefaultTripCount\n");
126//===----------------------------------------------------------------------===// 127// IndexedReference implementation 131OS << R.StoreOrLoadInst;
132OS <<
", IsValid=false.";
137for (
constSCEV *Subscript : R.Subscripts)
138OS <<
"[" << *Subscript <<
"]";
149 : StoreOrLoadInst(StoreOrLoadInst), SE(SE) {
150assert((isa<StoreInst>(StoreOrLoadInst) || isa<LoadInst>(StoreOrLoadInst)) &&
151"Expecting a load or store instruction");
153 IsValid = delinearize(LI);
162assert(IsValid &&
"Expecting a valid reference");
164if (BasePointer !=
Other.getBasePointer() && !isAliased(
Other, AA)) {
166 <<
"No spacial reuse: different base pointers\n");
171if (NumSubscripts !=
Other.getNumSubscripts()) {
173 <<
"No spacial reuse: different number of subscripts\n");
177// all subscripts must be equal, except the leftmost one (the last one). 178for (
auto SubNum : seq<unsigned>(0, NumSubscripts - 1)) {
182 << *
Other.getSubscript(SubNum) <<
"\n");
187// the difference between the last subscripts must be less than the cache line 190constSCEV *OtherLastSubscript =
Other.getLastSubscript();
196 <<
"No spacial reuse, difference between subscript:\n\t" 197 << *LastSubscript <<
"\n\t" << OtherLastSubscript
198 <<
"\nis not constant.\n");
211return InSameCacheLine;
216unsigned MaxDistance,
constLoop &L,
218assert(IsValid &&
"Expecting a valid reference");
220if (BasePointer !=
Other.getBasePointer() && !isAliased(
Other, AA)) {
222 <<
"No temporal reuse: different base pointer\n");
226 std::unique_ptr<Dependence>
D =
227 DI.
depends(&StoreOrLoadInst, &
Other.StoreOrLoadInst,
true);
234if (
D->isLoopIndependent()) {
239// Check the dependence distance at every loop level. There is temporal reuse 240// if the distance at the given loop's depth is small (|d| <= MaxDistance) and 241// it is zero at every other loop level. 242int LoopDepth = L.getLoopDepth();
243int Levels =
D->getLevels();
244for (
int Level = 1; Level <= Levels; ++Level) {
245constSCEV *Distance =
D->getDistance(Level);
246constSCEVConstant *SCEVConst = dyn_cast_or_null<SCEVConstant>(Distance);
248if (SCEVConst ==
nullptr) {
254if (Level != LoopDepth && !CI.
isZero()) {
256 <<
"No temporal reuse: distance is not zero at depth=" << Level
259 }
elseif (Level == LoopDepth && CI.
getSExtValue() > MaxDistance) {
262 <<
"No temporal reuse: distance is greater than MaxDistance at depth=" 274assert(IsValid &&
"Expecting a valid reference");
276dbgs().
indent(2) <<
"Computing cache cost for:\n";
280// If the indexed reference is loop invariant the cost is one. 281if (isLoopInvariant(L)) {
287assert(TripCount &&
"Expecting valid TripCount");
290constSCEV *RefCost =
nullptr;
291constSCEV *Stride =
nullptr;
292if (isConsecutive(L, Stride, CLS)) {
293// If the indexed reference is 'consecutive' the cost is 294// (TripCount*Stride)/CLS. 296"Stride should not be null for consecutive access!");
302// Round the fractional cost up to the nearest integer number. 303// The impact is the most significant when cost is calculated 304// to be a number less than one, because it makes more sense 305// to say one cache line is used rather than zero cache line 310 <<
"Access is consecutive: RefCost=(TripCount*Stride)/CLS=" 313// If the indexed reference is not 'consecutive' the cost is proportional to 314// the trip count and the depth of the dimension which the subject loop 315// subscript is accessing. We try to estimate this by multiplying the cost 316// by the trip counts of loops corresponding to the inner dimensions. For 317// example, given the indexed reference 'A[i][j][k]', and assuming the 318// i-loop is in the innermost position, the cost would be equal to the 319// iterations of the i-loop multiplied by iterations of the j-loop. 322int Index = getSubscriptIndex(L);
323assert(Index >= 0 &&
"Could not locate a valid Index");
328constSCEV *TripCount =
331// For the multiplication result to fit, request a type twice as wide. 338 <<
"Access is not consecutive: RefCost=" << *RefCost <<
"\n");
340assert(RefCost &&
"Expecting a valid RefCost");
342// Attempt to fold RefCost into a constant. 343// CacheCostTy is a signed integer, but the tripcount value can be large 344// and may not fit, so saturate/limit the value to the maximum signed 346if (
auto ConstantCost = dyn_cast<SCEVConstant>(RefCost))
347return ConstantCost->getValue()->getLimitedValue(
348 std::numeric_limits<int64_t>::max());
351 <<
"RefCost is not a constant! Setting to RefCost=InvalidCost " 352"(invalid value).\n");
357bool IndexedReference::tryDelinearizeFixedSize(
364// Populate Sizes with scev expressions to be used in calculations later. 365for (
autoIdx : seq<unsigned>(1, Subscripts.
size()))
370dbgs() <<
"Delinearized subscripts of fixed-size array\n" 377bool IndexedReference::delinearize(
constLoopInfo &LI) {
378assert(Subscripts.
empty() &&
"Subscripts should be empty");
379assert(Sizes.empty() &&
"Sizes should be empty");
380assert(!IsValid &&
"Should be called once from the constructor");
391if (BasePointer ==
nullptr) {
394 <<
"ERROR: failed to delinearize, can't identify base pointer\n");
398bool IsFixedSize =
false;
399// Try to delinearize fixed-size arrays. 400if (tryDelinearizeFixedSize(AccessFn, Subscripts)) {
402// The last element of Sizes is the element size. 403 Sizes.push_back(ElemSize);
405 <<
"', AccessFn: " << *AccessFn <<
"\n");
410// Try to delinearize parametric-size arrays. 413 <<
"', AccessFn: " << *AccessFn <<
"\n");
418if (Subscripts.
empty() || Sizes.empty() ||
419 Subscripts.
size() != Sizes.size()) {
420// Attempt to determine whether we have a single dimensional array access. 424 <<
"ERROR: failed to delinearize reference\n");
430// The array may be accessed in reverse, for example: 431// for (i = N; i > 0; i--) 433// In this case, reconstruct the access function using the absolute value 434// of the step recurrence. 435constSCEVAddRecExpr *AccessFnAR = dyn_cast<SCEVAddRecExpr>(AccessFn);
445 Sizes.push_back(ElemSize);
448returnall_of(Subscripts, [&](
constSCEV *Subscript) {
449return isSimpleAddRecurrence(*Subscript, *L);
456bool IndexedReference::isLoopInvariant(
constLoop &L)
const{
458assert(
Addr !=
nullptr &&
"Expecting either a load or a store instruction");
464// The indexed reference is loop invariant if none of the coefficients use 465// the loop induction variable. 466bool allCoeffForLoopAreZero =
all_of(Subscripts, [&](
constSCEV *Subscript) {
467return isCoeffForLoopZeroOrInvariant(*Subscript, L);
470return allCoeffForLoopAreZero;
473bool IndexedReference::isConsecutive(
constLoop &L,
constSCEV *&Stride,
475// The indexed reference is 'consecutive' if the only coefficient that uses 476// the loop induction variable is the last one... 477constSCEV *LastSubscript = Subscripts.
back();
478for (
constSCEV *Subscript : Subscripts) {
479if (Subscript == LastSubscript)
481if (!isCoeffForLoopZeroOrInvariant(*Subscript, L))
485// ...and the access stride is less than the cache line size. 486constSCEV *Coeff = getLastCoefficient();
487constSCEV *ElemSize = Sizes.back();
489// FIXME: This assumes that all values are signed integers which may 490// be incorrect in unusual codes and incorrectly use sext instead of zext. 491// for (uint32_t i = 0; i < 512; ++i) { 495// This consecutively iterates twice over A. If `trunc` is sign-extended, 496// we would conclude that this may iterate backwards over the array. 497// However, LoopCacheAnalysis is heuristic anyway and transformations must 498// not result in wrong optimizations if the heuristic was incorrect. 507int IndexedReference::getSubscriptIndex(
constLoop &L)
const{
510if (AR && AR->
getLoop() == &L) {
517constSCEV *IndexedReference::getLastCoefficient()
const{
519auto *AR = cast<SCEVAddRecExpr>(LastSubscript);
523bool IndexedReference::isCoeffForLoopZeroOrInvariant(
constSCEV &Subscript,
526return (AR !=
nullptr) ? AR->
getLoop() != &
L 530bool IndexedReference::isSimpleAddRecurrence(
constSCEV &Subscript,
532if (!isa<SCEVAddRecExpr>(Subscript))
557//===----------------------------------------------------------------------===// 558// CacheCost implementation 561for (
constauto &LC :
CC.LoopCosts) {
562constLoop *L = LC.first;
563OS <<
"Loop '" << L->getName() <<
"' has cost = " << LC.second <<
"\n";
571 std::optional<unsigned> TRT)
574assert(!
Loops.empty() &&
"Expecting a non-empty loop vector.");
582 calculateCacheFootprint();
585std::unique_ptr<CacheCost>
589LLVM_DEBUG(
dbgs() <<
"Expecting the outermost loop in a loop nest\n");
597LLVM_DEBUG(
dbgs() <<
"Cannot compute cache cost of loop nest with more " 598"than one innermost loop\n");
602return std::make_unique<CacheCost>(
Loops, AR.
LI, AR.
SE, AR.
TTI, AR.
AA, DI, TRT);
605void CacheCost::calculateCacheFootprint() {
608if (!populateReferenceGroups(RefGroups))
612for (
constLoop *L : Loops) {
615 [L](
const LoopCacheCostTy &LCC) {
return LCC.first == L; }) &&
616"Should not add duplicate element");
617CacheCostTy LoopCost = computeLoopCacheCost(*L, RefGroups);
618 LoopCosts.
push_back(std::make_pair(L, LoopCost));
626assert(RefGroups.
empty() &&
"Reference groups should be empty");
630assert(InnerMostLoop !=
nullptr &&
"Expecting a valid innermost loop");
634if (!isa<StoreInst>(
I) && !isa<LoadInst>(
I))
645dbgs() <<
"References:\n";
651// FIXME: Both positive and negative access functions will be placed 652// into the same reference group, resulting in a bi-directional array 654// for (i = N; i > 0; i--) 656// having the same cost calculation as a single dimention access pattern 657// for (i = 0; i < N; i++) 659// when in actuality, depending on the array size, the first example 660// should have a cost closer to 2x the second due to the two cache 661// access per iteration from opposite ends of the array 662 std::optional<bool> HasTemporalReuse =
663R->hasTemporalReuse(Representative, *TRT, *InnerMostLoop, DI, AA);
664 std::optional<bool> HasSpacialReuse =
665R->hasSpacialReuse(Representative, CLS, AA);
667if ((HasTemporalReuse && *HasTemporalReuse) ||
668 (HasSpacialReuse && *HasSpacialReuse)) {
669 RefGroup.push_back(std::move(R));
678 RefGroups.push_back(std::move(RG));
683if (RefGroups.empty())
687dbgs() <<
"\nIDENTIFIED REFERENCE GROUPS:\n";
691for (
constauto &
IR : RG)
702CacheCost::computeLoopCacheCost(
constLoop &L,
704if (!
L.isLoopSimplifyForm())
708 <<
"' as innermost loop.\n");
710// Compute the product of the trip counts of each other loop in the nest. 712for (
constauto &TC : TripCounts) {
715 TripCountsProduct *= TC.second;
720CacheCostTy RefGroupCost = computeRefGroupCacheCost(RG, L);
721 LoopCost += RefGroupCost * TripCountsProduct;
725 <<
"' has cost=" << LoopCost <<
"\n");
732assert(!RG.
empty() &&
"Reference group should have at least one member.");
738//===----------------------------------------------------------------------===// 739// LoopCachePrinterPass implementation This file builds on the ADT/GraphTraits.h file to build a generic breadth first graph iterator.
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
Legalize the Machine IR a function s Machine IR
static bool isOneDimensionalArray(const SCEV &AccessFn, const SCEV &ElemSize, const Loop &L, ScalarEvolution &SE)
static cl::opt< unsigned > TemporalReuseThreshold("temporal-reuse-threshold", cl::init(2), cl::Hidden, cl::desc("Use this to specify the max. distance between array elements " "accessed in a loop so that the elements are classified to have " "temporal reuse"))
static const SCEV * computeTripCount(const Loop &L, const SCEV &ElemSize, ScalarEvolution &SE)
Compute the trip count for the given loop L or assume a default value if it is not a compile time con...
static Loop * getInnerMostLoop(const LoopVectorTy &Loops)
Retrieve the innermost loop in the given loop nest Loops.
static cl::opt< unsigned > DefaultTripCount("default-trip-count", cl::init(100), cl::Hidden, cl::desc("Use this to specify the default trip count of a loop"))
This file defines the interface for the loop cache analysis.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Provides some synthesis utilities to produce sequences of values.
This file defines the SmallVector class.
static cl::opt< unsigned > CacheLineSize("cache-line-size", cl::init(0), cl::Hidden, cl::desc("Use this to override the target cache line size when " "specified by the user."))
This pass exposes codegen information to IR-level passes.
bool isMustAlias(const MemoryLocation &LocA, const MemoryLocation &LocB)
A trivial helper function to check to see if the specified pointers are must-alias.
A container for analyses that lazily runs them and caches their results.
LLVM Basic Block Representation.
CacheCost represents the estimated cost of a inner loop as the number of cache lines used by the memo...
CacheCost(const LoopVectorTy &Loops, const LoopInfo &LI, ScalarEvolution &SE, TargetTransformInfo &TTI, AAResults &AA, DependenceInfo &DI, std::optional< unsigned > TRT=std::nullopt)
Construct a CacheCost object for the loop nest described by Loops.
static std::unique_ptr< CacheCost > getCacheCost(Loop &Root, LoopStandardAnalysisResults &AR, DependenceInfo &DI, std::optional< unsigned > TRT=std::nullopt)
Create a CacheCost for the loop nest rooted by Root.
@ ICMP_ULT
unsigned less than
This is the shared class of boolean and integer constants.
bool isZero() const
This is just a convenience method to make client code smaller for a common code.
int64_t getSExtValue() const
Return the constant as a 64-bit integer value after it has been sign extended as appropriate for the ...
DependenceInfo - This class is the main dependence-analysis driver.
std::unique_ptr< Dependence > depends(Instruction *Src, Instruction *Dst, bool PossiblyLoopIndependent)
depends - Tests for a dependence between the Src and Dst instructions.
Represents a memory reference as a base pointer and a set of indexing operations.
CacheCostTy computeRefCost(const Loop &L, unsigned CLS) const
Compute the cost of the reference w.r.t.
const SCEV * getSubscript(unsigned SubNum) const
std::optional< bool > hasSpacialReuse(const IndexedReference &Other, unsigned CLS, AAResults &AA) const
Return true/false if the current object and the indexed reference Other are/aren't in the same cache ...
std::optional< bool > hasTemporalReuse(const IndexedReference &Other, unsigned MaxDistance, const Loop &L, DependenceInfo &DI, AAResults &AA) const
Return true if the current object and the indexed reference Other have distance smaller than MaxDista...
IndexedReference(Instruction &StoreOrLoadInst, const LoopInfo &LI, ScalarEvolution &SE)
Construct an indexed reference given a StoreOrLoadInst instruction.
const SCEV * getLastSubscript() const
size_t getNumSubscripts() const
static InstructionCost getInvalid(CostType Val=0)
This class provides an interface for updating the loop pass manager based on mutations to the loop ne...
bool isOutermost() const
Return true if the loop does not have a parent (natural) loop.
unsigned getLoopDepth() const
Return the nesting level of this loop.
ArrayRef< BlockT * > getBlocks() const
Get a list of the basic blocks which make up this loop.
LoopT * getParentLoop() const
Return the parent loop if it exists or nullptr for top level loops.
PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &U)
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
Represents a single loop in the control flow graph.
static MemoryLocation get(const LoadInst *LI)
Return a location with information about the memory reference by the given instruction.
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.
const Loop * getLoop() const
This class represents a constant integer value.
ConstantInt * getValue() const
NoWrapFlags getNoWrapFlags(NoWrapFlags Mask=NoWrapMask) const
This class represents an analyzed expression in the program.
Type * getType() const
Return the LLVM type of this SCEV expression.
The main scalar evolution driver.
const SCEV * getNegativeSCEV(const SCEV *V, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap)
Return the SCEV object corresponding to -V.
const SCEV * getUDivCeilSCEV(const SCEV *N, const SCEV *D)
Compute ceil(N / D).
Type * getWiderType(Type *Ty1, Type *Ty2) const
bool isKnownNegative(const SCEV *S)
Test if the given expression is known to be negative.
const SCEV * getSCEVAtScope(const SCEV *S, const Loop *L)
Return a SCEV expression for the specified value at the specified scope in the program.
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...
const SCEV * getConstant(ConstantInt *V)
const SCEV * getSCEV(Value *V)
Return a SCEV expression for the full generality of the specified expression.
const SCEV * getNoopOrSignExtend(const SCEV *V, Type *Ty)
Return a SCEV corresponding to a conversion of the input value to the specified type.
const SCEV * getTripCountFromExitCount(const SCEV *ExitCount)
A version of getTripCountFromExitCount below which always picks an evaluation type which can not resu...
bool isLoopInvariant(const SCEV *S, const Loop *L)
Return true if the value of the given SCEV is unchanging in the specified loop.
const SCEV * getAddRecExpr(const SCEV *Start, const SCEV *Step, const Loop *L, SCEV::NoWrapFlags Flags)
Get an add recurrence expression for the specified loop.
bool isSCEVable(Type *Ty) const
Test if values of the given type are analyzable within the SCEV framework.
const SCEV * getNoopOrAnyExtend(const SCEV *V, Type *Ty)
Return a SCEV corresponding to a conversion of the input value to the specified type.
const SCEV * getMinusSCEV(const SCEV *LHS, const SCEV *RHS, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)
Return LHS-RHS.
const SCEV * getNoopOrZeroExtend(const SCEV *V, Type *Ty)
Return a SCEV corresponding to a conversion of the input value to the specified type.
unsigned getSmallConstantTripCount(const Loop *L)
Returns the exact trip count of the loop if we can compute it, and the result is a small constant.
const SCEV * getPointerBase(const SCEV *V)
Transitively follow the chain of pointer-type operands until reaching a SCEV that does not have a sin...
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.
const SCEV * getElementSize(Instruction *Inst)
Return the size of an element read or written by Inst.
const SCEV * getUDivExactExpr(const SCEV *LHS, const SCEV *RHS)
Get a canonical unsigned division expression, or something simpler if possible.
bool isKnownPredicate(CmpPredicate Pred, const SCEV *LHS, const SCEV *RHS)
Test if the given expression is known to satisfy the condition described by Pred, LHS,...
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This pass provides access to the codegen interfaces that are needed for IR-level transformations.
unsigned getCacheLineSize() const
The instances of the Type class are immutable: once they are created, they are never changed.
Type * getExtendedType() const
Given scalar/vector integer type, returns a type with elements twice as wide as in the original type.
LLVM Value Representation.
const ParentTy * getParent() const
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.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
const Value * getLoadStorePointerOperand(const Value *V)
A helper function that returns the pointer operand of a load or store instruction.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
const Value * getPointerOperand(const Value *V)
A helper function that returns the pointer operand of a load, store or GEP instruction.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool none_of(R &&Range, UnaryPredicate P)
Provide wrappers to std::none_of which take ranges instead of having to pass begin/end explicitly.
bool is_sorted(R &&Range, Compare C)
Wrapper function around std::is_sorted to check if elements in a range R are sorted with respect to a...
iterator_range< bf_iterator< T > > breadth_first(const T &G)
bool tryDelinearizeFixedSizeImpl(ScalarEvolution *SE, Instruction *Inst, const SCEV *AccessFn, SmallVectorImpl< const SCEV * > &Subscripts, SmallVectorImpl< int > &Sizes)
Implementation of fixed size array delinearization.
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
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...
The adaptor from a function pass to a loop pass computes these analyses and makes them available to t...
TargetTransformInfo & TTI