40 "inliner-interactive-channel-base",
cl::Hidden,
42 "Base file path for the interactive mode. The incoming filename should "
43 "have the name <inliner-interactive-channel-base>.in, while the "
44 "outgoing name should be <inliner-interactive-channel-base>.out"));
46 (
Twine(
"In interactive mode, also send the default policy decision: ") +
59 "if-caller-not-cold",
"if the caller is not cold")));
64#if defined(LLVM_HAVE_TF_AOT_INLINERSIZEMODEL)
66#include "InlinerSizeModel.h"
72std::unique_ptr<InlineAdvisor>
74 std::function<
bool(
CallBase &)> GetDefaultAdvice) {
75 if (!llvm::isEmbeddedModelEvaluatorValid<CompiledModelType>() &&
78 auto RunnerFactory = [&](
const std::vector<TensorSpec> &
InputFeatures)
79 -> std::unique_ptr<MLModelRunner> {
80 std::unique_ptr<MLModelRunner> AOTRunner;
86 AOTRunner = std::make_unique<InteractiveModelRunner>(
93 return std::make_unique<MLInlineAdvisor>(M,
MAM, RunnerFactory,
97#define DEBUG_TYPE "inline-ml"
100 "ml-advisor-size-increase-threshold",
cl::Hidden,
101 cl::desc(
"Maximum factor by which expected native size may increase before "
102 "blocking any further inlining."),
108 "For test - keep the ML Inline advisor's FunctionPropertiesInfo cache"),
114#define POPULATE_NAMES(DTYPE, SHAPE, NAME, __) TensorSpec::createSpec<DTYPE>(#NAME, SHAPE),
135 if (
auto *CS = dyn_cast<CallBase>(&
I))
136 if (
Function *Callee = CS->getCalledFunction()) {
137 if (!Callee->isDeclaration()) {
147 std::unique_ptr<MLModelRunner>(
const std::vector<TensorSpec> &)>
149 std::function<
bool(
CallBase &)> GetDefaultAdvice)
152 GetDefaultAdvice(GetDefaultAdvice), FeatureMap(getInitialFeatureMap()),
155 InitialIRSize(getModuleIRSize()), CurrentIRSize(InitialIRSize),
165 const std::vector<CallGraphNode *> &CGNodes = *
I;
167 for (
auto *CGNode : CGNodes) {
169 if (!
F ||
F->isDeclaration())
173 auto *Called = CS->getCalledFunction();
174 auto Pos = FunctionLevels.find(&CG.
get(*Called));
178 if (Pos == FunctionLevels.end())
180 Level = std::max(Level, Pos->second + 1);
184 for (
auto *CGNode : CGNodes) {
186 if (
F && !
F->isDeclaration())
187 FunctionLevels[&CG.
get(*
F)] = Level;
190 for (
auto KVP : FunctionLevels) {
191 AllNodes.insert(KVP.first);
194 NodeCount = AllNodes.size();
197 if (!IR2VecVocabResult->isValid()) {
202 auto IR2VecDim = IR2VecVocabResult->getDimension();
204 TensorSpec::createSpec<float>(
"callee_embedding", {IR2VecDim}));
206 TensorSpec::createSpec<float>(
"caller_embedding", {IR2VecDim}));
224 if (!CurSCC || ForceStop)
244 while (!NodesInLastSCC.empty()) {
245 const auto *
N = *NodesInLastSCC.begin();
247 NodesInLastSCC.erase(
N);
249 const auto NLevel = FunctionLevels.at(
N);
250 for (
const auto &E : *(*
N)) {
251 const auto *AdjNode = &E.getNode();
252 assert(!AdjNode->isDead() && !AdjNode->getFunction().isDeclaration());
253 auto I = AllNodes.insert(AdjNode);
257 NodesInLastSCC.insert(AdjNode);
258 FunctionLevels[AdjNode] = NLevel;
263 EdgeCount -= EdgesOfLastSeenNodes;
264 EdgesOfLastSeenNodes = 0;
268 assert(NodesInLastSCC.empty());
269 for (
const auto &
N : *CurSCC)
270 NodesInLastSCC.insert(&
N);
277 if (!CurSCC || ForceStop)
282 EdgesOfLastSeenNodes = 0;
291 for (
const auto &
N : *CurSCC) {
293 auto I = NodesInLastSCC.insert(&
N);
297 assert(NodeCount >= NodesInLastSCC.size());
298 assert(EdgeCount >= EdgesOfLastSeenNodes);
311 bool CalleeWasDeleted) {
323 int64_t IRSizeAfter =
334 int64_t NewCallerAndCalleeEdges =
340 if (CalleeWasDeleted) {
342 NodesInLastSCC.erase(CG.
lookup(*Callee));
343 DeadFunctions.
insert(Callee);
345 NewCallerAndCalleeEdges +=
349 assert(CurrentIRSize >= 0 && EdgeCount >= 0 && NodeCount >= 0);
352int64_t MLInlineAdvisor::getModuleIRSize()
const {
355 if (!
F.isDeclaration())
361 auto InsertPair = FPICache.try_emplace(&
F);
362 if (!InsertPair.second)
363 return InsertPair.first->second;
365 return InsertPair.first->second;
369 if (
auto Skip = getSkipAdviceIfUnreachableCallsite(CB))
381 if (
SkipPolicy == SkipMLPolicyCriteria::IfCallerIsNotCold) {
383 return std::make_unique<InlineAdvice>(
this, CB, ORE,
403 <<
"Won't attempt inlining because module size grew too much.";
405 return std::make_unique<InlineAdvice>(
this, CB, ORE, Mandatory);
408 int CostEstimate = 0;
410 auto IsCallSiteInlinable =
412 if (!IsCallSiteInlinable) {
416 return std::make_unique<InlineAdvice>(
this, CB, ORE,
false);
418 CostEstimate = *IsCallSiteInlinable;
421 const auto CostFeatures =
424 return std::make_unique<InlineAdvice>(
this, CB, ORE,
false);
430 auto NumCtantParams = 0;
432 NumCtantParams += (isa<Constant>(*
I));
438 *
ModelRunner->getTensor<int64_t>(FeatureIndex::callee_basic_block_count) =
439 CalleeBefore.BasicBlockCount;
440 *
ModelRunner->getTensor<int64_t>(FeatureIndex::callsite_height) =
442 *
ModelRunner->getTensor<int64_t>(FeatureIndex::node_count) = NodeCount;
443 *
ModelRunner->getTensor<int64_t>(FeatureIndex::nr_ctant_params) =
445 *
ModelRunner->getTensor<int64_t>(FeatureIndex::edge_count) = EdgeCount;
446 *
ModelRunner->getTensor<int64_t>(FeatureIndex::caller_users) =
449 FeatureIndex::caller_conditionally_executed_blocks) =
450 CallerBefore.BlocksReachedFromConditionalInstruction;
451 *
ModelRunner->getTensor<int64_t>(FeatureIndex::caller_basic_block_count) =
452 CallerBefore.BasicBlockCount;
454 FeatureIndex::callee_conditionally_executed_blocks) =
455 CalleeBefore.BlocksReachedFromConditionalInstruction;
456 *
ModelRunner->getTensor<int64_t>(FeatureIndex::callee_users) =
458 *
ModelRunner->getTensor<int64_t>(FeatureIndex::cost_estimate) = CostEstimate;
459 *
ModelRunner->getTensor<int64_t>(FeatureIndex::is_callee_avail_external) =
460 Callee.hasAvailableExternallyLinkage();
461 *
ModelRunner->getTensor<int64_t>(FeatureIndex::is_caller_avail_external) =
462 Caller.hasAvailableExternallyLinkage();
471 [](
double Val) { return static_cast<float>(Val); });
474 setEmbedding(CalleeBefore.getFunctionEmbedding(),
476 setEmbedding(CallerBefore.getFunctionEmbedding(),
493std::unique_ptr<MLInlineAdvice>
496 return std::make_unique<MLInlineAdvice>(
497 this, CB, ORE,
static_cast<bool>(
ModelRunner->evaluate<int64_t>()));
500std::unique_ptr<InlineAdvice>
501MLInlineAdvisor::getSkipAdviceIfUnreachableCallsite(
CallBase &CB) {
504 return std::make_unique<InlineAdvice>(
this, CB,
getCallerORE(CB),
false);
511 if (
auto Skip = getSkipAdviceIfUnreachableCallsite(CB))
513 if (Advice && !ForceStop)
520 return std::make_unique<InlineAdvice>(
this, CB,
getCallerORE(CB), Advice);
523std::unique_ptr<MLInlineAdvice>
525 return std::make_unique<MLInlineAdvice>(
this, CB,
getCallerORE(CB),
true);
529 OS <<
"[MLInlineAdvisor] Nodes: " << NodeCount <<
" Edges: " << EdgeCount
530 <<
" EdgesOfLastSeenNodes: " << EdgesOfLastSeenNodes <<
"\n";
531 OS <<
"[MLInlineAdvisor] FPI:\n";
532 for (
auto I : FPICache) {
533 OS <<
I.first->getName() <<
":\n";
538 OS <<
"[MLInlineAdvisor] FuncLevels:\n";
539 for (
auto I : FunctionLevels)
540 OS << (DeadFunctions.
contains(&
I.first->getFunction())
542 :
I.first->getFunction().getName())
543 <<
" : " <<
I.second <<
"\n";
552 CallerIRSize(Advisor->isForcedToStop() ? 0 : Advisor->getIRSize(*Caller)),
553 CalleeIRSize(Advisor->isForcedToStop() ? 0 : Advisor->getIRSize(*Callee)),
554 CallerAndCalleeEdges(Advisor->isForcedToStop()
556 : (Advisor->getLocalCalls(*Caller) +
557 Advisor->getLocalCalls(*Callee))),
558 PreInlineCallerFPI(Advisor->getCachedFPI(*Caller)) {
563void MLInlineAdvice::reportContextForRemark(
580 reportContextForRemark(R);
590 reportContextForRemark(R);
602 reportContextForRemark(R);
610 reportContextForRemark(R);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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 ...
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 * getCachedResult(IRUnitT &IR) const
Get the cached result of an analysis pass for a given 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.
LLVM_ABI 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.
This analysis provides the vocabulary for IR2Vec.
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...
LLVM_ABI void emitError(const Instruction *I, const Twine &ErrorStr)
emitError - Emit an error message to the currently installed error handler with optional location inf...
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
const std::vector< TensorSpec > & getFeatureMap() const
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.
const MLModelRunner & getModelRunner() const
void onSuccessfulInlining(const MLInlineAdvice &Advice, bool CalleeWasDeleted)
static const std::vector< TensorSpec > & getInitialFeatureMap()
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...
MLInlineAdvisor(Module &M, ModuleAnalysisManager &MAM, std::function< std::unique_ptr< MLModelRunner >(const std::vector< TensorSpec > &)> GetModelRunner, std::function< bool(CallBase &)> GetDefaultAdvice)
int64_t getLocalCalls(Function &F)
std::vector< TensorSpec > FeatureMap
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
T * getTensor(I FeatureID)
A Module instance is used to store all the information related to an LLVM module.
LLVMContext & getContext() const
Get the global data context.
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.
PreservedAnalyses & abandon()
Mark an analysis as abandoned.
An analysis pass based on the new PM to deliver ProfileSummaryInfo.
LLVM_ABI 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...
LLVM_ABI 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)
LLVM_ABI const char *const DefaultDecisionName
scc_iterator< T > scc_begin(const T &G)
Construct the begin iterator for a deduced graph type T.
LLVM_ABI std::unique_ptr< InlineAdvisor > getReleaseModeAdvisor(Module &M, ModuleAnalysisManager &MAM, std::function< bool(CallBase &)> GetDefaultAdvice)
OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere.
LLVM_ABI const TensorSpec DefaultDecisionSpec
LLVM_ABI const char *const DecisionName
static const std::vector< TensorSpec > InputFeatures
LLVM_ABI 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.
LLVM_ABI const TensorSpec InlineDecisionSpec
LLVM_ABI const char *const RewardName
LLVM_ABI 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.
ReleaseModeModelRunner - production mode implementation of the MLModelRunner.
EmbeddedModelRunnerOptions & setModelSelector(StringRef Value)
Embedding is a datatype that wraps std::vector<double>.