39 "inliner-interactive-channel-base",
cl::Hidden,
41 "Base file path for the interactive mode. The incoming filename should "
42 "have the name <inliner-interactive-channel-base>.in, while the "
43 "outgoing name should be <inliner-interactive-channel-base>.out"));
45 (
Twine(
"In interactive mode, also send the default policy decision: ") +
58 "if-caller-not-cold",
"if the caller is not cold")));
63#if defined(LLVM_HAVE_TF_AOT_INLINERSIZEMODEL)
65#include "InlinerSizeModel.h"
71std::unique_ptr<InlineAdvisor>
73 std::function<
bool(
CallBase &)> GetDefaultAdvice) {
74 if (!llvm::isEmbeddedModelEvaluatorValid<CompiledModelType>() &&
77 std::unique_ptr<MLModelRunner> AOTRunner;
79 AOTRunner = std::make_unique<ReleaseModeModelRunner<CompiledModelType>>(
86 AOTRunner = std::make_unique<InteractiveModelRunner>(
91 return std::make_unique<MLInlineAdvisor>(M,
MAM, std::move(AOTRunner),
95#define DEBUG_TYPE "inline-ml"
98 "ml-advisor-size-increase-threshold",
cl::Hidden,
99 cl::desc(
"Maximum factor by which expected native size may increase before "
100 "blocking any further inlining."),
106 "For test - keep the ML Inline advisor's FunctionPropertiesInfo cache"),
111#define POPULATE_NAMES(DTYPE, SHAPE, NAME, __) TensorSpec::createSpec<DTYPE>(#NAME, SHAPE),
130 if (
auto *CS = dyn_cast<CallBase>(&
I))
131 if (
Function *Callee = CS->getCalledFunction()) {
132 if (!Callee->isDeclaration()) {
141 std::unique_ptr<MLModelRunner> Runner,
142 std::function<
bool(
CallBase &)> GetDefaultAdvice)
145 ModelRunner(
std::
move(Runner)), GetDefaultAdvice(GetDefaultAdvice),
147 InitialIRSize(getModuleIRSize()), CurrentIRSize(InitialIRSize),
159 const std::vector<CallGraphNode *> &CGNodes = *
I;
161 for (
auto *CGNode : CGNodes) {
163 if (!
F ||
F->isDeclaration())
167 auto *Called = CS->getCalledFunction();
168 auto Pos = FunctionLevels.find(&CG.
get(*Called));
172 if (Pos == FunctionLevels.end())
174 Level = std::max(Level, Pos->second + 1);
178 for (
auto *CGNode : CGNodes) {
180 if (
F && !
F->isDeclaration())
181 FunctionLevels[&CG.
get(*
F)] = Level;
184 for (
auto KVP : FunctionLevels) {
185 AllNodes.insert(KVP.first);
188 NodeCount = AllNodes.size();
196 if (!CurSCC || ForceStop)
216 while (!NodesInLastSCC.empty()) {
217 const auto *
N = *NodesInLastSCC.begin();
219 NodesInLastSCC.erase(
N);
221 const auto NLevel = FunctionLevels.at(
N);
222 for (
const auto &E : *(*
N)) {
223 const auto *AdjNode = &E.getNode();
224 assert(!AdjNode->isDead() && !AdjNode->getFunction().isDeclaration());
225 auto I = AllNodes.insert(AdjNode);
229 NodesInLastSCC.insert(AdjNode);
230 FunctionLevels[AdjNode] = NLevel;
235 EdgeCount -= EdgesOfLastSeenNodes;
236 EdgesOfLastSeenNodes = 0;
240 assert(NodesInLastSCC.empty());
241 for (
const auto &
N : *CurSCC)
242 NodesInLastSCC.insert(&
N);
249 if (!CurSCC || ForceStop)
254 EdgesOfLastSeenNodes = 0;
263 for (
const auto &
N : *CurSCC) {
265 auto I = NodesInLastSCC.insert(&
N);
269 assert(NodeCount >= NodesInLastSCC.size());
270 assert(EdgeCount >= EdgesOfLastSeenNodes);
283 bool CalleeWasDeleted) {
295 int64_t IRSizeAfter =
306 int64_t NewCallerAndCalleeEdges =
312 if (CalleeWasDeleted) {
314 NodesInLastSCC.erase(CG.
lookup(*Callee));
315 DeadFunctions.
insert(Callee);
317 NewCallerAndCalleeEdges +=
321 assert(CurrentIRSize >= 0 && EdgeCount >= 0 && NodeCount >= 0);
324int64_t MLInlineAdvisor::getModuleIRSize()
const {
327 if (!
F.isDeclaration())
335 if (!InsertPair.second)
336 return InsertPair.first->second;
338 return InsertPair.first->second;
342 if (
auto Skip = getSkipAdviceIfUnreachableCallsite(CB))
354 if (
SkipPolicy == SkipMLPolicyCriteria::IfCallerIsNotCold) {
356 return std::make_unique<InlineAdvice>(
this, CB, ORE,
376 <<
"Won't attempt inlining because module size grew too much.";
378 return std::make_unique<InlineAdvice>(
this, CB, ORE, Mandatory);
381 int CostEstimate = 0;
383 auto IsCallSiteInlinable =
385 if (!IsCallSiteInlinable) {
389 return std::make_unique<InlineAdvice>(
this, CB, ORE,
false);
391 CostEstimate = *IsCallSiteInlinable;
394 const auto CostFeatures =
397 return std::make_unique<InlineAdvice>(
this, CB, ORE,
false);
403 auto NumCtantParams = 0;
405 NumCtantParams += (isa<Constant>(*
I));
411 *
ModelRunner->getTensor<int64_t>(FeatureIndex::callee_basic_block_count) =
412 CalleeBefore.BasicBlockCount;
413 *
ModelRunner->getTensor<int64_t>(FeatureIndex::callsite_height) =
415 *
ModelRunner->getTensor<int64_t>(FeatureIndex::node_count) = NodeCount;
416 *
ModelRunner->getTensor<int64_t>(FeatureIndex::nr_ctant_params) =
418 *
ModelRunner->getTensor<int64_t>(FeatureIndex::edge_count) = EdgeCount;
419 *
ModelRunner->getTensor<int64_t>(FeatureIndex::caller_users) =
422 FeatureIndex::caller_conditionally_executed_blocks) =
423 CallerBefore.BlocksReachedFromConditionalInstruction;
424 *
ModelRunner->getTensor<int64_t>(FeatureIndex::caller_basic_block_count) =
425 CallerBefore.BasicBlockCount;
427 FeatureIndex::callee_conditionally_executed_blocks) =
428 CalleeBefore.BlocksReachedFromConditionalInstruction;
429 *
ModelRunner->getTensor<int64_t>(FeatureIndex::callee_users) =
431 *
ModelRunner->getTensor<int64_t>(FeatureIndex::cost_estimate) = CostEstimate;
432 *
ModelRunner->getTensor<int64_t>(FeatureIndex::is_callee_avail_external) =
433 Callee.hasAvailableExternallyLinkage();
434 *
ModelRunner->getTensor<int64_t>(FeatureIndex::is_caller_avail_external) =
435 Caller.hasAvailableExternallyLinkage();
450std::unique_ptr<MLInlineAdvice>
453 return std::make_unique<MLInlineAdvice>(
454 this, CB, ORE,
static_cast<bool>(
ModelRunner->evaluate<int64_t>()));
457std::unique_ptr<InlineAdvice>
458MLInlineAdvisor::getSkipAdviceIfUnreachableCallsite(
CallBase &CB) {
461 return std::make_unique<InlineAdvice>(
this, CB,
getCallerORE(CB),
false);
468 if (
auto Skip = getSkipAdviceIfUnreachableCallsite(CB))
470 if (Advice && !ForceStop)
477 return std::make_unique<InlineAdvice>(
this, CB,
getCallerORE(CB), Advice);
480std::unique_ptr<MLInlineAdvice>
482 return std::make_unique<MLInlineAdvice>(
this, CB,
getCallerORE(CB),
true);
486 OS <<
"[MLInlineAdvisor] Nodes: " << NodeCount <<
" Edges: " << EdgeCount
487 <<
" EdgesOfLastSeenNodes: " << EdgesOfLastSeenNodes <<
"\n";
488 OS <<
"[MLInlineAdvisor] FPI:\n";
489 for (
auto I : FPICache) {
490 OS <<
I.first->getName() <<
":\n";
495 OS <<
"[MLInlineAdvisor] FuncLevels:\n";
496 for (
auto I : FunctionLevels)
497 OS << (DeadFunctions.
contains(&
I.first->getFunction())
499 :
I.first->getFunction().getName())
500 <<
" : " <<
I.second <<
"\n";
509 CallerIRSize(Advisor->isForcedToStop() ? 0 : Advisor->getIRSize(*Caller)),
510 CalleeIRSize(Advisor->isForcedToStop() ? 0 : Advisor->getIRSize(*Callee)),
511 CallerAndCalleeEdges(Advisor->isForcedToStop()
513 : (Advisor->getLocalCalls(*Caller) +
514 Advisor->getLocalCalls(*Callee))),
515 PreInlineCallerFPI(Advisor->getCachedFPI(*Caller)) {
520void MLInlineAdvice::reportContextForRemark(
526 *getAdvisor()->getModelRunner().getTensor<int64_t>(
I));
537 reportContextForRemark(R);
547 reportContextForRemark(R);
559 reportContextForRemark(R);
567 reportContextForRemark(R);
Expand Atomic instructions
This file provides interfaces used to build and manipulate a call graph, which is a very useful tool ...
#define clEnumValN(ENUMVAL, FLAGNAME, DESC)
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
#define INLINE_COST_FEATURE_ITERATOR(M)
#define INLINE_FEATURE_ITERATOR(M)
Implements a lazy call graph analysis and related passes for the new pass manager.
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))
static cl::opt< std::string > ModelSelector("ml-inliner-model-selector", cl::Hidden, cl::init(""))
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< SkipMLPolicyCriteria > SkipPolicy("ml-inliner-skip-policy", cl::Hidden, cl::init(SkipMLPolicyCriteria::Never), cl::values(clEnumValN(SkipMLPolicyCriteria::Never, "never", "never"), clEnumValN(SkipMLPolicyCriteria::IfCallerIsNotCold, "if-caller-not-cold", "if the caller is not cold")))
static cl::opt< bool > InteractiveIncludeDefault("inliner-interactive-include-default", cl::Hidden, cl::desc(InclDefaultMsg))
FunctionAnalysisManager FAM
ModuleAnalysisManager MAM
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())
A container for analyses that lazily runs them and caches their results.
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.
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...
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
User::op_iterator arg_begin()
Return the iterator pointing to the beginning of the argument list.
User::op_iterator arg_end()
Return the iterator pointing to the end of the argument list.
Function * getCaller()
Helper to get the caller (the parent function).
The basic data container for the call graph of a Module of IR.
Common features for diagnostics dealing with optimization remarks that are used by both IR and MIR pa...
Analysis pass which computes a DominatorTree.
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.
Function *const Caller
Caller and Callee are pre-inlining.
const BasicBlock *const Block
OptimizationRemarkEmitter & ORE
InlineAdvisor *const Advisor
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.
An analysis over an "outer" IR unit that provides access to an analysis manager over an "inner" IR un...
An analysis pass which computes the call graph for a module.
A node in the call graph.
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.
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.
A mock class satisfying the interface expected by ReleaseModeModelRunner for its TGen parameter.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
void abandon()
Mark an analysis as abandoned.
An analysis pass based on the new PM to deliver ProfileSummaryInfo.
bool isFunctionEntryCold(const Function *F) const
Returns true if F has cold function entry.
Analysis pass providing the TargetTransformInfo.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
StringRef getName() const
Return a constant reference to the value's name.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
const ParentTy * getParent() const
This class implements an extremely fast bulk output stream that can only output to a stream.
ValuesClass values(OptsTy... Options)
Helper to build a ValuesClass by forwarding a variable number of arguments as an initializer list to ...
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
constexpr FeatureIndex inlineCostFeatureToMlFeature(InlineCostFeatureIndex Feature)
const char *const DefaultDecisionName
constexpr size_t NumberOfFeatures
scc_iterator< T > scc_begin(const T &G)
Construct the begin iterator for a deduced graph type T.
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
std::optional< InlineCostFeatures > getInliningCostFeatures(CallBase &Call, TargetTransformInfo &CalleeTTI, function_ref< AssumptionCache &(Function &)> GetAssumptionCache, function_ref< BlockFrequencyInfo &(Function &)> GetBFI=nullptr, function_ref< const TargetLibraryInfo &(Function &)> GetTLI=nullptr, ProfileSummaryInfo *PSI=nullptr, OptimizationRemarkEmitter *ORE=nullptr)
Get the expanded cost features.
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.
std::optional< int > getInliningCostEstimate(CallBase &Call, TargetTransformInfo &CalleeTTI, function_ref< AssumptionCache &(Function &)> GetAssumptionCache, function_ref< BlockFrequencyInfo &(Function &)> GetBFI=nullptr, function_ref< const TargetLibraryInfo &(Function &)> GetTLI=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.
ReleaseModeModelRunner - production mode implementation of the MLModelRunner.
EmbeddedModelRunnerOptions & setModelSelector(StringRef Value)