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