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