1*0b57cec5SDimitry Andric //===- CodeMetrics.cpp - Code cost measurements ---------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This file implements code cost measurement utilities.
10*0b57cec5SDimitry Andric //
11*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
12*0b57cec5SDimitry Andric
13*0b57cec5SDimitry Andric #include "llvm/Analysis/CodeMetrics.h"
14*0b57cec5SDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
15*0b57cec5SDimitry Andric #include "llvm/Analysis/AssumptionCache.h"
16*0b57cec5SDimitry Andric #include "llvm/Analysis/LoopInfo.h"
17*0b57cec5SDimitry Andric #include "llvm/Analysis/TargetTransformInfo.h"
18*0b57cec5SDimitry Andric #include "llvm/IR/Function.h"
19*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
20*0b57cec5SDimitry Andric #include "llvm/Support/InstructionCost.h"
21*0b57cec5SDimitry Andric
22*0b57cec5SDimitry Andric #define DEBUG_TYPE "code-metrics"
23*0b57cec5SDimitry Andric
24*0b57cec5SDimitry Andric using namespace llvm;
25*0b57cec5SDimitry Andric
26*0b57cec5SDimitry Andric static void
appendSpeculatableOperands(const Value * V,SmallPtrSetImpl<const Value * > & Visited,SmallVectorImpl<const Value * > & Worklist)27*0b57cec5SDimitry Andric appendSpeculatableOperands(const Value *V,
28*0b57cec5SDimitry Andric SmallPtrSetImpl<const Value *> &Visited,
29*0b57cec5SDimitry Andric SmallVectorImpl<const Value *> &Worklist) {
30*0b57cec5SDimitry Andric const User *U = dyn_cast<User>(V);
31*0b57cec5SDimitry Andric if (!U)
32*0b57cec5SDimitry Andric return;
33*0b57cec5SDimitry Andric
34*0b57cec5SDimitry Andric for (const Value *Operand : U->operands())
35*0b57cec5SDimitry Andric if (Visited.insert(Operand).second)
36*0b57cec5SDimitry Andric if (const auto *I = dyn_cast<Instruction>(Operand))
37*0b57cec5SDimitry Andric if (!I->mayHaveSideEffects() && !I->isTerminator())
38*0b57cec5SDimitry Andric Worklist.push_back(I);
39*0b57cec5SDimitry Andric }
40*0b57cec5SDimitry Andric
completeEphemeralValues(SmallPtrSetImpl<const Value * > & Visited,SmallVectorImpl<const Value * > & Worklist,SmallPtrSetImpl<const Value * > & EphValues)41*0b57cec5SDimitry Andric static void completeEphemeralValues(SmallPtrSetImpl<const Value *> &Visited,
42*0b57cec5SDimitry Andric SmallVectorImpl<const Value *> &Worklist,
43*0b57cec5SDimitry Andric SmallPtrSetImpl<const Value *> &EphValues) {
44*0b57cec5SDimitry Andric // Note: We don't speculate PHIs here, so we'll miss instruction chains kept
45*0b57cec5SDimitry Andric // alive only by ephemeral values.
46*0b57cec5SDimitry Andric
47*0b57cec5SDimitry Andric // Walk the worklist using an index but without caching the size so we can
48*0b57cec5SDimitry Andric // append more entries as we process the worklist. This forms a queue without
49*0b57cec5SDimitry Andric // quadratic behavior by just leaving processed nodes at the head of the
50*0b57cec5SDimitry Andric // worklist forever.
51*0b57cec5SDimitry Andric for (int i = 0; i < (int)Worklist.size(); ++i) {
52*0b57cec5SDimitry Andric const Value *V = Worklist[i];
53*0b57cec5SDimitry Andric
54*0b57cec5SDimitry Andric assert(Visited.count(V) &&
55*0b57cec5SDimitry Andric "Failed to add a worklist entry to our visited set!");
56*0b57cec5SDimitry Andric
57*0b57cec5SDimitry Andric // If all uses of this value are ephemeral, then so is this value.
58*0b57cec5SDimitry Andric if (!all_of(V->users(), [&](const User *U) { return EphValues.count(U); }))
59*0b57cec5SDimitry Andric continue;
60*0b57cec5SDimitry Andric
61*0b57cec5SDimitry Andric EphValues.insert(V);
62*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Ephemeral Value: " << *V << "\n");
63*0b57cec5SDimitry Andric
64*0b57cec5SDimitry Andric // Append any more operands to consider.
65*0b57cec5SDimitry Andric appendSpeculatableOperands(V, Visited, Worklist);
66*0b57cec5SDimitry Andric }
67*0b57cec5SDimitry Andric }
68*0b57cec5SDimitry Andric
69*0b57cec5SDimitry Andric // Find all ephemeral values.
collectEphemeralValues(const Loop * L,AssumptionCache * AC,SmallPtrSetImpl<const Value * > & EphValues)70*0b57cec5SDimitry Andric void CodeMetrics::collectEphemeralValues(
71*0b57cec5SDimitry Andric const Loop *L, AssumptionCache *AC,
72*0b57cec5SDimitry Andric SmallPtrSetImpl<const Value *> &EphValues) {
73*0b57cec5SDimitry Andric SmallPtrSet<const Value *, 32> Visited;
74*0b57cec5SDimitry Andric SmallVector<const Value *, 16> Worklist;
75*0b57cec5SDimitry Andric
76*0b57cec5SDimitry Andric for (auto &AssumeVH : AC->assumptions()) {
77*0b57cec5SDimitry Andric if (!AssumeVH)
78*0b57cec5SDimitry Andric continue;
79*0b57cec5SDimitry Andric Instruction *I = cast<Instruction>(AssumeVH);
80*0b57cec5SDimitry Andric
81*0b57cec5SDimitry Andric // Filter out call sites outside of the loop so we don't do a function's
82*0b57cec5SDimitry Andric // worth of work for each of its loops (and, in the common case, ephemeral
83*0b57cec5SDimitry Andric // values in the loop are likely due to @llvm.assume calls in the loop).
84*0b57cec5SDimitry Andric if (!L->contains(I->getParent()))
85*0b57cec5SDimitry Andric continue;
86*0b57cec5SDimitry Andric
87*0b57cec5SDimitry Andric if (EphValues.insert(I).second)
88*0b57cec5SDimitry Andric appendSpeculatableOperands(I, Visited, Worklist);
89*0b57cec5SDimitry Andric }
90*0b57cec5SDimitry Andric
91*0b57cec5SDimitry Andric completeEphemeralValues(Visited, Worklist, EphValues);
92*0b57cec5SDimitry Andric }
93*0b57cec5SDimitry Andric
collectEphemeralValues(const Function * F,AssumptionCache * AC,SmallPtrSetImpl<const Value * > & EphValues)94*0b57cec5SDimitry Andric void CodeMetrics::collectEphemeralValues(
95*0b57cec5SDimitry Andric const Function *F, AssumptionCache *AC,
96*0b57cec5SDimitry Andric SmallPtrSetImpl<const Value *> &EphValues) {
97*0b57cec5SDimitry Andric SmallPtrSet<const Value *, 32> Visited;
98*0b57cec5SDimitry Andric SmallVector<const Value *, 16> Worklist;
99*0b57cec5SDimitry Andric
100*0b57cec5SDimitry Andric for (auto &AssumeVH : AC->assumptions()) {
101*0b57cec5SDimitry Andric if (!AssumeVH)
102*0b57cec5SDimitry Andric continue;
103*0b57cec5SDimitry Andric Instruction *I = cast<Instruction>(AssumeVH);
104*0b57cec5SDimitry Andric assert(I->getParent()->getParent() == F &&
105*0b57cec5SDimitry Andric "Found assumption for the wrong function!");
106*0b57cec5SDimitry Andric
107*0b57cec5SDimitry Andric if (EphValues.insert(I).second)
108*0b57cec5SDimitry Andric appendSpeculatableOperands(I, Visited, Worklist);
109*0b57cec5SDimitry Andric }
110*0b57cec5SDimitry Andric
111*0b57cec5SDimitry Andric completeEphemeralValues(Visited, Worklist, EphValues);
112*0b57cec5SDimitry Andric }
113*0b57cec5SDimitry Andric
114*0b57cec5SDimitry Andric /// Fill in the current structure with information gleaned from the specified
115*0b57cec5SDimitry Andric /// block.
analyzeBasicBlock(const BasicBlock * BB,const TargetTransformInfo & TTI,const SmallPtrSetImpl<const Value * > & EphValues,bool PrepareForLTO)116*0b57cec5SDimitry Andric void CodeMetrics::analyzeBasicBlock(
117*0b57cec5SDimitry Andric const BasicBlock *BB, const TargetTransformInfo &TTI,
118*0b57cec5SDimitry Andric const SmallPtrSetImpl<const Value *> &EphValues, bool PrepareForLTO) {
119*0b57cec5SDimitry Andric ++NumBlocks;
120*0b57cec5SDimitry Andric InstructionCost NumInstsBeforeThisBB = NumInsts;
121*0b57cec5SDimitry Andric for (const Instruction &I : *BB) {
122*0b57cec5SDimitry Andric // Skip ephemeral values.
123*0b57cec5SDimitry Andric if (EphValues.count(&I))
124*0b57cec5SDimitry Andric continue;
125*0b57cec5SDimitry Andric
126*0b57cec5SDimitry Andric // Special handling for calls.
127*0b57cec5SDimitry Andric if (const auto *Call = dyn_cast<CallBase>(&I)) {
128*0b57cec5SDimitry Andric if (const Function *F = Call->getCalledFunction()) {
129*0b57cec5SDimitry Andric bool IsLoweredToCall = TTI.isLoweredToCall(F);
130*0b57cec5SDimitry Andric // If a function is both internal and has a single use, then it is
131*0b57cec5SDimitry Andric // extremely likely to get inlined in the future (it was probably
132*0b57cec5SDimitry Andric // exposed by an interleaved devirtualization pass).
133*0b57cec5SDimitry Andric // When preparing for LTO, liberally consider calls as inline
134*0b57cec5SDimitry Andric // candidates.
135*0b57cec5SDimitry Andric if (!Call->isNoInline() && IsLoweredToCall &&
136*0b57cec5SDimitry Andric ((F->hasInternalLinkage() && F->hasOneLiveUse()) ||
137*0b57cec5SDimitry Andric PrepareForLTO)) {
138*0b57cec5SDimitry Andric ++NumInlineCandidates;
139*0b57cec5SDimitry Andric }
140*0b57cec5SDimitry Andric
141*0b57cec5SDimitry Andric // If this call is to function itself, then the function is recursive.
142*0b57cec5SDimitry Andric // Inlining it into other functions is a bad idea, because this is
143*0b57cec5SDimitry Andric // basically just a form of loop peeling, and our metrics aren't useful
144*0b57cec5SDimitry Andric // for that case.
145*0b57cec5SDimitry Andric if (F == BB->getParent())
146*0b57cec5SDimitry Andric isRecursive = true;
147*0b57cec5SDimitry Andric
148*0b57cec5SDimitry Andric if (IsLoweredToCall)
149*0b57cec5SDimitry Andric ++NumCalls;
150*0b57cec5SDimitry Andric } else {
151*0b57cec5SDimitry Andric // We don't want inline asm to count as a call - that would prevent loop
152*0b57cec5SDimitry Andric // unrolling. The argument setup cost is still real, though.
153*0b57cec5SDimitry Andric if (!Call->isInlineAsm())
154*0b57cec5SDimitry Andric ++NumCalls;
155*0b57cec5SDimitry Andric }
156*0b57cec5SDimitry Andric }
157*0b57cec5SDimitry Andric
158*0b57cec5SDimitry Andric if (const AllocaInst *AI = dyn_cast<AllocaInst>(&I)) {
159*0b57cec5SDimitry Andric if (!AI->isStaticAlloca())
160*0b57cec5SDimitry Andric this->usesDynamicAlloca = true;
161*0b57cec5SDimitry Andric }
162*0b57cec5SDimitry Andric
163*0b57cec5SDimitry Andric if (isa<ExtractElementInst>(I) || I.getType()->isVectorTy())
164*0b57cec5SDimitry Andric ++NumVectorInsts;
165*0b57cec5SDimitry Andric
166*0b57cec5SDimitry Andric if (I.getType()->isTokenTy() && I.isUsedOutsideOfBlock(BB))
167*0b57cec5SDimitry Andric notDuplicatable = true;
168*0b57cec5SDimitry Andric
169*0b57cec5SDimitry Andric if (const CallInst *CI = dyn_cast<CallInst>(&I)) {
170*0b57cec5SDimitry Andric if (CI->cannotDuplicate())
171*0b57cec5SDimitry Andric notDuplicatable = true;
172*0b57cec5SDimitry Andric if (CI->isConvergent())
173*0b57cec5SDimitry Andric convergent = true;
174*0b57cec5SDimitry Andric }
175*0b57cec5SDimitry Andric
176*0b57cec5SDimitry Andric if (const InvokeInst *InvI = dyn_cast<InvokeInst>(&I))
177*0b57cec5SDimitry Andric if (InvI->cannotDuplicate())
178*0b57cec5SDimitry Andric notDuplicatable = true;
179*0b57cec5SDimitry Andric
180*0b57cec5SDimitry Andric NumInsts += TTI.getInstructionCost(&I, TargetTransformInfo::TCK_CodeSize);
181*0b57cec5SDimitry Andric }
182*0b57cec5SDimitry Andric
183*0b57cec5SDimitry Andric if (isa<ReturnInst>(BB->getTerminator()))
184*0b57cec5SDimitry Andric ++NumRets;
185*0b57cec5SDimitry Andric
186*0b57cec5SDimitry Andric // We never want to inline functions that contain an indirectbr. This is
187*0b57cec5SDimitry Andric // incorrect because all the blockaddress's (in static global initializers
188*0b57cec5SDimitry Andric // for example) would be referring to the original function, and this indirect
189*0b57cec5SDimitry Andric // jump would jump from the inlined copy of the function into the original
190*0b57cec5SDimitry Andric // function which is extremely undefined behavior.
191*0b57cec5SDimitry Andric // FIXME: This logic isn't really right; we can safely inline functions
192*0b57cec5SDimitry Andric // with indirectbr's as long as no other function or global references the
193*0b57cec5SDimitry Andric // blockaddress of a block within the current function. And as a QOI issue,
194*0b57cec5SDimitry Andric // if someone is using a blockaddress without an indirectbr, and that
195*0b57cec5SDimitry Andric // reference somehow ends up in another function or global, we probably
196 // don't want to inline this function.
197 notDuplicatable |= isa<IndirectBrInst>(BB->getTerminator());
198
199 // Remember NumInsts for this BB.
200 InstructionCost NumInstsThisBB = NumInsts - NumInstsBeforeThisBB;
201 NumBBInsts[BB] = NumInstsThisBB;
202 }
203