1*dd3b6498SWhitney Tsang //===- LoopCacheAnalysis.cpp - Loop Cache Analysis -------------------------==//
2*dd3b6498SWhitney Tsang //
3*dd3b6498SWhitney Tsang //                     The LLVM Compiler Infrastructure
4*dd3b6498SWhitney Tsang //
5*dd3b6498SWhitney Tsang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6*dd3b6498SWhitney Tsang // See https://llvm.org/LICENSE.txt for license information.
7*dd3b6498SWhitney Tsang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8*dd3b6498SWhitney Tsang //
9*dd3b6498SWhitney Tsang //===----------------------------------------------------------------------===//
10*dd3b6498SWhitney Tsang ///
11*dd3b6498SWhitney Tsang /// \file
12*dd3b6498SWhitney Tsang /// This file defines the implementation for the loop cache analysis.
13*dd3b6498SWhitney Tsang /// The implementation is largely based on the following paper:
14*dd3b6498SWhitney Tsang ///
15*dd3b6498SWhitney Tsang ///       Compiler Optimizations for Improving Data Locality
16*dd3b6498SWhitney Tsang ///       By: Steve Carr, Katherine S. McKinley, Chau-Wen Tseng
17*dd3b6498SWhitney Tsang ///       http://www.cs.utexas.edu/users/mckinley/papers/asplos-1994.pdf
18*dd3b6498SWhitney Tsang ///
19*dd3b6498SWhitney Tsang /// The general approach taken to estimate the number of cache lines used by the
20*dd3b6498SWhitney Tsang /// memory references in an inner loop is:
21*dd3b6498SWhitney Tsang ///    1. Partition memory references that exhibit temporal or spacial reuse
22*dd3b6498SWhitney Tsang ///       into reference groups.
23*dd3b6498SWhitney Tsang ///    2. For each loop L in the a loop nest LN:
24*dd3b6498SWhitney Tsang ///       a. Compute the cost of the reference group
25*dd3b6498SWhitney Tsang ///       b. Compute the loop cost by summing up the reference groups costs
26*dd3b6498SWhitney Tsang //===----------------------------------------------------------------------===//
27*dd3b6498SWhitney Tsang 
28*dd3b6498SWhitney Tsang #include "llvm/Analysis/LoopCacheAnalysis.h"
29*dd3b6498SWhitney Tsang #include "llvm/ADT/BreadthFirstIterator.h"
30*dd3b6498SWhitney Tsang #include "llvm/ADT/Sequence.h"
31*dd3b6498SWhitney Tsang #include "llvm/ADT/SmallVector.h"
32*dd3b6498SWhitney Tsang #include "llvm/Support/Debug.h"
33*dd3b6498SWhitney Tsang 
34*dd3b6498SWhitney Tsang using namespace llvm;
35*dd3b6498SWhitney Tsang 
36*dd3b6498SWhitney Tsang #define DEBUG_TYPE "loop-cache-cost"
37*dd3b6498SWhitney Tsang 
38*dd3b6498SWhitney Tsang static cl::opt<unsigned> DefaultTripCount(
39*dd3b6498SWhitney Tsang     "default-trip-count", cl::init(100), cl::Hidden,
40*dd3b6498SWhitney Tsang     cl::desc("Use this to specify the default trip count of a loop"));
41*dd3b6498SWhitney Tsang 
42*dd3b6498SWhitney Tsang // In this analysis two array references are considered to exhibit temporal
43*dd3b6498SWhitney Tsang // reuse if they access either the same memory location, or a memory location
44*dd3b6498SWhitney Tsang // with distance smaller than a configurable threshold.
45*dd3b6498SWhitney Tsang static cl::opt<unsigned> TemporalReuseThreshold(
46*dd3b6498SWhitney Tsang     "temporal-reuse-threshold", cl::init(2), cl::Hidden,
47*dd3b6498SWhitney Tsang     cl::desc("Use this to specify the max. distance between array elements "
48*dd3b6498SWhitney Tsang              "accessed in a loop so that the elements are classified to have "
49*dd3b6498SWhitney Tsang              "temporal reuse"));
50*dd3b6498SWhitney Tsang 
51*dd3b6498SWhitney Tsang /// Retrieve the innermost loop in the given loop nest \p Loops. It returns a
52*dd3b6498SWhitney Tsang /// nullptr if any loops in the loop vector supplied has more than one sibling.
53*dd3b6498SWhitney Tsang /// The loop vector is expected to contain loops collected in breadth-first
54*dd3b6498SWhitney Tsang /// order.
55*dd3b6498SWhitney Tsang static Loop *getInnerMostLoop(const LoopVectorTy &Loops) {
56*dd3b6498SWhitney Tsang   assert(!Loops.empty() && "Expecting a non-empy loop vector");
57*dd3b6498SWhitney Tsang 
58*dd3b6498SWhitney Tsang   Loop *LastLoop = Loops.back();
59*dd3b6498SWhitney Tsang   Loop *ParentLoop = LastLoop->getParentLoop();
60*dd3b6498SWhitney Tsang 
61*dd3b6498SWhitney Tsang   if (ParentLoop == nullptr) {
62*dd3b6498SWhitney Tsang     assert(Loops.size() == 1 && "Expecting a single loop");
63*dd3b6498SWhitney Tsang     return LastLoop;
64*dd3b6498SWhitney Tsang   }
65*dd3b6498SWhitney Tsang 
66*dd3b6498SWhitney Tsang   return (std::is_sorted(Loops.begin(), Loops.end(),
67*dd3b6498SWhitney Tsang                          [](const Loop *L1, const Loop *L2) {
68*dd3b6498SWhitney Tsang                            return L1->getLoopDepth() < L2->getLoopDepth();
69*dd3b6498SWhitney Tsang                          }))
70*dd3b6498SWhitney Tsang              ? LastLoop
71*dd3b6498SWhitney Tsang              : nullptr;
72*dd3b6498SWhitney Tsang }
73*dd3b6498SWhitney Tsang 
74*dd3b6498SWhitney Tsang static bool isOneDimensionalArray(const SCEV &AccessFn, const SCEV &ElemSize,
75*dd3b6498SWhitney Tsang                                   const Loop &L, ScalarEvolution &SE) {
76*dd3b6498SWhitney Tsang   const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(&AccessFn);
77*dd3b6498SWhitney Tsang   if (!AR || !AR->isAffine())
78*dd3b6498SWhitney Tsang     return false;
79*dd3b6498SWhitney Tsang 
80*dd3b6498SWhitney Tsang   assert(AR->getLoop() && "AR should have a loop");
81*dd3b6498SWhitney Tsang 
82*dd3b6498SWhitney Tsang   // Check that start and increment are not add recurrences.
83*dd3b6498SWhitney Tsang   const SCEV *Start = AR->getStart();
84*dd3b6498SWhitney Tsang   const SCEV *Step = AR->getStepRecurrence(SE);
85*dd3b6498SWhitney Tsang   if (isa<SCEVAddRecExpr>(Start) || isa<SCEVAddRecExpr>(Step))
86*dd3b6498SWhitney Tsang     return false;
87*dd3b6498SWhitney Tsang 
88*dd3b6498SWhitney Tsang   // Check that start and increment are both invariant in the loop.
89*dd3b6498SWhitney Tsang   if (!SE.isLoopInvariant(Start, &L) || !SE.isLoopInvariant(Step, &L))
90*dd3b6498SWhitney Tsang     return false;
91*dd3b6498SWhitney Tsang 
92*dd3b6498SWhitney Tsang   return AR->getStepRecurrence(SE) == &ElemSize;
93*dd3b6498SWhitney Tsang }
94*dd3b6498SWhitney Tsang 
95*dd3b6498SWhitney Tsang /// Compute the trip count for the given loop \p L. Return the SCEV expression
96*dd3b6498SWhitney Tsang /// for the trip count or nullptr if it cannot be computed.
97*dd3b6498SWhitney Tsang static const SCEV *computeTripCount(const Loop &L, ScalarEvolution &SE) {
98*dd3b6498SWhitney Tsang   const SCEV *BackedgeTakenCount = SE.getBackedgeTakenCount(&L);
99*dd3b6498SWhitney Tsang   if (isa<SCEVCouldNotCompute>(BackedgeTakenCount) ||
100*dd3b6498SWhitney Tsang       !isa<SCEVConstant>(BackedgeTakenCount))
101*dd3b6498SWhitney Tsang     return nullptr;
102*dd3b6498SWhitney Tsang 
103*dd3b6498SWhitney Tsang   return SE.getAddExpr(BackedgeTakenCount,
104*dd3b6498SWhitney Tsang                        SE.getOne(BackedgeTakenCount->getType()));
105*dd3b6498SWhitney Tsang }
106*dd3b6498SWhitney Tsang 
107*dd3b6498SWhitney Tsang //===----------------------------------------------------------------------===//
108*dd3b6498SWhitney Tsang // IndexedReference implementation
109*dd3b6498SWhitney Tsang //
110*dd3b6498SWhitney Tsang raw_ostream &llvm::operator<<(raw_ostream &OS, const IndexedReference &R) {
111*dd3b6498SWhitney Tsang   if (!R.IsValid) {
112*dd3b6498SWhitney Tsang     OS << R.StoreOrLoadInst;
113*dd3b6498SWhitney Tsang     OS << ", IsValid=false.";
114*dd3b6498SWhitney Tsang     return OS;
115*dd3b6498SWhitney Tsang   }
116*dd3b6498SWhitney Tsang 
117*dd3b6498SWhitney Tsang   OS << *R.BasePointer;
118*dd3b6498SWhitney Tsang   for (const SCEV *Subscript : R.Subscripts)
119*dd3b6498SWhitney Tsang     OS << "[" << *Subscript << "]";
120*dd3b6498SWhitney Tsang 
121*dd3b6498SWhitney Tsang   OS << ", Sizes: ";
122*dd3b6498SWhitney Tsang   for (const SCEV *Size : R.Sizes)
123*dd3b6498SWhitney Tsang     OS << "[" << *Size << "]";
124*dd3b6498SWhitney Tsang 
125*dd3b6498SWhitney Tsang   return OS;
126*dd3b6498SWhitney Tsang }
127*dd3b6498SWhitney Tsang 
128*dd3b6498SWhitney Tsang IndexedReference::IndexedReference(Instruction &StoreOrLoadInst,
129*dd3b6498SWhitney Tsang                                    const LoopInfo &LI, ScalarEvolution &SE)
130*dd3b6498SWhitney Tsang     : StoreOrLoadInst(StoreOrLoadInst), SE(SE) {
131*dd3b6498SWhitney Tsang   assert((isa<StoreInst>(StoreOrLoadInst) || isa<LoadInst>(StoreOrLoadInst)) &&
132*dd3b6498SWhitney Tsang          "Expecting a load or store instruction");
133*dd3b6498SWhitney Tsang 
134*dd3b6498SWhitney Tsang   IsValid = delinearize(LI);
135*dd3b6498SWhitney Tsang   if (IsValid)
136*dd3b6498SWhitney Tsang     LLVM_DEBUG(dbgs().indent(2) << "Succesfully delinearized: " << *this
137*dd3b6498SWhitney Tsang                                 << "\n");
138*dd3b6498SWhitney Tsang }
139*dd3b6498SWhitney Tsang 
140*dd3b6498SWhitney Tsang Optional<bool> IndexedReference::hasSpacialReuse(const IndexedReference &Other,
141*dd3b6498SWhitney Tsang                                                  unsigned CLS,
142*dd3b6498SWhitney Tsang                                                  AliasAnalysis &AA) const {
143*dd3b6498SWhitney Tsang   assert(IsValid && "Expecting a valid reference");
144*dd3b6498SWhitney Tsang 
145*dd3b6498SWhitney Tsang   if (BasePointer != Other.getBasePointer() && !isAliased(Other, AA)) {
146*dd3b6498SWhitney Tsang     LLVM_DEBUG(dbgs().indent(2)
147*dd3b6498SWhitney Tsang                << "No spacial reuse: different base pointers\n");
148*dd3b6498SWhitney Tsang     return false;
149*dd3b6498SWhitney Tsang   }
150*dd3b6498SWhitney Tsang 
151*dd3b6498SWhitney Tsang   unsigned NumSubscripts = getNumSubscripts();
152*dd3b6498SWhitney Tsang   if (NumSubscripts != Other.getNumSubscripts()) {
153*dd3b6498SWhitney Tsang     LLVM_DEBUG(dbgs().indent(2)
154*dd3b6498SWhitney Tsang                << "No spacial reuse: different number of subscripts\n");
155*dd3b6498SWhitney Tsang     return false;
156*dd3b6498SWhitney Tsang   }
157*dd3b6498SWhitney Tsang 
158*dd3b6498SWhitney Tsang   // all subscripts must be equal, except the leftmost one (the last one).
159*dd3b6498SWhitney Tsang   for (auto SubNum : seq<unsigned>(0, NumSubscripts - 1)) {
160*dd3b6498SWhitney Tsang     if (getSubscript(SubNum) != Other.getSubscript(SubNum)) {
161*dd3b6498SWhitney Tsang       LLVM_DEBUG(dbgs().indent(2) << "No spacial reuse, different subscripts: "
162*dd3b6498SWhitney Tsang                                   << "\n\t" << *getSubscript(SubNum) << "\n\t"
163*dd3b6498SWhitney Tsang                                   << *Other.getSubscript(SubNum) << "\n");
164*dd3b6498SWhitney Tsang       return false;
165*dd3b6498SWhitney Tsang     }
166*dd3b6498SWhitney Tsang   }
167*dd3b6498SWhitney Tsang 
168*dd3b6498SWhitney Tsang   // the difference between the last subscripts must be less than the cache line
169*dd3b6498SWhitney Tsang   // size.
170*dd3b6498SWhitney Tsang   const SCEV *LastSubscript = getLastSubscript();
171*dd3b6498SWhitney Tsang   const SCEV *OtherLastSubscript = Other.getLastSubscript();
172*dd3b6498SWhitney Tsang   const SCEVConstant *Diff = dyn_cast<SCEVConstant>(
173*dd3b6498SWhitney Tsang       SE.getMinusSCEV(LastSubscript, OtherLastSubscript));
174*dd3b6498SWhitney Tsang 
175*dd3b6498SWhitney Tsang   if (Diff == nullptr) {
176*dd3b6498SWhitney Tsang     LLVM_DEBUG(dbgs().indent(2)
177*dd3b6498SWhitney Tsang                << "No spacial reuse, difference between subscript:\n\t"
178*dd3b6498SWhitney Tsang                << *LastSubscript << "\n\t" << OtherLastSubscript
179*dd3b6498SWhitney Tsang                << "\nis not constant.\n");
180*dd3b6498SWhitney Tsang     return None;
181*dd3b6498SWhitney Tsang   }
182*dd3b6498SWhitney Tsang 
183*dd3b6498SWhitney Tsang   bool InSameCacheLine = (Diff->getValue()->getSExtValue() < CLS);
184*dd3b6498SWhitney Tsang 
185*dd3b6498SWhitney Tsang   LLVM_DEBUG({
186*dd3b6498SWhitney Tsang     if (InSameCacheLine)
187*dd3b6498SWhitney Tsang       dbgs().indent(2) << "Found spacial reuse.\n";
188*dd3b6498SWhitney Tsang     else
189*dd3b6498SWhitney Tsang       dbgs().indent(2) << "No spacial reuse.\n";
190*dd3b6498SWhitney Tsang   });
191*dd3b6498SWhitney Tsang 
192*dd3b6498SWhitney Tsang   return InSameCacheLine;
193*dd3b6498SWhitney Tsang }
194*dd3b6498SWhitney Tsang 
195*dd3b6498SWhitney Tsang Optional<bool> IndexedReference::hasTemporalReuse(const IndexedReference &Other,
196*dd3b6498SWhitney Tsang                                                   unsigned MaxDistance,
197*dd3b6498SWhitney Tsang                                                   const Loop &L,
198*dd3b6498SWhitney Tsang                                                   DependenceInfo &DI,
199*dd3b6498SWhitney Tsang                                                   AliasAnalysis &AA) const {
200*dd3b6498SWhitney Tsang   assert(IsValid && "Expecting a valid reference");
201*dd3b6498SWhitney Tsang 
202*dd3b6498SWhitney Tsang   if (BasePointer != Other.getBasePointer() && !isAliased(Other, AA)) {
203*dd3b6498SWhitney Tsang     LLVM_DEBUG(dbgs().indent(2)
204*dd3b6498SWhitney Tsang                << "No temporal reuse: different base pointer\n");
205*dd3b6498SWhitney Tsang     return false;
206*dd3b6498SWhitney Tsang   }
207*dd3b6498SWhitney Tsang 
208*dd3b6498SWhitney Tsang   std::unique_ptr<Dependence> D =
209*dd3b6498SWhitney Tsang       DI.depends(&StoreOrLoadInst, &Other.StoreOrLoadInst, true);
210*dd3b6498SWhitney Tsang 
211*dd3b6498SWhitney Tsang   if (D == nullptr) {
212*dd3b6498SWhitney Tsang     LLVM_DEBUG(dbgs().indent(2) << "No temporal reuse: no dependence\n");
213*dd3b6498SWhitney Tsang     return false;
214*dd3b6498SWhitney Tsang   }
215*dd3b6498SWhitney Tsang 
216*dd3b6498SWhitney Tsang   if (D->isLoopIndependent()) {
217*dd3b6498SWhitney Tsang     LLVM_DEBUG(dbgs().indent(2) << "Found temporal reuse\n");
218*dd3b6498SWhitney Tsang     return true;
219*dd3b6498SWhitney Tsang   }
220*dd3b6498SWhitney Tsang 
221*dd3b6498SWhitney Tsang   // Check the dependence distance at every loop level. There is temporal reuse
222*dd3b6498SWhitney Tsang   // if the distance at the given loop's depth is small (|d| <= MaxDistance) and
223*dd3b6498SWhitney Tsang   // it is zero at every other loop level.
224*dd3b6498SWhitney Tsang   int LoopDepth = L.getLoopDepth();
225*dd3b6498SWhitney Tsang   int Levels = D->getLevels();
226*dd3b6498SWhitney Tsang   for (int Level = 1; Level <= Levels; ++Level) {
227*dd3b6498SWhitney Tsang     const SCEV *Distance = D->getDistance(Level);
228*dd3b6498SWhitney Tsang     const SCEVConstant *SCEVConst = dyn_cast_or_null<SCEVConstant>(Distance);
229*dd3b6498SWhitney Tsang 
230*dd3b6498SWhitney Tsang     if (SCEVConst == nullptr) {
231*dd3b6498SWhitney Tsang       LLVM_DEBUG(dbgs().indent(2) << "No temporal reuse: distance unknown\n");
232*dd3b6498SWhitney Tsang       return None;
233*dd3b6498SWhitney Tsang     }
234*dd3b6498SWhitney Tsang 
235*dd3b6498SWhitney Tsang     const ConstantInt &CI = *SCEVConst->getValue();
236*dd3b6498SWhitney Tsang     if (Level != LoopDepth && !CI.isZero()) {
237*dd3b6498SWhitney Tsang       LLVM_DEBUG(dbgs().indent(2)
238*dd3b6498SWhitney Tsang                  << "No temporal reuse: distance is not zero at depth=" << Level
239*dd3b6498SWhitney Tsang                  << "\n");
240*dd3b6498SWhitney Tsang       return false;
241*dd3b6498SWhitney Tsang     } else if (Level == LoopDepth && CI.getSExtValue() > MaxDistance) {
242*dd3b6498SWhitney Tsang       LLVM_DEBUG(
243*dd3b6498SWhitney Tsang           dbgs().indent(2)
244*dd3b6498SWhitney Tsang           << "No temporal reuse: distance is greater than MaxDistance at depth="
245*dd3b6498SWhitney Tsang           << Level << "\n");
246*dd3b6498SWhitney Tsang       return false;
247*dd3b6498SWhitney Tsang     }
248*dd3b6498SWhitney Tsang   }
249*dd3b6498SWhitney Tsang 
250*dd3b6498SWhitney Tsang   LLVM_DEBUG(dbgs().indent(2) << "Found temporal reuse\n");
251*dd3b6498SWhitney Tsang   return true;
252*dd3b6498SWhitney Tsang }
253*dd3b6498SWhitney Tsang 
254*dd3b6498SWhitney Tsang CacheCostTy IndexedReference::computeRefCost(const Loop &L,
255*dd3b6498SWhitney Tsang                                              unsigned CLS) const {
256*dd3b6498SWhitney Tsang   assert(IsValid && "Expecting a valid reference");
257*dd3b6498SWhitney Tsang   LLVM_DEBUG({
258*dd3b6498SWhitney Tsang     dbgs().indent(2) << "Computing cache cost for:\n";
259*dd3b6498SWhitney Tsang     dbgs().indent(4) << *this << "\n";
260*dd3b6498SWhitney Tsang   });
261*dd3b6498SWhitney Tsang 
262*dd3b6498SWhitney Tsang   // If the indexed reference is loop invariant the cost is one.
263*dd3b6498SWhitney Tsang   if (isLoopInvariant(L)) {
264*dd3b6498SWhitney Tsang     LLVM_DEBUG(dbgs().indent(4) << "Reference is loop invariant: RefCost=1\n");
265*dd3b6498SWhitney Tsang     return 1;
266*dd3b6498SWhitney Tsang   }
267*dd3b6498SWhitney Tsang 
268*dd3b6498SWhitney Tsang   const SCEV *TripCount = computeTripCount(L, SE);
269*dd3b6498SWhitney Tsang   if (!TripCount) {
270*dd3b6498SWhitney Tsang     LLVM_DEBUG(dbgs() << "Trip count of loop " << L.getName()
271*dd3b6498SWhitney Tsang                       << " could not be computed, using DefaultTripCount\n");
272*dd3b6498SWhitney Tsang     const SCEV *ElemSize = Sizes.back();
273*dd3b6498SWhitney Tsang     TripCount = SE.getConstant(ElemSize->getType(), DefaultTripCount);
274*dd3b6498SWhitney Tsang   }
275*dd3b6498SWhitney Tsang   LLVM_DEBUG(dbgs() << "TripCount=" << *TripCount << "\n");
276*dd3b6498SWhitney Tsang 
277*dd3b6498SWhitney Tsang   // If the indexed reference is 'consecutive' the cost is
278*dd3b6498SWhitney Tsang   // (TripCount*Stride)/CLS, otherwise the cost is TripCount.
279*dd3b6498SWhitney Tsang   const SCEV *RefCost = TripCount;
280*dd3b6498SWhitney Tsang 
281*dd3b6498SWhitney Tsang   if (isConsecutive(L, CLS)) {
282*dd3b6498SWhitney Tsang     const SCEV *Coeff = getLastCoefficient();
283*dd3b6498SWhitney Tsang     const SCEV *ElemSize = Sizes.back();
284*dd3b6498SWhitney Tsang     const SCEV *Stride = SE.getMulExpr(Coeff, ElemSize);
285*dd3b6498SWhitney Tsang     const SCEV *CacheLineSize = SE.getConstant(Stride->getType(), CLS);
286*dd3b6498SWhitney Tsang     const SCEV *Numerator = SE.getMulExpr(Stride, TripCount);
287*dd3b6498SWhitney Tsang     RefCost = SE.getUDivExpr(Numerator, CacheLineSize);
288*dd3b6498SWhitney Tsang     LLVM_DEBUG(dbgs().indent(4)
289*dd3b6498SWhitney Tsang                << "Access is consecutive: RefCost=(TripCount*Stride)/CLS="
290*dd3b6498SWhitney Tsang                << *RefCost << "\n");
291*dd3b6498SWhitney Tsang   } else
292*dd3b6498SWhitney Tsang     LLVM_DEBUG(dbgs().indent(4)
293*dd3b6498SWhitney Tsang                << "Access is not consecutive: RefCost=TripCount=" << *RefCost
294*dd3b6498SWhitney Tsang                << "\n");
295*dd3b6498SWhitney Tsang 
296*dd3b6498SWhitney Tsang   // Attempt to fold RefCost into a constant.
297*dd3b6498SWhitney Tsang   if (auto ConstantCost = dyn_cast<SCEVConstant>(RefCost))
298*dd3b6498SWhitney Tsang     return ConstantCost->getValue()->getSExtValue();
299*dd3b6498SWhitney Tsang 
300*dd3b6498SWhitney Tsang   LLVM_DEBUG(dbgs().indent(4)
301*dd3b6498SWhitney Tsang              << "RefCost is not a constant! Setting to RefCost=InvalidCost "
302*dd3b6498SWhitney Tsang                 "(invalid value).\n");
303*dd3b6498SWhitney Tsang 
304*dd3b6498SWhitney Tsang   return CacheCost::InvalidCost;
305*dd3b6498SWhitney Tsang }
306*dd3b6498SWhitney Tsang 
307*dd3b6498SWhitney Tsang bool IndexedReference::delinearize(const LoopInfo &LI) {
308*dd3b6498SWhitney Tsang   assert(Subscripts.empty() && "Subscripts should be empty");
309*dd3b6498SWhitney Tsang   assert(Sizes.empty() && "Sizes should be empty");
310*dd3b6498SWhitney Tsang   assert(!IsValid && "Should be called once from the constructor");
311*dd3b6498SWhitney Tsang   LLVM_DEBUG(dbgs() << "Delinearizing: " << StoreOrLoadInst << "\n");
312*dd3b6498SWhitney Tsang 
313*dd3b6498SWhitney Tsang   const SCEV *ElemSize = SE.getElementSize(&StoreOrLoadInst);
314*dd3b6498SWhitney Tsang   const BasicBlock *BB = StoreOrLoadInst.getParent();
315*dd3b6498SWhitney Tsang 
316*dd3b6498SWhitney Tsang   for (Loop *L = LI.getLoopFor(BB); L != nullptr; L = L->getParentLoop()) {
317*dd3b6498SWhitney Tsang     const SCEV *AccessFn =
318*dd3b6498SWhitney Tsang         SE.getSCEVAtScope(getPointerOperand(&StoreOrLoadInst), L);
319*dd3b6498SWhitney Tsang 
320*dd3b6498SWhitney Tsang     BasePointer = dyn_cast<SCEVUnknown>(SE.getPointerBase(AccessFn));
321*dd3b6498SWhitney Tsang     if (BasePointer == nullptr) {
322*dd3b6498SWhitney Tsang       LLVM_DEBUG(
323*dd3b6498SWhitney Tsang           dbgs().indent(2)
324*dd3b6498SWhitney Tsang           << "ERROR: failed to delinearize, can't identify base pointer\n");
325*dd3b6498SWhitney Tsang       return false;
326*dd3b6498SWhitney Tsang     }
327*dd3b6498SWhitney Tsang 
328*dd3b6498SWhitney Tsang     AccessFn = SE.getMinusSCEV(AccessFn, BasePointer);
329*dd3b6498SWhitney Tsang 
330*dd3b6498SWhitney Tsang     LLVM_DEBUG(dbgs().indent(2) << "In Loop '" << L->getName()
331*dd3b6498SWhitney Tsang                                 << "', AccessFn: " << *AccessFn << "\n");
332*dd3b6498SWhitney Tsang 
333*dd3b6498SWhitney Tsang     SE.delinearize(AccessFn, Subscripts, Sizes,
334*dd3b6498SWhitney Tsang                    SE.getElementSize(&StoreOrLoadInst));
335*dd3b6498SWhitney Tsang 
336*dd3b6498SWhitney Tsang     if (Subscripts.empty() || Sizes.empty() ||
337*dd3b6498SWhitney Tsang         Subscripts.size() != Sizes.size()) {
338*dd3b6498SWhitney Tsang       // Attempt to determine whether we have a single dimensional array access.
339*dd3b6498SWhitney Tsang       // before giving up.
340*dd3b6498SWhitney Tsang       if (!isOneDimensionalArray(*AccessFn, *ElemSize, *L, SE)) {
341*dd3b6498SWhitney Tsang         LLVM_DEBUG(dbgs().indent(2)
342*dd3b6498SWhitney Tsang                    << "ERROR: failed to delinearize reference\n");
343*dd3b6498SWhitney Tsang         Subscripts.clear();
344*dd3b6498SWhitney Tsang         Sizes.clear();
345*dd3b6498SWhitney Tsang         break;
346*dd3b6498SWhitney Tsang       }
347*dd3b6498SWhitney Tsang 
348*dd3b6498SWhitney Tsang       const SCEV *Div = SE.getUDivExactExpr(AccessFn, ElemSize);
349*dd3b6498SWhitney Tsang       Subscripts.push_back(Div);
350*dd3b6498SWhitney Tsang       Sizes.push_back(ElemSize);
351*dd3b6498SWhitney Tsang     }
352*dd3b6498SWhitney Tsang 
353*dd3b6498SWhitney Tsang     return all_of(Subscripts, [&](const SCEV *Subscript) {
354*dd3b6498SWhitney Tsang       return isSimpleAddRecurrence(*Subscript, *L);
355*dd3b6498SWhitney Tsang     });
356*dd3b6498SWhitney Tsang   }
357*dd3b6498SWhitney Tsang 
358*dd3b6498SWhitney Tsang   return false;
359*dd3b6498SWhitney Tsang }
360*dd3b6498SWhitney Tsang 
361*dd3b6498SWhitney Tsang bool IndexedReference::isLoopInvariant(const Loop &L) const {
362*dd3b6498SWhitney Tsang   Value *Addr = getPointerOperand(&StoreOrLoadInst);
363*dd3b6498SWhitney Tsang   assert(Addr != nullptr && "Expecting either a load or a store instruction");
364*dd3b6498SWhitney Tsang   assert(SE.isSCEVable(Addr->getType()) && "Addr should be SCEVable");
365*dd3b6498SWhitney Tsang 
366*dd3b6498SWhitney Tsang   if (SE.isLoopInvariant(SE.getSCEV(Addr), &L))
367*dd3b6498SWhitney Tsang     return true;
368*dd3b6498SWhitney Tsang 
369*dd3b6498SWhitney Tsang   // The indexed reference is loop invariant if none of the coefficients use
370*dd3b6498SWhitney Tsang   // the loop induction variable.
371*dd3b6498SWhitney Tsang   bool allCoeffForLoopAreZero = all_of(Subscripts, [&](const SCEV *Subscript) {
372*dd3b6498SWhitney Tsang     return isCoeffForLoopZeroOrInvariant(*Subscript, L);
373*dd3b6498SWhitney Tsang   });
374*dd3b6498SWhitney Tsang 
375*dd3b6498SWhitney Tsang   return allCoeffForLoopAreZero;
376*dd3b6498SWhitney Tsang }
377*dd3b6498SWhitney Tsang 
378*dd3b6498SWhitney Tsang bool IndexedReference::isConsecutive(const Loop &L, unsigned CLS) const {
379*dd3b6498SWhitney Tsang   // The indexed reference is 'consecutive' if the only coefficient that uses
380*dd3b6498SWhitney Tsang   // the loop induction variable is the last one...
381*dd3b6498SWhitney Tsang   const SCEV *LastSubscript = Subscripts.back();
382*dd3b6498SWhitney Tsang   for (const SCEV *Subscript : Subscripts) {
383*dd3b6498SWhitney Tsang     if (Subscript == LastSubscript)
384*dd3b6498SWhitney Tsang       continue;
385*dd3b6498SWhitney Tsang     if (!isCoeffForLoopZeroOrInvariant(*Subscript, L))
386*dd3b6498SWhitney Tsang       return false;
387*dd3b6498SWhitney Tsang   }
388*dd3b6498SWhitney Tsang 
389*dd3b6498SWhitney Tsang   // ...and the access stride is less than the cache line size.
390*dd3b6498SWhitney Tsang   const SCEV *Coeff = getLastCoefficient();
391*dd3b6498SWhitney Tsang   const SCEV *ElemSize = Sizes.back();
392*dd3b6498SWhitney Tsang   const SCEV *Stride = SE.getMulExpr(Coeff, ElemSize);
393*dd3b6498SWhitney Tsang   const SCEV *CacheLineSize = SE.getConstant(Stride->getType(), CLS);
394*dd3b6498SWhitney Tsang 
395*dd3b6498SWhitney Tsang   return SE.isKnownPredicate(ICmpInst::ICMP_ULT, Stride, CacheLineSize);
396*dd3b6498SWhitney Tsang }
397*dd3b6498SWhitney Tsang 
398*dd3b6498SWhitney Tsang const SCEV *IndexedReference::getLastCoefficient() const {
399*dd3b6498SWhitney Tsang   const SCEV *LastSubscript = getLastSubscript();
400*dd3b6498SWhitney Tsang   assert(isa<SCEVAddRecExpr>(LastSubscript) &&
401*dd3b6498SWhitney Tsang          "Expecting a SCEV add recurrence expression");
402*dd3b6498SWhitney Tsang   const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(LastSubscript);
403*dd3b6498SWhitney Tsang   return AR->getStepRecurrence(SE);
404*dd3b6498SWhitney Tsang }
405*dd3b6498SWhitney Tsang 
406*dd3b6498SWhitney Tsang bool IndexedReference::isCoeffForLoopZeroOrInvariant(const SCEV &Subscript,
407*dd3b6498SWhitney Tsang                                                      const Loop &L) const {
408*dd3b6498SWhitney Tsang   const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(&Subscript);
409*dd3b6498SWhitney Tsang   return (AR != nullptr) ? AR->getLoop() != &L
410*dd3b6498SWhitney Tsang                          : SE.isLoopInvariant(&Subscript, &L);
411*dd3b6498SWhitney Tsang }
412*dd3b6498SWhitney Tsang 
413*dd3b6498SWhitney Tsang bool IndexedReference::isSimpleAddRecurrence(const SCEV &Subscript,
414*dd3b6498SWhitney Tsang                                              const Loop &L) const {
415*dd3b6498SWhitney Tsang   if (!isa<SCEVAddRecExpr>(Subscript))
416*dd3b6498SWhitney Tsang     return false;
417*dd3b6498SWhitney Tsang 
418*dd3b6498SWhitney Tsang   const SCEVAddRecExpr *AR = cast<SCEVAddRecExpr>(&Subscript);
419*dd3b6498SWhitney Tsang   assert(AR->getLoop() && "AR should have a loop");
420*dd3b6498SWhitney Tsang 
421*dd3b6498SWhitney Tsang   if (!AR->isAffine())
422*dd3b6498SWhitney Tsang     return false;
423*dd3b6498SWhitney Tsang 
424*dd3b6498SWhitney Tsang   const SCEV *Start = AR->getStart();
425*dd3b6498SWhitney Tsang   const SCEV *Step = AR->getStepRecurrence(SE);
426*dd3b6498SWhitney Tsang 
427*dd3b6498SWhitney Tsang   if (!SE.isLoopInvariant(Start, &L) || !SE.isLoopInvariant(Step, &L))
428*dd3b6498SWhitney Tsang     return false;
429*dd3b6498SWhitney Tsang 
430*dd3b6498SWhitney Tsang   return true;
431*dd3b6498SWhitney Tsang }
432*dd3b6498SWhitney Tsang 
433*dd3b6498SWhitney Tsang bool IndexedReference::isAliased(const IndexedReference &Other,
434*dd3b6498SWhitney Tsang                                  AliasAnalysis &AA) const {
435*dd3b6498SWhitney Tsang   const auto &Loc1 = MemoryLocation::get(&StoreOrLoadInst);
436*dd3b6498SWhitney Tsang   const auto &Loc2 = MemoryLocation::get(&Other.StoreOrLoadInst);
437*dd3b6498SWhitney Tsang   return AA.isMustAlias(Loc1, Loc2);
438*dd3b6498SWhitney Tsang }
439*dd3b6498SWhitney Tsang 
440*dd3b6498SWhitney Tsang //===----------------------------------------------------------------------===//
441*dd3b6498SWhitney Tsang // CacheCost implementation
442*dd3b6498SWhitney Tsang //
443*dd3b6498SWhitney Tsang raw_ostream &llvm::operator<<(raw_ostream &OS, const CacheCost &CC) {
444*dd3b6498SWhitney Tsang   for (const auto &LC : CC.LoopCosts) {
445*dd3b6498SWhitney Tsang     const Loop *L = LC.first;
446*dd3b6498SWhitney Tsang     OS << "Loop '" << L->getName() << "' has cost = " << LC.second << "\n";
447*dd3b6498SWhitney Tsang   }
448*dd3b6498SWhitney Tsang   return OS;
449*dd3b6498SWhitney Tsang }
450*dd3b6498SWhitney Tsang 
451*dd3b6498SWhitney Tsang CacheCost::CacheCost(const LoopVectorTy &Loops, const LoopInfo &LI,
452*dd3b6498SWhitney Tsang                      ScalarEvolution &SE, TargetTransformInfo &TTI,
453*dd3b6498SWhitney Tsang                      AliasAnalysis &AA, DependenceInfo &DI,
454*dd3b6498SWhitney Tsang                      Optional<unsigned> TRT)
455*dd3b6498SWhitney Tsang     : Loops(Loops), TripCounts(), LoopCosts(),
456*dd3b6498SWhitney Tsang       TRT(TRT == None ? Optional<unsigned>(TemporalReuseThreshold) : TRT),
457*dd3b6498SWhitney Tsang       LI(LI), SE(SE), TTI(TTI), AA(AA), DI(DI) {
458*dd3b6498SWhitney Tsang   assert(!Loops.empty() && "Expecting a non-empty loop vector.");
459*dd3b6498SWhitney Tsang 
460*dd3b6498SWhitney Tsang   for (const Loop *L : Loops) {
461*dd3b6498SWhitney Tsang     unsigned TripCount = SE.getSmallConstantTripCount(L);
462*dd3b6498SWhitney Tsang     TripCount = (TripCount == 0) ? DefaultTripCount : TripCount;
463*dd3b6498SWhitney Tsang     TripCounts.push_back({L, TripCount});
464*dd3b6498SWhitney Tsang   }
465*dd3b6498SWhitney Tsang 
466*dd3b6498SWhitney Tsang   calculateCacheFootprint();
467*dd3b6498SWhitney Tsang }
468*dd3b6498SWhitney Tsang 
469*dd3b6498SWhitney Tsang std::unique_ptr<CacheCost>
470*dd3b6498SWhitney Tsang CacheCost::getCacheCost(Loop &Root, LoopStandardAnalysisResults &AR,
471*dd3b6498SWhitney Tsang                         DependenceInfo &DI, Optional<unsigned> TRT) {
472*dd3b6498SWhitney Tsang   if (Root.getParentLoop()) {
473*dd3b6498SWhitney Tsang     LLVM_DEBUG(dbgs() << "Expecting the outermost loop in a loop nest\n");
474*dd3b6498SWhitney Tsang     return nullptr;
475*dd3b6498SWhitney Tsang   }
476*dd3b6498SWhitney Tsang 
477*dd3b6498SWhitney Tsang   LoopVectorTy Loops;
478*dd3b6498SWhitney Tsang   for (Loop *L : breadth_first(&Root))
479*dd3b6498SWhitney Tsang     Loops.push_back(L);
480*dd3b6498SWhitney Tsang 
481*dd3b6498SWhitney Tsang   if (!getInnerMostLoop(Loops)) {
482*dd3b6498SWhitney Tsang     LLVM_DEBUG(dbgs() << "Cannot compute cache cost of loop nest with more "
483*dd3b6498SWhitney Tsang                          "than one innermost loop\n");
484*dd3b6498SWhitney Tsang     return nullptr;
485*dd3b6498SWhitney Tsang   }
486*dd3b6498SWhitney Tsang 
487*dd3b6498SWhitney Tsang   return make_unique<CacheCost>(Loops, AR.LI, AR.SE, AR.TTI, AR.AA, DI, TRT);
488*dd3b6498SWhitney Tsang }
489*dd3b6498SWhitney Tsang 
490*dd3b6498SWhitney Tsang void CacheCost::calculateCacheFootprint() {
491*dd3b6498SWhitney Tsang   LLVM_DEBUG(dbgs() << "POPULATING REFERENCE GROUPS\n");
492*dd3b6498SWhitney Tsang   ReferenceGroupsTy RefGroups;
493*dd3b6498SWhitney Tsang   if (!populateReferenceGroups(RefGroups))
494*dd3b6498SWhitney Tsang     return;
495*dd3b6498SWhitney Tsang 
496*dd3b6498SWhitney Tsang   LLVM_DEBUG(dbgs() << "COMPUTING LOOP CACHE COSTS\n");
497*dd3b6498SWhitney Tsang   for (const Loop *L : Loops) {
498*dd3b6498SWhitney Tsang     assert((std::find_if(LoopCosts.begin(), LoopCosts.end(),
499*dd3b6498SWhitney Tsang                          [L](const LoopCacheCostTy &LCC) {
500*dd3b6498SWhitney Tsang                            return LCC.first == L;
501*dd3b6498SWhitney Tsang                          }) == LoopCosts.end()) &&
502*dd3b6498SWhitney Tsang            "Should not add duplicate element");
503*dd3b6498SWhitney Tsang     CacheCostTy LoopCost = computeLoopCacheCost(*L, RefGroups);
504*dd3b6498SWhitney Tsang     LoopCosts.push_back(std::make_pair(L, LoopCost));
505*dd3b6498SWhitney Tsang   }
506*dd3b6498SWhitney Tsang 
507*dd3b6498SWhitney Tsang   sortLoopCosts();
508*dd3b6498SWhitney Tsang   RefGroups.clear();
509*dd3b6498SWhitney Tsang }
510*dd3b6498SWhitney Tsang 
511*dd3b6498SWhitney Tsang bool CacheCost::populateReferenceGroups(ReferenceGroupsTy &RefGroups) const {
512*dd3b6498SWhitney Tsang   assert(RefGroups.empty() && "Reference groups should be empty");
513*dd3b6498SWhitney Tsang 
514*dd3b6498SWhitney Tsang   unsigned CLS = TTI.getCacheLineSize();
515*dd3b6498SWhitney Tsang   Loop *InnerMostLoop = getInnerMostLoop(Loops);
516*dd3b6498SWhitney Tsang   assert(InnerMostLoop != nullptr && "Expecting a valid innermost loop");
517*dd3b6498SWhitney Tsang 
518*dd3b6498SWhitney Tsang   for (BasicBlock *BB : InnerMostLoop->getBlocks()) {
519*dd3b6498SWhitney Tsang     for (Instruction &I : *BB) {
520*dd3b6498SWhitney Tsang       if (!isa<StoreInst>(I) && !isa<LoadInst>(I))
521*dd3b6498SWhitney Tsang         continue;
522*dd3b6498SWhitney Tsang 
523*dd3b6498SWhitney Tsang       std::unique_ptr<IndexedReference> R(new IndexedReference(I, LI, SE));
524*dd3b6498SWhitney Tsang       if (!R->isValid())
525*dd3b6498SWhitney Tsang         continue;
526*dd3b6498SWhitney Tsang 
527*dd3b6498SWhitney Tsang       bool Added = false;
528*dd3b6498SWhitney Tsang       for (ReferenceGroupTy &RefGroup : RefGroups) {
529*dd3b6498SWhitney Tsang         const IndexedReference &Representative = *RefGroup.front().get();
530*dd3b6498SWhitney Tsang         LLVM_DEBUG({
531*dd3b6498SWhitney Tsang           dbgs() << "References:\n";
532*dd3b6498SWhitney Tsang           dbgs().indent(2) << *R << "\n";
533*dd3b6498SWhitney Tsang           dbgs().indent(2) << Representative << "\n";
534*dd3b6498SWhitney Tsang         });
535*dd3b6498SWhitney Tsang 
536*dd3b6498SWhitney Tsang         Optional<bool> HasTemporalReuse =
537*dd3b6498SWhitney Tsang             R->hasTemporalReuse(Representative, *TRT, *InnerMostLoop, DI, AA);
538*dd3b6498SWhitney Tsang         Optional<bool> HasSpacialReuse =
539*dd3b6498SWhitney Tsang             R->hasSpacialReuse(Representative, CLS, AA);
540*dd3b6498SWhitney Tsang 
541*dd3b6498SWhitney Tsang         if ((HasTemporalReuse.hasValue() && *HasTemporalReuse) ||
542*dd3b6498SWhitney Tsang             (HasSpacialReuse.hasValue() && *HasSpacialReuse)) {
543*dd3b6498SWhitney Tsang           RefGroup.push_back(std::move(R));
544*dd3b6498SWhitney Tsang           Added = true;
545*dd3b6498SWhitney Tsang           break;
546*dd3b6498SWhitney Tsang         }
547*dd3b6498SWhitney Tsang       }
548*dd3b6498SWhitney Tsang 
549*dd3b6498SWhitney Tsang       if (!Added) {
550*dd3b6498SWhitney Tsang         ReferenceGroupTy RG;
551*dd3b6498SWhitney Tsang         RG.push_back(std::move(R));
552*dd3b6498SWhitney Tsang         RefGroups.push_back(std::move(RG));
553*dd3b6498SWhitney Tsang       }
554*dd3b6498SWhitney Tsang     }
555*dd3b6498SWhitney Tsang   }
556*dd3b6498SWhitney Tsang 
557*dd3b6498SWhitney Tsang   if (RefGroups.empty())
558*dd3b6498SWhitney Tsang     return false;
559*dd3b6498SWhitney Tsang 
560*dd3b6498SWhitney Tsang   LLVM_DEBUG({
561*dd3b6498SWhitney Tsang     dbgs() << "\nIDENTIFIED REFERENCE GROUPS:\n";
562*dd3b6498SWhitney Tsang     int n = 1;
563*dd3b6498SWhitney Tsang     for (const ReferenceGroupTy &RG : RefGroups) {
564*dd3b6498SWhitney Tsang       dbgs().indent(2) << "RefGroup " << n << ":\n";
565*dd3b6498SWhitney Tsang       for (const auto &IR : RG)
566*dd3b6498SWhitney Tsang         dbgs().indent(4) << *IR << "\n";
567*dd3b6498SWhitney Tsang       n++;
568*dd3b6498SWhitney Tsang     }
569*dd3b6498SWhitney Tsang     dbgs() << "\n";
570*dd3b6498SWhitney Tsang   });
571*dd3b6498SWhitney Tsang 
572*dd3b6498SWhitney Tsang   return true;
573*dd3b6498SWhitney Tsang }
574*dd3b6498SWhitney Tsang 
575*dd3b6498SWhitney Tsang CacheCostTy
576*dd3b6498SWhitney Tsang CacheCost::computeLoopCacheCost(const Loop &L,
577*dd3b6498SWhitney Tsang                                 const ReferenceGroupsTy &RefGroups) const {
578*dd3b6498SWhitney Tsang   if (!L.isLoopSimplifyForm())
579*dd3b6498SWhitney Tsang     return InvalidCost;
580*dd3b6498SWhitney Tsang 
581*dd3b6498SWhitney Tsang   LLVM_DEBUG(dbgs() << "Considering loop '" << L.getName()
582*dd3b6498SWhitney Tsang                     << "' as innermost loop.\n");
583*dd3b6498SWhitney Tsang 
584*dd3b6498SWhitney Tsang   // Compute the product of the trip counts of each other loop in the nest.
585*dd3b6498SWhitney Tsang   CacheCostTy TripCountsProduct = 1;
586*dd3b6498SWhitney Tsang   for (const auto &TC : TripCounts) {
587*dd3b6498SWhitney Tsang     if (TC.first == &L)
588*dd3b6498SWhitney Tsang       continue;
589*dd3b6498SWhitney Tsang     TripCountsProduct *= TC.second;
590*dd3b6498SWhitney Tsang   }
591*dd3b6498SWhitney Tsang 
592*dd3b6498SWhitney Tsang   CacheCostTy LoopCost = 0;
593*dd3b6498SWhitney Tsang   for (const ReferenceGroupTy &RG : RefGroups) {
594*dd3b6498SWhitney Tsang     CacheCostTy RefGroupCost = computeRefGroupCacheCost(RG, L);
595*dd3b6498SWhitney Tsang     LoopCost += RefGroupCost * TripCountsProduct;
596*dd3b6498SWhitney Tsang   }
597*dd3b6498SWhitney Tsang 
598*dd3b6498SWhitney Tsang   LLVM_DEBUG(dbgs().indent(2) << "Loop '" << L.getName()
599*dd3b6498SWhitney Tsang                               << "' has cost=" << LoopCost << "\n");
600*dd3b6498SWhitney Tsang 
601*dd3b6498SWhitney Tsang   return LoopCost;
602*dd3b6498SWhitney Tsang }
603*dd3b6498SWhitney Tsang 
604*dd3b6498SWhitney Tsang CacheCostTy CacheCost::computeRefGroupCacheCost(const ReferenceGroupTy &RG,
605*dd3b6498SWhitney Tsang                                                 const Loop &L) const {
606*dd3b6498SWhitney Tsang   assert(!RG.empty() && "Reference group should have at least one member.");
607*dd3b6498SWhitney Tsang 
608*dd3b6498SWhitney Tsang   const IndexedReference *Representative = RG.front().get();
609*dd3b6498SWhitney Tsang   return Representative->computeRefCost(L, TTI.getCacheLineSize());
610*dd3b6498SWhitney Tsang }
611*dd3b6498SWhitney Tsang 
612*dd3b6498SWhitney Tsang //===----------------------------------------------------------------------===//
613*dd3b6498SWhitney Tsang // LoopCachePrinterPass implementation
614*dd3b6498SWhitney Tsang //
615*dd3b6498SWhitney Tsang PreservedAnalyses LoopCachePrinterPass::run(Loop &L, LoopAnalysisManager &AM,
616*dd3b6498SWhitney Tsang                                             LoopStandardAnalysisResults &AR,
617*dd3b6498SWhitney Tsang                                             LPMUpdater &U) {
618*dd3b6498SWhitney Tsang   Function *F = L.getHeader()->getParent();
619*dd3b6498SWhitney Tsang   DependenceInfo DI(F, &AR.AA, &AR.SE, &AR.LI);
620*dd3b6498SWhitney Tsang 
621*dd3b6498SWhitney Tsang   if (auto CC = CacheCost::getCacheCost(L, AR, DI))
622*dd3b6498SWhitney Tsang     OS << *CC;
623*dd3b6498SWhitney Tsang 
624*dd3b6498SWhitney Tsang   return PreservedAnalyses::all();
625*dd3b6498SWhitney Tsang }
626