1dff0c46cSDimitry Andric //===- CodeMetrics.cpp - Code cost measurements ---------------------------===//
2dff0c46cSDimitry Andric //
3dff0c46cSDimitry Andric //                     The LLVM Compiler Infrastructure
4dff0c46cSDimitry Andric //
5dff0c46cSDimitry Andric // This file is distributed under the University of Illinois Open Source
6dff0c46cSDimitry Andric // License. See LICENSE.TXT for details.
7dff0c46cSDimitry Andric //
8dff0c46cSDimitry Andric //===----------------------------------------------------------------------===//
9dff0c46cSDimitry Andric //
10dff0c46cSDimitry Andric // This file implements code cost measurement utilities.
11dff0c46cSDimitry Andric //
12dff0c46cSDimitry Andric //===----------------------------------------------------------------------===//
13dff0c46cSDimitry Andric 
14dff0c46cSDimitry Andric #include "llvm/Analysis/CodeMetrics.h"
15db17bf38SDimitry Andric #include "llvm/Analysis/AssumptionCache.h"
1639d628a0SDimitry Andric #include "llvm/Analysis/LoopInfo.h"
17139f7f9bSDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h"
1839d628a0SDimitry Andric #include "llvm/Analysis/ValueTracking.h"
1991bc56edSDimitry Andric #include "llvm/IR/CallSite.h"
20139f7f9bSDimitry Andric #include "llvm/IR/DataLayout.h"
21139f7f9bSDimitry Andric #include "llvm/IR/Function.h"
2239d628a0SDimitry Andric #include "llvm/Support/Debug.h"
23ff0cc061SDimitry Andric #include "llvm/Support/raw_ostream.h"
2439d628a0SDimitry Andric 
2539d628a0SDimitry Andric #define DEBUG_TYPE "code-metrics"
26dff0c46cSDimitry Andric 
27dff0c46cSDimitry Andric using namespace llvm;
28dff0c46cSDimitry Andric 
29d88c1a5aSDimitry Andric static void
appendSpeculatableOperands(const Value * V,SmallPtrSetImpl<const Value * > & Visited,SmallVectorImpl<const Value * > & Worklist)30d88c1a5aSDimitry Andric appendSpeculatableOperands(const Value *V,
31d88c1a5aSDimitry Andric                            SmallPtrSetImpl<const Value *> &Visited,
32d88c1a5aSDimitry Andric                            SmallVectorImpl<const Value *> &Worklist) {
33d88c1a5aSDimitry Andric   const User *U = dyn_cast<User>(V);
34d88c1a5aSDimitry Andric   if (!U)
35d88c1a5aSDimitry Andric     return;
36d88c1a5aSDimitry Andric 
37d88c1a5aSDimitry Andric   for (const Value *Operand : U->operands())
38d88c1a5aSDimitry Andric     if (Visited.insert(Operand).second)
39d88c1a5aSDimitry Andric       if (isSafeToSpeculativelyExecute(Operand))
40d88c1a5aSDimitry Andric         Worklist.push_back(Operand);
41d88c1a5aSDimitry Andric }
42d88c1a5aSDimitry Andric 
completeEphemeralValues(SmallPtrSetImpl<const Value * > & Visited,SmallVectorImpl<const Value * > & Worklist,SmallPtrSetImpl<const Value * > & EphValues)43d88c1a5aSDimitry Andric static void completeEphemeralValues(SmallPtrSetImpl<const Value *> &Visited,
44d88c1a5aSDimitry Andric                                     SmallVectorImpl<const Value *> &Worklist,
4539d628a0SDimitry Andric                                     SmallPtrSetImpl<const Value *> &EphValues) {
4639d628a0SDimitry Andric   // Note: We don't speculate PHIs here, so we'll miss instruction chains kept
4739d628a0SDimitry Andric   // alive only by ephemeral values.
4839d628a0SDimitry Andric 
49d88c1a5aSDimitry Andric   // Walk the worklist using an index but without caching the size so we can
50d88c1a5aSDimitry Andric   // append more entries as we process the worklist. This forms a queue without
51d88c1a5aSDimitry Andric   // quadratic behavior by just leaving processed nodes at the head of the
52d88c1a5aSDimitry Andric   // worklist forever.
53d88c1a5aSDimitry Andric   for (int i = 0; i < (int)Worklist.size(); ++i) {
54d88c1a5aSDimitry Andric     const Value *V = Worklist[i];
5539d628a0SDimitry Andric 
56d88c1a5aSDimitry Andric     assert(Visited.count(V) &&
57d88c1a5aSDimitry Andric            "Failed to add a worklist entry to our visited set!");
5839d628a0SDimitry Andric 
5939d628a0SDimitry Andric     // If all uses of this value are ephemeral, then so is this value.
60d88c1a5aSDimitry Andric     if (!all_of(V->users(), [&](const User *U) { return EphValues.count(U); }))
6139d628a0SDimitry Andric       continue;
6239d628a0SDimitry Andric 
6339d628a0SDimitry Andric     EphValues.insert(V);
64*4ba319b5SDimitry Andric     LLVM_DEBUG(dbgs() << "Ephemeral Value: " << *V << "\n");
6539d628a0SDimitry Andric 
66d88c1a5aSDimitry Andric     // Append any more operands to consider.
67d88c1a5aSDimitry Andric     appendSpeculatableOperands(V, Visited, Worklist);
6839d628a0SDimitry Andric   }
6939d628a0SDimitry Andric }
7039d628a0SDimitry Andric 
7139d628a0SDimitry Andric // Find all ephemeral values.
collectEphemeralValues(const Loop * L,AssumptionCache * AC,SmallPtrSetImpl<const Value * > & EphValues)7239d628a0SDimitry Andric void CodeMetrics::collectEphemeralValues(
7339d628a0SDimitry Andric     const Loop *L, AssumptionCache *AC,
7439d628a0SDimitry Andric     SmallPtrSetImpl<const Value *> &EphValues) {
75d88c1a5aSDimitry Andric   SmallPtrSet<const Value *, 32> Visited;
76d88c1a5aSDimitry Andric   SmallVector<const Value *, 16> Worklist;
7739d628a0SDimitry Andric 
7839d628a0SDimitry Andric   for (auto &AssumeVH : AC->assumptions()) {
7939d628a0SDimitry Andric     if (!AssumeVH)
8039d628a0SDimitry Andric       continue;
8139d628a0SDimitry Andric     Instruction *I = cast<Instruction>(AssumeVH);
8239d628a0SDimitry Andric 
83d88c1a5aSDimitry Andric     // Filter out call sites outside of the loop so we don't do a function's
8439d628a0SDimitry Andric     // worth of work for each of its loops (and, in the common case, ephemeral
8539d628a0SDimitry Andric     // values in the loop are likely due to @llvm.assume calls in the loop).
8639d628a0SDimitry Andric     if (!L->contains(I->getParent()))
8739d628a0SDimitry Andric       continue;
8839d628a0SDimitry Andric 
89d88c1a5aSDimitry Andric     if (EphValues.insert(I).second)
90d88c1a5aSDimitry Andric       appendSpeculatableOperands(I, Visited, Worklist);
9139d628a0SDimitry Andric   }
9239d628a0SDimitry Andric 
93d88c1a5aSDimitry Andric   completeEphemeralValues(Visited, Worklist, EphValues);
9439d628a0SDimitry Andric }
9539d628a0SDimitry Andric 
collectEphemeralValues(const Function * F,AssumptionCache * AC,SmallPtrSetImpl<const Value * > & EphValues)9639d628a0SDimitry Andric void CodeMetrics::collectEphemeralValues(
9739d628a0SDimitry Andric     const Function *F, AssumptionCache *AC,
9839d628a0SDimitry Andric     SmallPtrSetImpl<const Value *> &EphValues) {
99d88c1a5aSDimitry Andric   SmallPtrSet<const Value *, 32> Visited;
100d88c1a5aSDimitry Andric   SmallVector<const Value *, 16> Worklist;
10139d628a0SDimitry Andric 
10239d628a0SDimitry Andric   for (auto &AssumeVH : AC->assumptions()) {
10339d628a0SDimitry Andric     if (!AssumeVH)
10439d628a0SDimitry Andric       continue;
10539d628a0SDimitry Andric     Instruction *I = cast<Instruction>(AssumeVH);
10639d628a0SDimitry Andric     assert(I->getParent()->getParent() == F &&
10739d628a0SDimitry Andric            "Found assumption for the wrong function!");
108d88c1a5aSDimitry Andric 
109d88c1a5aSDimitry Andric     if (EphValues.insert(I).second)
110d88c1a5aSDimitry Andric       appendSpeculatableOperands(I, Visited, Worklist);
11139d628a0SDimitry Andric   }
11239d628a0SDimitry Andric 
113d88c1a5aSDimitry Andric   completeEphemeralValues(Visited, Worklist, EphValues);
11439d628a0SDimitry Andric }
11539d628a0SDimitry Andric 
1163ca95b02SDimitry Andric /// Fill in the current structure with information gleaned from the specified
1173ca95b02SDimitry Andric /// block.
analyzeBasicBlock(const BasicBlock * BB,const TargetTransformInfo & TTI,const SmallPtrSetImpl<const Value * > & EphValues)118dff0c46cSDimitry Andric void CodeMetrics::analyzeBasicBlock(const BasicBlock *BB,
11939d628a0SDimitry Andric                                     const TargetTransformInfo &TTI,
120d88c1a5aSDimitry Andric                                     const SmallPtrSetImpl<const Value*> &EphValues) {
121dff0c46cSDimitry Andric   ++NumBlocks;
122dff0c46cSDimitry Andric   unsigned NumInstsBeforeThisBB = NumInsts;
1233ca95b02SDimitry Andric   for (const Instruction &I : *BB) {
12439d628a0SDimitry Andric     // Skip ephemeral values.
1253ca95b02SDimitry Andric     if (EphValues.count(&I))
12639d628a0SDimitry Andric       continue;
12739d628a0SDimitry Andric 
128dff0c46cSDimitry Andric     // Special handling for calls.
1293ca95b02SDimitry Andric     if (isa<CallInst>(I) || isa<InvokeInst>(I)) {
1303ca95b02SDimitry Andric       ImmutableCallSite CS(&I);
131dff0c46cSDimitry Andric 
132dff0c46cSDimitry Andric       if (const Function *F = CS.getCalledFunction()) {
133dff0c46cSDimitry Andric         // If a function is both internal and has a single use, then it is
134dff0c46cSDimitry Andric         // extremely likely to get inlined in the future (it was probably
135dff0c46cSDimitry Andric         // exposed by an interleaved devirtualization pass).
136dff0c46cSDimitry Andric         if (!CS.isNoInline() && F->hasInternalLinkage() && F->hasOneUse())
137dff0c46cSDimitry Andric           ++NumInlineCandidates;
138dff0c46cSDimitry Andric 
139dff0c46cSDimitry Andric         // If this call is to function itself, then the function is recursive.
140dff0c46cSDimitry Andric         // Inlining it into other functions is a bad idea, because this is
141dff0c46cSDimitry Andric         // basically just a form of loop peeling, and our metrics aren't useful
142dff0c46cSDimitry Andric         // for that case.
143dff0c46cSDimitry Andric         if (F == BB->getParent())
144dff0c46cSDimitry Andric           isRecursive = true;
145dff0c46cSDimitry Andric 
146139f7f9bSDimitry Andric         if (TTI.isLoweredToCall(F))
147139f7f9bSDimitry Andric           ++NumCalls;
148139f7f9bSDimitry Andric       } else {
149dff0c46cSDimitry Andric         // We don't want inline asm to count as a call - that would prevent loop
150dff0c46cSDimitry Andric         // unrolling. The argument setup cost is still real, though.
151dff0c46cSDimitry Andric         if (!isa<InlineAsm>(CS.getCalledValue()))
152dff0c46cSDimitry Andric           ++NumCalls;
153dff0c46cSDimitry Andric       }
154dff0c46cSDimitry Andric     }
155dff0c46cSDimitry Andric 
1563ca95b02SDimitry Andric     if (const AllocaInst *AI = dyn_cast<AllocaInst>(&I)) {
157dff0c46cSDimitry Andric       if (!AI->isStaticAlloca())
158dff0c46cSDimitry Andric         this->usesDynamicAlloca = true;
159dff0c46cSDimitry Andric     }
160dff0c46cSDimitry Andric 
1613ca95b02SDimitry Andric     if (isa<ExtractElementInst>(I) || I.getType()->isVectorTy())
162dff0c46cSDimitry Andric       ++NumVectorInsts;
163dff0c46cSDimitry Andric 
1643ca95b02SDimitry Andric     if (I.getType()->isTokenTy() && I.isUsedOutsideOfBlock(BB))
1657d523365SDimitry Andric       notDuplicatable = true;
1667d523365SDimitry Andric 
1673ca95b02SDimitry Andric     if (const CallInst *CI = dyn_cast<CallInst>(&I)) {
16891bc56edSDimitry Andric       if (CI->cannotDuplicate())
169139f7f9bSDimitry Andric         notDuplicatable = true;
1703ca95b02SDimitry Andric       if (CI->isConvergent())
1713ca95b02SDimitry Andric         convergent = true;
1723ca95b02SDimitry Andric     }
173139f7f9bSDimitry Andric 
1743ca95b02SDimitry Andric     if (const InvokeInst *InvI = dyn_cast<InvokeInst>(&I))
17591bc56edSDimitry Andric       if (InvI->cannotDuplicate())
176139f7f9bSDimitry Andric         notDuplicatable = true;
177139f7f9bSDimitry Andric 
1783ca95b02SDimitry Andric     NumInsts += TTI.getUserCost(&I);
179dff0c46cSDimitry Andric   }
180dff0c46cSDimitry Andric 
181dff0c46cSDimitry Andric   if (isa<ReturnInst>(BB->getTerminator()))
182dff0c46cSDimitry Andric     ++NumRets;
183dff0c46cSDimitry Andric 
184dff0c46cSDimitry Andric   // We never want to inline functions that contain an indirectbr.  This is
185dff0c46cSDimitry Andric   // incorrect because all the blockaddress's (in static global initializers
186dff0c46cSDimitry Andric   // for example) would be referring to the original function, and this indirect
187dff0c46cSDimitry Andric   // jump would jump from the inlined copy of the function into the original
188dff0c46cSDimitry Andric   // function which is extremely undefined behavior.
189dff0c46cSDimitry Andric   // FIXME: This logic isn't really right; we can safely inline functions
190dff0c46cSDimitry Andric   // with indirectbr's as long as no other function or global references the
191dff0c46cSDimitry Andric   // blockaddress of a block within the current function.  And as a QOI issue,
192dff0c46cSDimitry Andric   // if someone is using a blockaddress without an indirectbr, and that
193dff0c46cSDimitry Andric   // reference somehow ends up in another function or global, we probably
194dff0c46cSDimitry Andric   // don't want to inline this function.
195139f7f9bSDimitry Andric   notDuplicatable |= isa<IndirectBrInst>(BB->getTerminator());
196dff0c46cSDimitry Andric 
197dff0c46cSDimitry Andric   // Remember NumInsts for this BB.
198dff0c46cSDimitry Andric   NumBBInsts[BB] = NumInsts - NumInstsBeforeThisBB;
199dff0c46cSDimitry Andric }
200