LLVM: lib/Analysis/LoopCacheAnalysis.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
40
41using namespace llvm;
42
43#define DEBUG_TYPE "loop-cache-cost"
44
47 cl::desc("Use this to specify the default trip count of a loop"));
48
49
50
51
54 cl::desc("Use this to specify the max. distance between array elements "
55 "accessed in a loop so that the elements are classified to have "
56 "temporal reuse"));
57
58
59
60
61
63 assert(.empty() && "Expecting a non-empy loop vector");
64
67
68 if (ParentLoop == nullptr) {
69 assert(Loops.size() == 1 && "Expecting a single loop");
70 return LastLoop;
71 }
72
74 [](const Loop *L1, const Loop *L2) {
76 }))
77 ? LastLoop
78 : nullptr;
79}
80
83 const SCEVAddRecExpr *AR = dyn_cast(&AccessFn);
85 return false;
86
88
89
92 if (isa(Start) || isa(Step))
93 return false;
94
95
97 return false;
98
102
103 return StepRec == &ElemSize;
104}
105
106
107
108
112 const SCEV *TripCount = (!isa(BackedgeTakenCount) &&
113 isa(BackedgeTakenCount))
115 : nullptr;
116
117 if (!TripCount) {
118 LLVM_DEBUG(dbgs() << "Trip count of loop " << L.getName()
119 << " could not be computed, using DefaultTripCount\n");
121 }
122
123 return TripCount;
124}
125
126
127
128
130 if (!R.IsValid) {
131 OS << R.StoreOrLoadInst;
132 OS << ", IsValid=false.";
133 return OS;
134 }
135
136 OS << *R.BasePointer;
137 for (const SCEV *Subscript : R.Subscripts)
138 OS << "[" << *Subscript << "]";
139
140 OS << ", Sizes: ";
141 for (const SCEV *Size : R.Sizes)
142 OS << "[" << *Size << "]";
143
144 return OS;
145}
146
149 : StoreOrLoadInst(StoreOrLoadInst), SE(SE) {
150 assert((isa(StoreOrLoadInst) || isa(StoreOrLoadInst)) &&
151 "Expecting a load or store instruction");
152
153 IsValid = delinearize(LI);
154 if (IsValid)
156 << "\n");
157}
158
159std::optional
162 assert(IsValid && "Expecting a valid reference");
163
164 if (BasePointer != Other.getBasePointer() && !isAliased(Other, AA)) {
166 << "No spacial reuse: different base pointers\n");
167 return false;
168 }
169
171 if (NumSubscripts != Other.getNumSubscripts()) {
173 << "No spacial reuse: different number of subscripts\n");
174 return false;
175 }
176
177
178 for (auto SubNum : seq(0, NumSubscripts - 1)) {
182 << *Other.getSubscript(SubNum) << "\n");
183 return false;
184 }
185 }
186
187
188
190 const SCEV *OtherLastSubscript = Other.getLastSubscript();
191 const SCEVConstant *Diff = dyn_cast(
192 SE.getMinusSCEV(LastSubscript, OtherLastSubscript));
193
194 if (Diff == nullptr) {
196 << "No spacial reuse, difference between subscript:\n\t"
197 << *LastSubscript << "\n\t" << OtherLastSubscript
198 << "\nis not constant.\n");
199 return std::nullopt;
200 }
201
203
205 if (InSameCacheLine)
206 dbgs().indent(2) << "Found spacial reuse.\n";
207 else
208 dbgs().indent(2) << "No spacial reuse.\n";
209 });
210
211 return InSameCacheLine;
212}
213
214std::optional
216 unsigned MaxDistance, const Loop &L,
218 assert(IsValid && "Expecting a valid reference");
219
220 if (BasePointer != Other.getBasePointer() && !isAliased(Other, AA)) {
222 << "No temporal reuse: different base pointer\n");
223 return false;
224 }
225
226 std::unique_ptr D =
227 DI.depends(&StoreOrLoadInst, &Other.StoreOrLoadInst, true);
228
229 if (D == nullptr) {
231 return false;
232 }
233
234 if (D->isLoopIndependent()) {
236 return true;
237 }
238
239
240
241
242 int LoopDepth = L.getLoopDepth();
243 int Levels = D->getLevels();
244 for (int Level = 1; Level <= Levels; ++Level) {
245 const SCEV *Distance = D->getDistance(Level);
246 const SCEVConstant *SCEVConst = dyn_cast_or_null(Distance);
247
248 if (SCEVConst == nullptr) {
250 return std::nullopt;
251 }
252
254 if (Level != LoopDepth && !CI.isZero()) {
256 << "No temporal reuse: distance is not zero at depth=" << Level
257 << "\n");
258 return false;
259 } else if (Level == LoopDepth && CI.getSExtValue() > MaxDistance) {
262 << "No temporal reuse: distance is greater than MaxDistance at depth="
263 << Level << "\n");
264 return false;
265 }
266 }
267
269 return true;
270}
271
273 unsigned CLS) const {
274 assert(IsValid && "Expecting a valid reference");
276 dbgs().indent(2) << "Computing cache cost for:\n";
278 });
279
280
281 if (isLoopInvariant(L)) {
283 return 1;
284 }
285
287 assert(TripCount && "Expecting valid TripCount");
288 LLVM_DEBUG(dbgs() << "TripCount=" << *TripCount << "\n");
289
290 const SCEV *RefCost = nullptr;
291 const SCEV *Stride = nullptr;
292 if (isConsecutive(L, Stride, CLS)) {
293
294
295 assert(Stride != nullptr &&
296 "Stride should not be null for consecutive access!");
301 const SCEV *Numerator = SE.getMulExpr(Stride, TripCount);
302
303
304
305
306
308
310 << "Access is consecutive: RefCost=(TripCount*Stride)/CLS="
311 << *RefCost << "\n");
312 } else {
313
314
315
316
317
318
319
320 RefCost = TripCount;
321
322 int Index = getSubscriptIndex(L);
323 assert(Index >= 0 && "Could not locate a valid Index");
324
327 assert(AR && AR->getLoop() && "Expecting valid loop");
328 const SCEV *TripCount =
331
335 }
336
338 << "Access is not consecutive: RefCost=" << *RefCost << "\n");
339 }
340 assert(RefCost && "Expecting a valid RefCost");
341
342
343
344
345
346 if (auto ConstantCost = dyn_cast(RefCost))
347 return ConstantCost->getValue()->getLimitedValue(
348 std::numeric_limits<int64_t>::max());
349
351 << "RefCost is not a constant! Setting to RefCost=InvalidCost "
352 "(invalid value).\n");
353
355}
356
357bool IndexedReference::tryDelinearizeFixedSize(
361 ArraySizes))
362 return false;
363
364
365 for (auto Idx : seq(1, Subscripts.size()))
366 Sizes.push_back(
367 SE.getConstant(Subscripts[Idx]->getType(), ArraySizes[Idx - 1]));
368
370 dbgs() << "Delinearized subscripts of fixed-size array\n"
372 << "\n";
373 });
374 return true;
375}
376
377bool IndexedReference::delinearize(const LoopInfo &LI) {
378 assert(Subscripts.empty() && "Subscripts should be empty");
379 assert(Sizes.empty() && "Sizes should be empty");
380 assert(!IsValid && "Should be called once from the constructor");
381 LLVM_DEBUG(dbgs() << "Delinearizing: " << StoreOrLoadInst << "\n");
382
385
387 const SCEV *AccessFn =
389
390 BasePointer = dyn_cast(SE.getPointerBase(AccessFn));
391 if (BasePointer == nullptr) {
394 << "ERROR: failed to delinearize, can't identify base pointer\n");
395 return false;
396 }
397
398 bool IsFixedSize = false;
399
400 if (tryDelinearizeFixedSize(AccessFn, Subscripts)) {
401 IsFixedSize = true;
402
403 Sizes.push_back(ElemSize);
405 << "', AccessFn: " << *AccessFn << "\n");
406 }
407
408 AccessFn = SE.getMinusSCEV(AccessFn, BasePointer);
409
410
411 if (!IsFixedSize) {
413 << "', AccessFn: " << *AccessFn << "\n");
416 }
417
418 if (Subscripts.empty() || Sizes.empty() ||
419 Subscripts.size() != Sizes.size()) {
420
421
424 << "ERROR: failed to delinearize reference\n");
425 Subscripts.clear();
426 Sizes.clear();
427 return false;
428 }
429
430
431
432
433
434
435 const SCEVAddRecExpr *AccessFnAR = dyn_cast(AccessFn);
437
445 Sizes.push_back(ElemSize);
446 }
447
448 return all_of(Subscripts, [&](const SCEV *Subscript) {
449 return isSimpleAddRecurrence(*Subscript, *L);
450 });
451 }
452
453 return false;
454}
455
456bool IndexedReference::isLoopInvariant(const Loop &L) const {
458 assert(Addr != nullptr && "Expecting either a load or a store instruction");
460
462 return true;
463
464
465
466 bool allCoeffForLoopAreZero = all_of(Subscripts, [&](const SCEV *Subscript) {
467 return isCoeffForLoopZeroOrInvariant(*Subscript, L);
468 });
469
470 return allCoeffForLoopAreZero;
471}
472
473bool IndexedReference::isConsecutive(const Loop &L, const SCEV *&Stride,
474 unsigned CLS) const {
475
476
477 const SCEV *LastSubscript = Subscripts.back();
478 for (const SCEV *Subscript : Subscripts) {
479 if (Subscript == LastSubscript)
480 continue;
481 if (!isCoeffForLoopZeroOrInvariant(*Subscript, L))
482 return false;
483 }
484
485
486 const SCEV *Coeff = getLastCoefficient();
487 const SCEV *ElemSize = Sizes.back();
489
490
491
492
493
494
495
496
497
498
502
505}
506
507int IndexedReference::getSubscriptIndex(const Loop &L) const {
510 if (AR && AR->getLoop() == &L) {
511 return Idx;
512 }
513 }
514 return -1;
515}
516
517const SCEV *IndexedReference::getLastCoefficient() const {
519 auto *AR = cast(LastSubscript);
521}
522
523bool IndexedReference::isCoeffForLoopZeroOrInvariant(const SCEV &Subscript,
524 const Loop &L) const {
525 const SCEVAddRecExpr *AR = dyn_cast(&Subscript);
526 return (AR != nullptr) ? AR->getLoop() != &L
528}
529
530bool IndexedReference::isSimpleAddRecurrence(const SCEV &Subscript,
531 const Loop &L) const {
532 if (!isa(Subscript))
533 return false;
534
535 const SCEVAddRecExpr *AR = cast(&Subscript);
536 assert(AR->getLoop() && "AR should have a loop");
537
539 return false;
540
543
545 return false;
546
547 return true;
548}
549
555}
556
557
558
559
561 for (const auto &LC : CC.LoopCosts) {
562 const Loop *L = LC.first;
563 OS << "Loop '" << L->getName() << "' has cost = " << LC.second << "\n";
564 }
565 return OS;
566}
567
571 std::optional TRT)
573 TTI(TTI), AA(AA), DI(DI) {
574 assert(.empty() && "Expecting a non-empty loop vector.");
575
579 TripCounts.push_back({L, TripCount});
580 }
581
582 calculateCacheFootprint();
583}
584
585std::unique_ptr
589 LLVM_DEBUG(dbgs() << "Expecting the outermost loop in a loop nest\n");
590 return nullptr;
591 }
592
595
597 LLVM_DEBUG(dbgs() << "Cannot compute cache cost of loop nest with more "
598 "than one innermost loop\n");
599 return nullptr;
600 }
601
602 return std::make_unique(Loops, AR.LI, AR.SE, AR.TTI, AR.AA, DI, TRT);
603}
604
605void CacheCost::calculateCacheFootprint() {
606 LLVM_DEBUG(dbgs() << "POPULATING REFERENCE GROUPS\n");
608 if (!populateReferenceGroups(RefGroups))
609 return;
610
611 LLVM_DEBUG(dbgs() << "COMPUTING LOOP CACHE COSTS\n");
612 for (const Loop *L : Loops) {
614 LoopCosts,
615 [L](const LoopCacheCostTy &LCC) { return LCC.first == L; }) &&
616 "Should not add duplicate element");
617 CacheCostTy LoopCost = computeLoopCacheCost(*L, RefGroups);
618 LoopCosts.push_back(std::make_pair(L, LoopCost));
619 }
620
621 sortLoopCosts();
622 RefGroups.clear();
623}
624
625bool CacheCost::populateReferenceGroups(ReferenceGroupsTy &RefGroups) const {
626 assert(RefGroups.empty() && "Reference groups should be empty");
627
630 assert(InnerMostLoop != nullptr && "Expecting a valid innermost loop");
631
635 continue;
636
637 std::unique_ptr R(new IndexedReference(I, LI, SE));
638 if (->isValid())
639 continue;
640
641 bool Added = false;
645 dbgs() << "References:\n";
647 dbgs().indent(2) << Representative << "\n";
648 });
649
650
651
652
653
654
655
656
657
658
659
660
661
662 std::optional HasTemporalReuse =
663 R->hasTemporalReuse(Representative, *TRT, *InnerMostLoop, DI, AA);
664 std::optional HasSpacialReuse =
665 R->hasSpacialReuse(Representative, CLS, AA);
666
667 if ((HasTemporalReuse && *HasTemporalReuse) ||
668 (HasSpacialReuse && *HasSpacialReuse)) {
669 RefGroup.push_back(std::move(R));
671 break;
672 }
673 }
674
675 if (!Added) {
678 RefGroups.push_back(std::move(RG));
679 }
680 }
681 }
682
683 if (RefGroups.empty())
684 return false;
685
687 dbgs() << "\nIDENTIFIED REFERENCE GROUPS:\n";
688 int n = 1;
690 dbgs().indent(2) << "RefGroup " << n << ":\n";
691 for (const auto &IR : RG)
693 n++;
694 }
695 dbgs() << "\n";
696 });
697
698 return true;
699}
700
702CacheCost::computeLoopCacheCost(const Loop &L,
704 if (.isLoopSimplifyForm())
706
708 << "' as innermost loop.\n");
709
710
712 for (const auto &TC : TripCounts) {
713 if (TC.first == &L)
714 continue;
715 TripCountsProduct *= TC.second;
716 }
717
720 CacheCostTy RefGroupCost = computeRefGroupCacheCost(RG, L);
721 LoopCost += RefGroupCost * TripCountsProduct;
722 }
723
725 << "' has cost=" << LoopCost << "\n");
726
727 return LoopCost;
728}
729
731 const Loop &L) const {
732 assert(!RG.empty() && "Reference group should have at least one member.");
733
736}
737
738
739
740
744 Function *F = L.getHeader()->getParent();
746
748 OS << *CC;
749
751}
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