LLVM 18.0.0git
MLInlineAdvisor.cpp
Go to the documentation of this file.
1//===- MLInlineAdvisor.cpp - machine learned InlineAdvisor ----------------===//
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 the interface between the inliner and a learned model.
10// It delegates model evaluation to either the AOT compiled model (the
11// 'release' mode) or a runtime-loaded model (the 'development' case).
12//
13//===----------------------------------------------------------------------===//
28#include "llvm/IR/Dominators.h"
30#include "llvm/IR/PassManager.h"
32
33using namespace llvm;
34
36 "inliner-interactive-channel-base", cl::Hidden,
38 "Base file path for the interactive mode. The incoming filename should "
39 "have the name <inliner-interactive-channel-base>.in, while the "
40 "outgoing name should be <inliner-interactive-channel-base>.out"));
41static const std::string InclDefaultMsg =
42 (Twine("In interactive mode, also send the default policy decision: ") +
44 .str();
45static cl::opt<bool>
46 InteractiveIncludeDefault("inliner-interactive-include-default", cl::Hidden,
48
49#if defined(LLVM_HAVE_TF_AOT_INLINERSIZEMODEL)
50// codegen-ed file
51#include "InlinerSizeModel.h" // NOLINT
52using CompiledModelType = llvm::InlinerSizeModel;
53#else
55#endif
56
57std::unique_ptr<InlineAdvisor>
59 std::function<bool(CallBase &)> GetDefaultAdvice) {
60 if (!llvm::isEmbeddedModelEvaluatorValid<CompiledModelType>() &&
62 return nullptr;
63 std::unique_ptr<MLModelRunner> AOTRunner;
65 AOTRunner = std::make_unique<ReleaseModeModelRunner<CompiledModelType>>(
66 M.getContext(), FeatureMap, DecisionName);
67 else {
68 auto Features = FeatureMap;
70 Features.push_back(DefaultDecisionSpec);
71 AOTRunner = std::make_unique<InteractiveModelRunner>(
72 M.getContext(), Features, InlineDecisionSpec,
75 }
76 return std::make_unique<MLInlineAdvisor>(M, MAM, std::move(AOTRunner),
77 GetDefaultAdvice);
78}
79
80#define DEBUG_TYPE "inline-ml"
81
83 "ml-advisor-size-increase-threshold", cl::Hidden,
84 cl::desc("Maximum factor by which expected native size may increase before "
85 "blocking any further inlining."),
86 cl::init(2.0));
87
89 "ml-advisor-keep-fpi-cache", cl::Hidden,
91 "For test - keep the ML Inline advisor's FunctionPropertiesInfo cache"),
92 cl::init(false));
93
94// clang-format off
95const std::vector<TensorSpec> llvm::FeatureMap{
96#define POPULATE_NAMES(DTYPE, SHAPE, NAME, __) TensorSpec::createSpec<DTYPE>(#NAME, SHAPE),
97// InlineCost features - these must come first
99
100// Non-cost features
102#undef POPULATE_NAMES
103};
104// clang-format on
105
106const char *const llvm::DecisionName = "inlining_decision";
108 TensorSpec::createSpec<int64_t>(DecisionName, {1});
109const char *const llvm::DefaultDecisionName = "inlining_default";
111 TensorSpec::createSpec<int64_t>(DefaultDecisionName, {1});
112const char *const llvm::RewardName = "delta_size";
113
115 if (auto *CS = dyn_cast<CallBase>(&I))
116 if (Function *Callee = CS->getCalledFunction()) {
117 if (!Callee->isDeclaration()) {
118 return CS;
119 }
120 }
121 return nullptr;
122}
123
126 std::unique_ptr<MLModelRunner> Runner,
127 std::function<bool(CallBase &)> GetDefaultAdvice)
129 M, MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager()),
130 ModelRunner(std::move(Runner)), GetDefaultAdvice(GetDefaultAdvice),
131 CG(MAM.getResult<LazyCallGraphAnalysis>(M)),
132 InitialIRSize(getModuleIRSize()), CurrentIRSize(InitialIRSize) {
134 ModelRunner->switchContext("");
135 // Extract the 'call site height' feature - the position of a call site
136 // relative to the farthest statically reachable SCC node. We don't mutate
137 // this value while inlining happens. Empirically, this feature proved
138 // critical in behavioral cloning - i.e. training a model to mimic the manual
139 // heuristic's decisions - and, thus, equally important for training for
140 // improvement.
141 CallGraph CGraph(M);
142 for (auto I = scc_begin(&CGraph); !I.isAtEnd(); ++I) {
143 const std::vector<CallGraphNode *> &CGNodes = *I;
144 unsigned Level = 0;
145 for (auto *CGNode : CGNodes) {
146 Function *F = CGNode->getFunction();
147 if (!F || F->isDeclaration())
148 continue;
149 for (auto &I : instructions(F)) {
150 if (auto *CS = getInlinableCS(I)) {
151 auto *Called = CS->getCalledFunction();
152 auto Pos = FunctionLevels.find(&CG.get(*Called));
153 // In bottom up traversal, an inlinable callee is either in the
154 // same SCC, or to a function in a visited SCC. So not finding its
155 // level means we haven't visited it yet, meaning it's in this SCC.
156 if (Pos == FunctionLevels.end())
157 continue;
158 Level = std::max(Level, Pos->second + 1);
159 }
160 }
161 }
162 for (auto *CGNode : CGNodes) {
163 Function *F = CGNode->getFunction();
164 if (F && !F->isDeclaration())
165 FunctionLevels[&CG.get(*F)] = Level;
166 }
167 }
168 for (auto KVP : FunctionLevels) {
169 AllNodes.insert(KVP.first);
170 EdgeCount += getLocalCalls(KVP.first->getFunction());
171 }
172 NodeCount = AllNodes.size();
173}
174
176 return CG.lookup(F) ? FunctionLevels.at(CG.lookup(F)) : 0;
177}
178
180 if (!LastSCC || ForceStop)
181 return;
182 FPICache.clear();
183 // Function passes executed between InlinerPass runs may have changed the
184 // module-wide features.
185 // The cgscc pass manager rules are such that:
186 // - if a pass leads to merging SCCs, then the pipeline is restarted on the
187 // merged SCC
188 // - if a pass leads to splitting the SCC, then we continue with one of the
189 // splits
190 // This means that the NodesInLastSCC is a superset (not strict) of the nodes
191 // that subsequent passes would have processed
192 // - in addition, if new Nodes were created by a pass (e.g. CoroSplit),
193 // they'd be adjacent to Nodes in the last SCC. So we just need to check the
194 // boundary of Nodes in NodesInLastSCC for Nodes we haven't seen. We don't
195 // care about the nature of the Edge (call or ref).
196 NodeCount -= static_cast<int64_t>(NodesInLastSCC.size());
197 while (!NodesInLastSCC.empty()) {
198 const auto *N = *NodesInLastSCC.begin();
199 NodesInLastSCC.erase(N);
200 // The Function wrapped by N could have been deleted since we last saw it.
201 if (N->isDead()) {
202 assert(!N->getFunction().isDeclaration());
203 continue;
204 }
205 ++NodeCount;
206 EdgeCount += getLocalCalls(N->getFunction());
207 for (const auto &E : *(*N)) {
208 const auto *AdjNode = &E.getNode();
209 assert(!AdjNode->isDead() && !AdjNode->getFunction().isDeclaration());
210 auto I = AllNodes.insert(AdjNode);
211 if (I.second)
212 NodesInLastSCC.insert(AdjNode);
213 }
214 }
215
216 EdgeCount -= EdgesOfLastSeenNodes;
217 EdgesOfLastSeenNodes = 0;
218
219 // (Re)use NodesInLastSCC to remember the nodes in the SCC right now,
220 // in case the SCC is split before onPassExit and some nodes are split out
221 assert(NodesInLastSCC.empty());
222 for (const auto &N : *LastSCC)
223 NodesInLastSCC.insert(&N);
224}
225
227 // No need to keep this around - function passes will invalidate it.
228 if (!KeepFPICache)
229 FPICache.clear();
230 if (!LastSCC || ForceStop)
231 return;
232 // Keep track of the nodes and edges we last saw. Then, in onPassEntry,
233 // we update the node count and edge count from the subset of these nodes that
234 // survived.
235 EdgesOfLastSeenNodes = 0;
236
237 // Check on nodes that were in SCC onPassEntry
238 for (auto I = NodesInLastSCC.begin(); I != NodesInLastSCC.end();) {
239 if ((*I)->isDead())
240 NodesInLastSCC.erase(*I++);
241 else
242 EdgesOfLastSeenNodes += getLocalCalls((*I++)->getFunction());
243 }
244
245 // Check on nodes that may have got added to SCC
246 for (const auto &N : *LastSCC) {
247 assert(!N.isDead());
248 auto I = NodesInLastSCC.insert(&N);
249 if (I.second)
250 EdgesOfLastSeenNodes += getLocalCalls(N.getFunction());
251 }
252 assert(NodeCount >= NodesInLastSCC.size());
253 assert(EdgeCount >= EdgesOfLastSeenNodes);
254}
255
258}
259
260// Update the internal state of the advisor, and force invalidate feature
261// analysis. Currently, we maintain minimal (and very simple) global state - the
262// number of functions and the number of static calls. We also keep track of the
263// total IR size in this module, to stop misbehaving policies at a certain bloat
264// factor (SizeIncreaseThreshold)
266 bool CalleeWasDeleted) {
267 assert(!ForceStop);
268 Function *Caller = Advice.getCaller();
269 Function *Callee = Advice.getCallee();
270 // The caller features aren't valid anymore.
271 {
275 PA.abandon<LoopAnalysis>();
276 FAM.invalidate(*Caller, PA);
277 }
279 int64_t IRSizeAfter =
280 getIRSize(*Caller) + (CalleeWasDeleted ? 0 : Advice.CalleeIRSize);
281 CurrentIRSize += IRSizeAfter - (Advice.CallerIRSize + Advice.CalleeIRSize);
282 if (CurrentIRSize > SizeIncreaseThreshold * InitialIRSize)
283 ForceStop = true;
284
285 // We can delta-update module-wide features. We know the inlining only changed
286 // the caller, and maybe the callee (by deleting the latter).
287 // Nodes are simple to update.
288 // For edges, we 'forget' the edges that the caller and callee used to have
289 // before inlining, and add back what they currently have together.
290 int64_t NewCallerAndCalleeEdges =
292
293 if (CalleeWasDeleted)
294 --NodeCount;
295 else
296 NewCallerAndCalleeEdges +=
298 EdgeCount += (NewCallerAndCalleeEdges - Advice.CallerAndCalleeEdges);
299 assert(CurrentIRSize >= 0 && EdgeCount >= 0 && NodeCount >= 0);
300}
301
302int64_t MLInlineAdvisor::getModuleIRSize() const {
303 int64_t Ret = 0;
304 for (auto &F : M)
305 if (!F.isDeclaration())
306 Ret += getIRSize(F);
307 return Ret;
308}
309
311 auto InsertPair =
312 FPICache.insert(std::make_pair(&F, FunctionPropertiesInfo()));
313 if (!InsertPair.second)
314 return InsertPair.first->second;
315 InsertPair.first->second = FAM.getResult<FunctionPropertiesAnalysis>(F);
316 return InsertPair.first->second;
317}
318
319std::unique_ptr<InlineAdvice> MLInlineAdvisor::getAdviceImpl(CallBase &CB) {
320 if (auto Skip = getSkipAdviceIfUnreachableCallsite(CB))
321 return Skip;
322
323 auto &Caller = *CB.getCaller();
324 auto &Callee = *CB.getCalledFunction();
325
326 auto GetAssumptionCache = [&](Function &F) -> AssumptionCache & {
328 };
329 auto &TIR = FAM.getResult<TargetIRAnalysis>(Callee);
331
332 auto MandatoryKind = InlineAdvisor::getMandatoryKind(CB, FAM, ORE);
333 // If this is a "never inline" case, there won't be any changes to internal
334 // state we need to track, so we can just return the base InlineAdvice, which
335 // will do nothing interesting.
336 // Same thing if this is a recursive case.
337 if (MandatoryKind == InlineAdvisor::MandatoryInliningKind::Never ||
338 &Caller == &Callee)
339 return getMandatoryAdvice(CB, false);
340
341 bool Mandatory =
343
344 // If we need to stop, we won't want to track anymore any state changes, so
345 // we just return the base InlineAdvice, which acts as a noop.
346 if (ForceStop) {
347 ORE.emit([&] {
348 return OptimizationRemarkMissed(DEBUG_TYPE, "ForceStop", &CB)
349 << "Won't attempt inlining because module size grew too much.";
350 });
351 return std::make_unique<InlineAdvice>(this, CB, ORE, Mandatory);
352 }
353
354 int CostEstimate = 0;
355 if (!Mandatory) {
356 auto IsCallSiteInlinable =
357 llvm::getInliningCostEstimate(CB, TIR, GetAssumptionCache);
358 if (!IsCallSiteInlinable) {
359 // We can't inline this for correctness reasons, so return the base
360 // InlineAdvice, as we don't care about tracking any state changes (which
361 // won't happen).
362 return std::make_unique<InlineAdvice>(this, CB, ORE, false);
363 }
364 CostEstimate = *IsCallSiteInlinable;
365 }
366
367 const auto CostFeatures =
368 llvm::getInliningCostFeatures(CB, TIR, GetAssumptionCache);
369 if (!CostFeatures) {
370 return std::make_unique<InlineAdvice>(this, CB, ORE, false);
371 }
372
373 if (Mandatory)
374 return getMandatoryAdvice(CB, true);
375
376 auto NrCtantParams = 0;
377 for (auto I = CB.arg_begin(), E = CB.arg_end(); I != E; ++I) {
378 NrCtantParams += (isa<Constant>(*I));
379 }
380
381 auto &CallerBefore = getCachedFPI(Caller);
382 auto &CalleeBefore = getCachedFPI(Callee);
383
384 *ModelRunner->getTensor<int64_t>(FeatureIndex::callee_basic_block_count) =
385 CalleeBefore.BasicBlockCount;
386 *ModelRunner->getTensor<int64_t>(FeatureIndex::callsite_height) =
388 *ModelRunner->getTensor<int64_t>(FeatureIndex::node_count) = NodeCount;
389 *ModelRunner->getTensor<int64_t>(FeatureIndex::nr_ctant_params) =
390 NrCtantParams;
391 *ModelRunner->getTensor<int64_t>(FeatureIndex::edge_count) = EdgeCount;
392 *ModelRunner->getTensor<int64_t>(FeatureIndex::caller_users) =
393 CallerBefore.Uses;
394 *ModelRunner->getTensor<int64_t>(
395 FeatureIndex::caller_conditionally_executed_blocks) =
396 CallerBefore.BlocksReachedFromConditionalInstruction;
397 *ModelRunner->getTensor<int64_t>(FeatureIndex::caller_basic_block_count) =
398 CallerBefore.BasicBlockCount;
399 *ModelRunner->getTensor<int64_t>(
400 FeatureIndex::callee_conditionally_executed_blocks) =
401 CalleeBefore.BlocksReachedFromConditionalInstruction;
402 *ModelRunner->getTensor<int64_t>(FeatureIndex::callee_users) =
403 CalleeBefore.Uses;
404 *ModelRunner->getTensor<int64_t>(FeatureIndex::cost_estimate) = CostEstimate;
405
406 // Add the cost features
407 for (size_t I = 0;
408 I < static_cast<size_t>(InlineCostFeatureIndex::NumberOfFeatures); ++I) {
409 *ModelRunner->getTensor<int64_t>(inlineCostFeatureToMlFeature(
410 static_cast<InlineCostFeatureIndex>(I))) = CostFeatures->at(I);
411 }
412 // This one would have been set up to be right at the end.
416 return getAdviceFromModel(CB, ORE);
417}
418
419std::unique_ptr<MLInlineAdvice>
422 return std::make_unique<MLInlineAdvice>(
423 this, CB, ORE, static_cast<bool>(ModelRunner->evaluate<int64_t>()));
424}
425
426std::unique_ptr<InlineAdvice>
427MLInlineAdvisor::getSkipAdviceIfUnreachableCallsite(CallBase &CB) {
429 .isReachableFromEntry(CB.getParent()))
430 return std::make_unique<InlineAdvice>(this, CB, getCallerORE(CB), false);
431 return nullptr;
432}
433
434std::unique_ptr<InlineAdvice> MLInlineAdvisor::getMandatoryAdvice(CallBase &CB,
435 bool Advice) {
436 // Make sure we track inlinings in all cases - mandatory or not.
437 if (auto Skip = getSkipAdviceIfUnreachableCallsite(CB))
438 return Skip;
439 if (Advice && !ForceStop)
440 return getMandatoryAdviceImpl(CB);
441
442 // If this is a "never inline" case, there won't be any changes to internal
443 // state we need to track, so we can just return the base InlineAdvice, which
444 // will do nothing interesting.
445 // Same if we are forced to stop - we don't track anymore.
446 return std::make_unique<InlineAdvice>(this, CB, getCallerORE(CB), Advice);
447}
448
449std::unique_ptr<MLInlineAdvice>
451 return std::make_unique<MLInlineAdvice>(this, CB, getCallerORE(CB), true);
452}
453
454void MLInlineAdvisor::print(raw_ostream &OS) const {
455 OS << "[MLInlineAdvisor] Nodes: " << NodeCount << " Edges: " << EdgeCount
456 << " EdgesOfLastSeenNodes: " << EdgesOfLastSeenNodes << "\n";
457 OS << "[MLInlineAdvisor] FPI:\n";
458 for (auto I : FPICache) {
459 OS << I.first->getName() << ":\n";
460 I.second.print(OS);
461 OS << "\n";
462 }
463 OS << "\n";
464}
465
468 bool Recommendation)
469 : InlineAdvice(Advisor, CB, ORE, Recommendation),
470 CallerIRSize(Advisor->isForcedToStop() ? 0 : Advisor->getIRSize(*Caller)),
471 CalleeIRSize(Advisor->isForcedToStop() ? 0 : Advisor->getIRSize(*Callee)),
472 CallerAndCalleeEdges(Advisor->isForcedToStop()
473 ? 0
474 : (Advisor->getLocalCalls(*Caller) +
475 Advisor->getLocalCalls(*Callee))),
476 PreInlineCallerFPI(Advisor->getCachedFPI(*Caller)) {
477 if (Recommendation)
478 FPU.emplace(Advisor->getCachedFPI(*getCaller()), CB);
479}
480
481void MLInlineAdvice::reportContextForRemark(
483 using namespace ore;
484 OR << NV("Callee", Callee->getName());
485 for (size_t I = 0; I < NumberOfFeatures; ++I)
486 OR << NV(FeatureMap[I].name(),
487 *getAdvisor()->getModelRunner().getTensor<int64_t>(I));
488 OR << NV("ShouldInline", isInliningRecommended());
489}
490
492 FPU->finish(FAM);
493}
494
496 ORE.emit([&]() {
497 OptimizationRemark R(DEBUG_TYPE, "InliningSuccess", DLoc, Block);
498 reportContextForRemark(R);
499 return R;
500 });
501 getAdvisor()->onSuccessfulInlining(*this, /*CalleeWasDeleted*/ false);
502}
503
505 ORE.emit([&]() {
506 OptimizationRemark R(DEBUG_TYPE, "InliningSuccessWithCalleeDeleted", DLoc,
507 Block);
508 reportContextForRemark(R);
509 return R;
510 });
511 getAdvisor()->onSuccessfulInlining(*this, /*CalleeWasDeleted*/ true);
512}
513
515 const InlineResult &Result) {
516 getAdvisor()->getCachedFPI(*Caller) = PreInlineCallerFPI;
517 ORE.emit([&]() {
518 OptimizationRemarkMissed R(DEBUG_TYPE, "InliningAttemptedAndUnsuccessful",
519 DLoc, Block);
520 reportContextForRemark(R);
521 return R;
522 });
523}
525 assert(!FPU);
526 ORE.emit([&]() {
527 OptimizationRemarkMissed R(DEBUG_TYPE, "IniningNotAttempted", DLoc, Block);
528 reportContextForRemark(R);
529 return R;
530 });
531}
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file provides interfaces used to build and manipulate a call graph, which is a very useful tool ...
static Function * getFunction(Constant *C)
Definition: Evaluator.cpp:236
#define DEBUG_TYPE
#define INLINE_COST_FEATURE_ITERATOR(M)
#define INLINE_FEATURE_ITERATOR(M)
Select target instructions out of generic instructions
Implements a lazy call graph analysis and related passes for the new pass manager.
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
static cl::opt< bool > KeepFPICache("ml-advisor-keep-fpi-cache", cl::Hidden, cl::desc("For test - keep the ML Inline advisor's FunctionPropertiesInfo cache"), cl::init(false))
CallBase * getInlinableCS(Instruction &I)
static cl::opt< std::string > InteractiveChannelBaseName("inliner-interactive-channel-base", cl::Hidden, cl::desc("Base file path for the interactive mode. The incoming filename should " "have the name <inliner-interactive-channel-base>.in, while the " "outgoing name should be <inliner-interactive-channel-base>.out"))
#define POPULATE_NAMES(DTYPE, SHAPE, NAME, __)
static cl::opt< float > SizeIncreaseThreshold("ml-advisor-size-increase-threshold", cl::Hidden, cl::desc("Maximum factor by which expected native size may increase before " "blocking any further inlining."), cl::init(2.0))
static const std::string InclDefaultMsg
static cl::opt< bool > InteractiveIncludeDefault("inliner-interactive-include-default", cl::Hidden, cl::desc(InclDefaultMsg))
#define DecisionName
if(VerifyEach)
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
This header defines various interfaces for pass management in LLVM.
This builds on the llvm/ADT/GraphTraits.h file to find the strongly connected components (SCCs) of a ...
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static const char * name
Definition: SMEABIPass.cpp:49
raw_pwrite_stream & OS
This pass exposes codegen information to IR-level passes.
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:620
void invalidate(IRUnitT &IR, const PreservedAnalyses &PA)
Invalidate cached analyses for an IR unit.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Definition: PassManager.h:774
A function analysis which provides an AssumptionCache.
A cache of @llvm.assume calls within a function.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
Definition: InstrTypes.h:1190
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
Definition: InstrTypes.h:1412
User::op_iterator arg_begin()
Return the iterator pointing to the beginning of the argument list.
Definition: InstrTypes.h:1332
User::op_iterator arg_end()
Return the iterator pointing to the end of the argument list.
Definition: InstrTypes.h:1338
Function * getCaller()
Helper to get the caller (the parent function).
The basic data container for the call graph of a Module of IR.
Definition: CallGraph.h:72
Common features for diagnostics dealing with optimization remarks that are used by both IR and MIR pa...
Analysis pass which computes a DominatorTree.
Definition: Dominators.h:279
int64_t DirectCallsToDefinedFunctions
Number of direct calls made from this function to other functions defined in this module.
Capture state between an inlining decision having had been made, and its impact being observable.
Definition: InlineAdvisor.h:76
Function *const Callee
Function *const Caller
Caller and Callee are pre-inlining.
const BasicBlock *const Block
OptimizationRemarkEmitter & ORE
InlineAdvisor *const Advisor
const DebugLoc DLoc
bool isInliningRecommended() const
Get the inlining recommendation.
Interface for deciding whether to inline a call site or not.
OptimizationRemarkEmitter & getCallerORE(CallBase &CB)
FunctionAnalysisManager & FAM
static MandatoryInliningKind getMandatoryKind(CallBase &CB, FunctionAnalysisManager &FAM, OptimizationRemarkEmitter &ORE)
InlineResult is basically true or false.
Definition: InlineCost.h:179
An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...
Definition: PassManager.h:933
const BasicBlock * getParent() const
Definition: Instruction.h:90
An analysis pass which computes the call graph for a module.
An SCC of the call graph.
Node & get(Function &F)
Get a graph node for a given function, scanning it to populate the graph data as necessary.
Node * lookup(const Function &F) const
Lookup a function in the graph which has already been scanned and added.
Analysis pass that exposes the LoopInfo for a function.
Definition: LoopInfo.h:569
InlineAdvice that tracks changes post inlining.
void updateCachedCallerFPI(FunctionAnalysisManager &FAM) const
const int64_t CallerIRSize
MLInlineAdvice(MLInlineAdvisor *Advisor, CallBase &CB, OptimizationRemarkEmitter &ORE, bool Recommendation)
const int64_t CalleeIRSize
void recordInliningImpl() override
Function * getCaller() const
const int64_t CallerAndCalleeEdges
void recordUnsuccessfulInliningImpl(const InlineResult &Result) override
Function * getCallee() const
void recordInliningWithCalleeDeletedImpl() override
void recordUnattemptedInliningImpl() override
std::unique_ptr< MLModelRunner > ModelRunner
FunctionPropertiesInfo & getCachedFPI(Function &) const
void onPassExit(LazyCallGraph::SCC *SCC) override
This must be called when the Inliner pass is exited, as function passes may be run subsequently.
MLInlineAdvisor(Module &M, ModuleAnalysisManager &MAM, std::unique_ptr< MLModelRunner > ModelRunner, std::function< bool(CallBase &)> GetDefaultAdvice)
void onSuccessfulInlining(const MLInlineAdvice &Advice, bool CalleeWasDeleted)
virtual std::unique_ptr< MLInlineAdvice > getMandatoryAdviceImpl(CallBase &CB)
void onPassEntry(LazyCallGraph::SCC *SCC) override
This must be called when the Inliner pass is entered, to allow the InlineAdvisor update internal stat...
int64_t getLocalCalls(Function &F)
virtual std::unique_ptr< MLInlineAdvice > getAdviceFromModel(CallBase &CB, OptimizationRemarkEmitter &ORE)
int64_t getIRSize(Function &F) const
std::function< bool(CallBase &)> GetDefaultAdvice
std::unique_ptr< InlineAdvice > getAdviceImpl(CallBase &CB) override
std::unique_ptr< InlineAdvice > getMandatoryAdvice(CallBase &CB, bool Advice) override
unsigned getInitialFunctionLevel(const Function &F) const
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
A mock class satisfying the interface expected by ReleaseModeModelRunner for its TGen parameter.
The optimization diagnostic interface.
void emit(DiagnosticInfoOptimizationBase &OptDiag)
Output the remark via the diagnostic handler and to the optimization record file.
Diagnostic information for missed-optimization remarks.
Diagnostic information for applied optimization remarks.
A set of analyses that are preserved following a run of a transformation pass.
Definition: PassManager.h:152
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: PassManager.h:158
void abandon()
Mark an analysis as abandoned.
Definition: PassManager.h:206
Analysis pass providing the TargetTransformInfo.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
StringRef getName() const
Return a constant reference to the value's name.
Definition: Value.cpp:309
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:445
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
constexpr FeatureIndex inlineCostFeatureToMlFeature(InlineCostFeatureIndex Feature)
const char *const DefaultDecisionName
constexpr size_t NumberOfFeatures
std::optional< InlineCostFeatures > getInliningCostFeatures(CallBase &Call, TargetTransformInfo &CalleeTTI, function_ref< AssumptionCache &(Function &)> GetAssumptionCache, function_ref< BlockFrequencyInfo &(Function &)> GetBFI=nullptr, ProfileSummaryInfo *PSI=nullptr, OptimizationRemarkEmitter *ORE=nullptr)
Get the expanded cost features.
scc_iterator< T > scc_begin(const T &G)
Construct the begin iterator for a deduced graph type T.
Definition: SCCIterator.h:233
std::unique_ptr< InlineAdvisor > getReleaseModeAdvisor(Module &M, ModuleAnalysisManager &MAM, std::function< bool(CallBase &)> GetDefaultAdvice)
const TensorSpec DefaultDecisionSpec
const char *const DecisionName
const std::vector< TensorSpec > FeatureMap
const TensorSpec InlineDecisionSpec
const char *const RewardName
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1854
std::optional< int > getInliningCostEstimate(CallBase &Call, TargetTransformInfo &CalleeTTI, function_ref< AssumptionCache &(Function &)> GetAssumptionCache, function_ref< BlockFrequencyInfo &(Function &)> GetBFI=nullptr, ProfileSummaryInfo *PSI=nullptr, OptimizationRemarkEmitter *ORE=nullptr)
Get the cost estimate ignoring thresholds.
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
#define N