LLVM 24.0.0git
InlineOrder.cpp
Go to the documentation of this file.
1//===- InlineOrder.cpp - Inlining order abstraction -*- C++ ---*-----------===//
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
10#include "AnalysisOptions.h"
20
21using namespace llvm;
22
23#define DEBUG_TYPE "inline-order"
24
25namespace {
26
27llvm::InlineCost getInlineCostWrapper(CallBase &CB,
29 const InlineParams &Params) {
30 Function &Caller = *CB.getCaller();
33 .getCachedResult<ProfileSummaryAnalysis>(
34 *CB.getParent()->getParent()->getParent());
35
36 auto &ORE = FAM.getResult<OptimizationRemarkEmitterAnalysis>(Caller);
37 auto GetAssumptionCache = [&](Function &F) -> AssumptionCache & {
38 return FAM.getResult<AssumptionAnalysis>(F);
39 };
40 auto GetBFI = [&](Function &F) -> BlockFrequencyInfo & {
41 return FAM.getResult<BlockFrequencyAnalysis>(F);
42 };
43 auto GetTLI = [&](Function &F) -> const TargetLibraryInfo & {
44 return FAM.getResult<TargetLibraryAnalysis>(F);
45 };
46
47 Function &Callee = *CB.getCalledFunction();
48 auto &CallerTTI = FAM.getResult<TargetIRAnalysis>(Caller);
49 bool RemarksEnabled =
50 Callee.getContext().getDiagHandlerPtr()->isMissedOptRemarkEnabled(
52 return getInlineCost(CB, Params, CallerTTI, GetAssumptionCache, GetTLI,
53 GetBFI, PSI, RemarksEnabled ? &ORE : nullptr);
54}
55
56class SizePriority {
57public:
58 SizePriority() = default;
59 SizePriority(const CallBase *CB, FunctionAnalysisManager &,
60 const InlineParams &) {
61 Function *Callee = CB->getCalledFunction();
62 Size = Callee->getInstructionCount();
63 }
64
65 static bool isMoreDesirable(const SizePriority &P1, const SizePriority &P2) {
66 return P1.Size < P2.Size;
67 }
68
69private:
70 unsigned Size = UINT_MAX;
71};
72
73class CostPriority {
74public:
75 CostPriority() = default;
76 CostPriority(const CallBase *CB, FunctionAnalysisManager &FAM,
77 const InlineParams &Params) {
78 auto IC = getInlineCostWrapper(const_cast<CallBase &>(*CB), FAM, Params);
79 if (IC.isVariable())
80 Cost = IC.getCost();
81 else
82 Cost = IC.isNever() ? INT_MAX : INT_MIN;
83 }
84
85 static bool isMoreDesirable(const CostPriority &P1, const CostPriority &P2) {
86 return P1.Cost < P2.Cost;
87 }
88
89private:
90 int Cost = INT_MAX;
91};
92
93class CostBenefitPriority {
94public:
95 CostBenefitPriority() = default;
96 CostBenefitPriority(const CallBase *CB, FunctionAnalysisManager &FAM,
97 const InlineParams &Params) {
98 auto IC = getInlineCostWrapper(const_cast<CallBase &>(*CB), FAM, Params);
99 int StaticBonusApplied = 0;
100 if (IC.isVariable()) {
101 Cost = IC.getCost();
102 StaticBonusApplied = IC.getStaticBonusApplied();
103 CostBenefit = IC.getCostBenefit();
104 } else {
105 Cost = IC.isNever() ? INT_MAX : INT_MIN;
106 CostBenefit = std::nullopt;
107 }
108 // We add back StaticBonusApplied to determine whether we expect the caller
109 // to shrink (even if we don't delete the callee).
110 ReducesCallerSize =
111 Cost + StaticBonusApplied < getAnalysisOptions(*CB->getCaller())
112 .module_inliner_top_priority_threshold;
113 }
114
115 static bool isMoreDesirable(const CostBenefitPriority &P1,
116 const CostBenefitPriority &P2) {
117 // We prioritize call sites in the dictionary order of the following
118 // priorities:
119 //
120 // 1. Those call sites that are expected to reduce the caller size when
121 // inlined. Within them, we prioritize those call sites with bigger
122 // reduction.
123 //
124 // 2. Those call sites that have gone through the cost-benefit analysis.
125 // Currently, they are limited to hot call sites. Within them, we
126 // prioritize those call sites with higher benefit-to-cost ratios.
127 //
128 // 3. Remaining call sites are prioritized according to their costs.
129 if (P1.ReducesCallerSize || P2.ReducesCallerSize) {
130 // If one reduces the caller size while the other doesn't, then return
131 // true iff P1 reduces the caller size.
132 if (P1.ReducesCallerSize != P2.ReducesCallerSize)
133 return P1.ReducesCallerSize;
134
135 // If they both reduce the caller size, pick the one with the smaller
136 // cost.
137 return P1.Cost < P2.Cost;
138 }
139
140 bool P1HasCB = P1.CostBenefit.has_value();
141 bool P2HasCB = P2.CostBenefit.has_value();
142 if (P1HasCB || P2HasCB) {
143 // If one has undergone the cost-benefit analysis while the other hasn't,
144 // then return true iff P1 has.
145 if (P1HasCB != P2HasCB)
146 return P1HasCB;
147
148 // If they have undergone the cost-benefit analysis, then pick the one
149 // with a higher benefit-to-cost ratio.
150 APInt LHS = P1.CostBenefit->getBenefit() * P2.CostBenefit->getCost();
151 APInt RHS = P2.CostBenefit->getBenefit() * P1.CostBenefit->getCost();
152 return LHS.ugt(RHS);
153 }
154
155 // Remaining call sites are ordered according to their costs.
156 return P1.Cost < P2.Cost;
157 }
158
159private:
160 int Cost = INT_MAX;
161 bool ReducesCallerSize = false;
162 std::optional<CostBenefitPair> CostBenefit;
163};
164
165class MLPriority {
166public:
167 MLPriority() = default;
168 MLPriority(const CallBase *CB, FunctionAnalysisManager &FAM,
169 const InlineParams &Params) {
170 auto IC = getInlineCostWrapper(const_cast<CallBase &>(*CB), FAM, Params);
171 if (IC.isVariable())
172 Cost = IC.getCost();
173 else
174 Cost = IC.isNever() ? INT_MAX : INT_MIN;
175 }
176
177 static bool isMoreDesirable(const MLPriority &P1, const MLPriority &P2) {
178 return P1.Cost < P2.Cost;
179 }
180
181private:
182 int Cost = INT_MAX;
183};
184
185template <typename PriorityT> class PriorityInlineOrder : public InlineOrder {
186 bool hasLowerPriority(const CallBase *L, const CallBase *R) const {
187 const auto I1 = Priorities.find(L);
188 const auto I2 = Priorities.find(R);
189 assert(I1 != Priorities.end() && I2 != Priorities.end());
190 return PriorityT::isMoreDesirable(I2->second, I1->second);
191 }
192
193 bool updateAndCheckDecreased(const CallBase *CB) {
194 auto It = Priorities.find(CB);
195 const auto OldPriority = It->second;
196 It->second = PriorityT(CB, FAM, Params);
197 const auto NewPriority = It->second;
198 return PriorityT::isMoreDesirable(OldPriority, NewPriority);
199 }
200
201 // A call site could become less desirable for inlining because of the size
202 // growth from prior inlining into the callee. This method is used to lazily
203 // update the desirability of a call site if it's decreasing. It is only
204 // called on pop(), not every time the desirability changes. When the
205 // desirability of the front call site decreases, an updated one would be
206 // pushed right back into the heap. For simplicity, those cases where the
207 // desirability of a call site increases are ignored here.
208 void pop_heap_adjust() {
209 std::pop_heap(Heap.begin(), Heap.end(), isLess);
210 while (updateAndCheckDecreased(Heap.back())) {
211 std::push_heap(Heap.begin(), Heap.end(), isLess);
212 std::pop_heap(Heap.begin(), Heap.end(), isLess);
213 }
214 }
215
216public:
217 PriorityInlineOrder(FunctionAnalysisManager &FAM, const InlineParams &Params)
218 : FAM(FAM), Params(Params) {
219 isLess = [&](const CallBase *L, const CallBase *R) {
220 return hasLowerPriority(L, R);
221 };
222 }
223
224 size_t size() override { return Heap.size(); }
225
226 void push(CallBase *CB) override {
227 Heap.push_back(CB);
228 Priorities[CB] = PriorityT(CB, FAM, Params);
229 std::push_heap(Heap.begin(), Heap.end(), isLess);
230 }
231
232 CallBase *pop() override {
233 assert(size() > 0);
234 pop_heap_adjust();
235
236 return Heap.pop_back_val();
237 }
238
239 void erase_if(function_ref<bool(CallBase *)> Pred) override {
240 llvm::erase_if(Heap, Pred);
241 std::make_heap(Heap.begin(), Heap.end(), isLess);
242 }
243
244private:
246 std::function<bool(const CallBase *L, const CallBase *R)> isLess;
249 const InlineParams &Params;
250};
251
252} // namespace
253
255
256std::unique_ptr<InlineOrder>
258 const InlineParams &Params,
260 switch (getAnalysisOptions(M).inline_priority_mode) {
262 LLVM_DEBUG(dbgs() << " Current used priority: Size priority ---- \n");
263 return std::make_unique<PriorityInlineOrder<SizePriority>>(FAM, Params);
264
266 LLVM_DEBUG(dbgs() << " Current used priority: Cost priority ---- \n");
267 return std::make_unique<PriorityInlineOrder<CostPriority>>(FAM, Params);
268
271 dbgs() << " Current used priority: cost-benefit priority ---- \n");
272 return std::make_unique<PriorityInlineOrder<CostBenefitPriority>>(FAM,
273 Params);
275 LLVM_DEBUG(dbgs() << " Current used priority: ML priority ---- \n");
276 return std::make_unique<PriorityInlineOrder<MLPriority>>(FAM, Params);
277 }
278 return nullptr;
279}
280
282 const InlineParams &Params,
284 Module &M) {
285 if (MAM.isPassRegistered<PluginInlineOrderAnalysis>()) {
286 LLVM_DEBUG(dbgs() << " Current used priority: plugin ---- \n");
287 return MAM.getResult<PluginInlineOrderAnalysis>(M).Factory(FAM, Params, MAM,
288 M);
289 }
290 return getDefaultInlineOrder(FAM, Params, MAM, M);
291}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define DEBUG_TYPE
This is the interface for a simple mod/ref and alias analysis over globals.
#define F(x, y, z)
Definition MD5.cpp:54
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
#define LLVM_DEBUG(...)
Definition Debug.h:119
This pass exposes codegen information to IR-level passes.
Value * RHS
Value * LHS
Class for arbitrary precision integers.
Definition APInt.h:78
A function analysis which provides an AssumptionCache.
A cache of @llvm.assume calls within a function.
Analysis pass which computes BlockFrequencyInfo.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
LLVM_ABI Function * getCaller()
Helper to get the caller (the parent function).
Represents the cost of inlining a function.
Definition InlineCost.h:91
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
Used for dynamically loading instances of InlineOrder as plugins.
Definition InlineOrder.h:53
static LLVM_ABI AnalysisKey Key
Definition InlineOrder.h:55
Analysis providing profile information.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Analysis pass providing the TargetTransformInfo.
Analysis pass providing the TargetLibraryInfo.
Provides information about what library functions are available for the current target.
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
Definition ilist_node.h:34
This is an optimization pass for GlobalISel generic memory operations.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition STLExtras.h:1685
LLVM_ABI InlineCost getInlineCost(CallBase &Call, const InlineParams &Params, TargetTransformInfo &CallerTTI, function_ref< AssumptionCache &(Function &)> GetAssumptionCache, function_ref< const TargetLibraryInfo &(Function &)> GetTLI, function_ref< BlockFrequencyInfo &(Function &)> GetBFI=nullptr, ProfileSummaryInfo *PSI=nullptr, OptimizationRemarkEmitter *ORE=nullptr, function_ref< EphemeralValuesCache &(Function &)> GetEphValuesCache=nullptr)
Get an InlineCost object representing the cost of inlining this callsite.
OuterAnalysisManagerProxy< ModuleAnalysisManager, Function > ModuleAnalysisManagerFunctionProxy
Provide the ModuleAnalysisManager to Function proxy.
const AnalysisOptions & getAnalysisOptions(const LLVMContext &C)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
LLVM_ABI std::unique_ptr< InlineOrder > getDefaultInlineOrder(FunctionAnalysisManager &FAM, const InlineParams &Params, ModuleAnalysisManager &MAM, Module &M)
LLVM_ABI std::unique_ptr< InlineOrder > getInlineOrder(FunctionAnalysisManager &FAM, const InlineParams &Params, ModuleAnalysisManager &MAM, Module &M)
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
Definition STLExtras.h:2208
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
A special type used by analysis passes to provide an address that identifies that particular analysis...
Definition Analysis.h:29
Thresholds to tune inline cost analysis.
Definition InlineCost.h:207