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