//===- InlineAdvisor.h - Inlining decision making abstraction -*- C++ ---*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // #ifndef LLVM_ANALYSIS_INLINEADVISOR_H #define LLVM_ANALYSIS_INLINEADVISOR_H #include "llvm/Analysis/CGSCCPassManager.h" #include "llvm/Analysis/InlineCost.h" #include "llvm/Analysis/LazyCallGraph.h" #include "llvm/IR/PassManager.h" #include <memory> namespace llvm { class BasicBlock; class CallBase; class Function; class Module; class OptimizationRemark; class ImportedFunctionsInliningStatistics; class OptimizationRemarkEmitter; struct ReplayInlinerSettings; /// There are 4 scenarios we can use the InlineAdvisor: /// - Default - use manual heuristics. /// /// - Release mode, the expected mode for production, day to day deployments. /// In this mode, when building the compiler, we also compile a pre-trained ML /// model to native code, and link it as a static library. This mode has low /// overhead and no additional dependencies for the compiler runtime. /// /// - Development mode, for training new models. /// In this mode, we trade off runtime performance for flexibility. This mode /// requires the TFLite library, and evaluates models dynamically. This mode /// also permits generating training logs, for offline training. /// /// - Dynamically load an advisor via a plugin (PluginInlineAdvisorAnalysis) enum class InliningAdvisorMode : int { … }; // Each entry represents an inline driver. enum class InlinePass : int { … }; /// Provides context on when an inline advisor is constructed in the pipeline /// (e.g., link phase, inline driver). struct InlineContext { … }; std::string AnnotateInlinePassName(InlineContext IC); class InlineAdvisor; /// Capture state between an inlining decision having had been made, and /// its impact being observable. When collecting model training data, this /// allows recording features/decisions/partial reward data sets. /// /// Derivations of this type are expected to be tightly coupled with their /// InliningAdvisors. The base type implements the minimal contractual /// obligations. class InlineAdvice { … }; class DefaultInlineAdvice : public InlineAdvice { … }; /// Interface for deciding whether to inline a call site or not. class InlineAdvisor { … }; /// The default (manual heuristics) implementation of the InlineAdvisor. This /// implementation does not need to keep state between inliner pass runs, and is /// reusable as-is for inliner pass test scenarios, as well as for regular use. class DefaultInlineAdvisor : public InlineAdvisor { … }; /// Used for dynamically registering InlineAdvisors as plugins /// /// An advisor plugin adds a new advisor at runtime by registering an instance /// of PluginInlineAdvisorAnalysis in the current ModuleAnalysisManager. /// For example, the following code dynamically registers a /// DefaultInlineAdvisor: /// /// namespace { /// /// InlineAdvisor *defaultAdvisorFactory(Module &M, FunctionAnalysisManager /// &FAM, /// InlineParams Params, InlineContext IC) /// { /// return new DefaultInlineAdvisor(M, FAM, Params, IC); /// } /// /// struct DefaultDynamicAdvisor : PassInfoMixin<DefaultDynamicAdvisor> { /// PreservedAnalyses run(Module &, ModuleAnalysisManager &MAM) { /// PluginInlineAdvisorAnalysis PA(defaultAdvisorFactory); /// MAM.registerPass([&] { return PA; }); /// return PreservedAnalyses::all(); /// } /// }; /// /// } // namespace /// /// extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo /// llvmGetPassPluginInfo() { /// return {LLVM_PLUGIN_API_VERSION, "DynamicDefaultAdvisor", /// LLVM_VERSION_STRING, /// [](PassBuilder &PB) { /// PB.registerPipelineStartEPCallback( /// [](ModulePassManager &MPM, OptimizationLevel Level) { /// MPM.addPass(DefaultDynamicAdvisor()); /// }); /// }}; /// } /// /// A plugin must implement an AdvisorFactory and register it with a /// PluginInlineAdvisorAnlysis to the provided ModuleanAlysisManager. /// /// If such a plugin has been registered /// InlineAdvisorAnalysis::Result::tryCreate will return the dynamically loaded /// advisor. /// class PluginInlineAdvisorAnalysis : public AnalysisInfoMixin<PluginInlineAdvisorAnalysis> { … }; /// The InlineAdvisorAnalysis is a module pass because the InlineAdvisor /// needs to capture state right before inlining commences over a module. class InlineAdvisorAnalysis : public AnalysisInfoMixin<InlineAdvisorAnalysis> { … }; /// Printer pass for the InlineAdvisorAnalysis results. class InlineAdvisorAnalysisPrinterPass : public PassInfoMixin<InlineAdvisorAnalysisPrinterPass> { … }; std::unique_ptr<InlineAdvisor> getReleaseModeAdvisor(Module &M, ModuleAnalysisManager &MAM, std::function<bool(CallBase &)> GetDefaultAdvice); std::unique_ptr<InlineAdvisor> getDevelopmentModeAdvisor(Module &M, ModuleAnalysisManager &MAM, std::function<bool(CallBase &)> GetDefaultAdvice); // Default (manual policy) decision making helper APIs. Shared with the legacy // pass manager inliner. /// Return the cost only if the inliner should attempt to inline at the given /// CallSite. If we return the cost, we will emit an optimisation remark later /// using that cost, so we won't do so from this function. Return std::nullopt /// if inlining should not be attempted. std::optional<InlineCost> shouldInline(CallBase &CB, function_ref<InlineCost(CallBase &CB)> GetInlineCost, OptimizationRemarkEmitter &ORE, bool EnableDeferral = true); /// Emit ORE message. void emitInlinedInto(OptimizationRemarkEmitter &ORE, DebugLoc DLoc, const BasicBlock *Block, const Function &Callee, const Function &Caller, bool IsMandatory, function_ref<void(OptimizationRemark &)> ExtraContext = { … }; /// Emit ORE message based in cost (default heuristic). void emitInlinedIntoBasedOnCost(OptimizationRemarkEmitter &ORE, DebugLoc DLoc, const BasicBlock *Block, const Function &Callee, const Function &Caller, const InlineCost &IC, bool ForProfileContext = false, const char *PassName = nullptr); /// Add location info to ORE message. void addLocationToRemarks(OptimizationRemark &Remark, DebugLoc DLoc); /// Set the inline-remark attribute. void setInlineRemark(CallBase &CB, StringRef Message); /// Utility for extracting the inline cost message to a string. std::string inlineCostStr(const InlineCost &IC); } // namespace llvm #endif // LLVM_ANALYSIS_INLINEADVISOR_H