InlineAdvisor.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- InlineAdvisor.h - Inlining decision making abstraction -*- C++ ---*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. #ifndef LLVM_ANALYSIS_INLINEADVISOR_H
  15. #define LLVM_ANALYSIS_INLINEADVISOR_H
  16. #include "llvm/Analysis/CGSCCPassManager.h"
  17. #include "llvm/Analysis/InlineCost.h"
  18. #include "llvm/Analysis/LazyCallGraph.h"
  19. #include "llvm/Config/llvm-config.h"
  20. #include "llvm/IR/PassManager.h"
  21. #include <memory>
  22. namespace llvm {
  23. class BasicBlock;
  24. class CallBase;
  25. class Function;
  26. class Module;
  27. class OptimizationRemark;
  28. class ImportedFunctionsInliningStatistics;
  29. class OptimizationRemarkEmitter;
  30. struct ReplayInlinerSettings;
  31. /// There are 4 scenarios we can use the InlineAdvisor:
  32. /// - Default - use manual heuristics.
  33. ///
  34. /// - Release mode, the expected mode for production, day to day deployments.
  35. /// In this mode, when building the compiler, we also compile a pre-trained ML
  36. /// model to native code, and link it as a static library. This mode has low
  37. /// overhead and no additional dependencies for the compiler runtime.
  38. ///
  39. /// - Development mode, for training new models.
  40. /// In this mode, we trade off runtime performance for flexibility. This mode
  41. /// requires the full C Tensorflow API library, and evaluates models
  42. /// dynamically. This mode also permits generating training logs, for offline
  43. /// training.
  44. ///
  45. /// - Dynamically load an advisor via a plugin (PluginInlineAdvisorAnalysis)
  46. enum class InliningAdvisorMode : int { Default, Release, Development };
  47. // Each entry represents an inline driver.
  48. enum class InlinePass : int {
  49. AlwaysInliner,
  50. CGSCCInliner,
  51. EarlyInliner,
  52. ModuleInliner,
  53. MLInliner,
  54. ReplayCGSCCInliner,
  55. ReplaySampleProfileInliner,
  56. SampleProfileInliner,
  57. };
  58. /// Provides context on when an inline advisor is constructed in the pipeline
  59. /// (e.g., link phase, inline driver).
  60. struct InlineContext {
  61. ThinOrFullLTOPhase LTOPhase;
  62. InlinePass Pass;
  63. };
  64. std::string AnnotateInlinePassName(InlineContext IC);
  65. class InlineAdvisor;
  66. /// Capture state between an inlining decision having had been made, and
  67. /// its impact being observable. When collecting model training data, this
  68. /// allows recording features/decisions/partial reward data sets.
  69. ///
  70. /// Derivations of this type are expected to be tightly coupled with their
  71. /// InliningAdvisors. The base type implements the minimal contractual
  72. /// obligations.
  73. class InlineAdvice {
  74. public:
  75. InlineAdvice(InlineAdvisor *Advisor, CallBase &CB,
  76. OptimizationRemarkEmitter &ORE, bool IsInliningRecommended);
  77. InlineAdvice(InlineAdvice &&) = delete;
  78. InlineAdvice(const InlineAdvice &) = delete;
  79. virtual ~InlineAdvice() {
  80. assert(Recorded && "InlineAdvice should have been informed of the "
  81. "inliner's decision in all cases");
  82. }
  83. /// Exactly one of the record* APIs must be called. Implementers may extend
  84. /// behavior by implementing the corresponding record*Impl.
  85. ///
  86. /// Call after inlining succeeded, and did not result in deleting the callee.
  87. void recordInlining();
  88. /// Call after inlining succeeded, and results in the callee being
  89. /// delete-able, meaning, it has no more users, and will be cleaned up
  90. /// subsequently.
  91. void recordInliningWithCalleeDeleted();
  92. /// Call after the decision for a call site was to not inline.
  93. void recordUnsuccessfulInlining(const InlineResult &Result) {
  94. markRecorded();
  95. recordUnsuccessfulInliningImpl(Result);
  96. }
  97. /// Call to indicate inlining was not attempted.
  98. void recordUnattemptedInlining() {
  99. markRecorded();
  100. recordUnattemptedInliningImpl();
  101. }
  102. /// Get the inlining recommendation.
  103. bool isInliningRecommended() const { return IsInliningRecommended; }
  104. const DebugLoc &getOriginalCallSiteDebugLoc() const { return DLoc; }
  105. const BasicBlock *getOriginalCallSiteBasicBlock() const { return Block; }
  106. protected:
  107. virtual void recordInliningImpl() {}
  108. virtual void recordInliningWithCalleeDeletedImpl() {}
  109. virtual void recordUnsuccessfulInliningImpl(const InlineResult &Result) {}
  110. virtual void recordUnattemptedInliningImpl() {}
  111. InlineAdvisor *const Advisor;
  112. /// Caller and Callee are pre-inlining.
  113. Function *const Caller;
  114. Function *const Callee;
  115. // Capture the context of CB before inlining, as a successful inlining may
  116. // change that context, and we want to report success or failure in the
  117. // original context.
  118. const DebugLoc DLoc;
  119. const BasicBlock *const Block;
  120. OptimizationRemarkEmitter &ORE;
  121. const bool IsInliningRecommended;
  122. private:
  123. void markRecorded() {
  124. assert(!Recorded && "Recording should happen exactly once");
  125. Recorded = true;
  126. }
  127. void recordInlineStatsIfNeeded();
  128. bool Recorded = false;
  129. };
  130. class DefaultInlineAdvice : public InlineAdvice {
  131. public:
  132. DefaultInlineAdvice(InlineAdvisor *Advisor, CallBase &CB,
  133. std::optional<InlineCost> OIC,
  134. OptimizationRemarkEmitter &ORE, bool EmitRemarks = true)
  135. : InlineAdvice(Advisor, CB, ORE, OIC.has_value()), OriginalCB(&CB),
  136. OIC(OIC), EmitRemarks(EmitRemarks) {}
  137. private:
  138. void recordUnsuccessfulInliningImpl(const InlineResult &Result) override;
  139. void recordInliningWithCalleeDeletedImpl() override;
  140. void recordInliningImpl() override;
  141. private:
  142. CallBase *const OriginalCB;
  143. std::optional<InlineCost> OIC;
  144. bool EmitRemarks;
  145. };
  146. /// Interface for deciding whether to inline a call site or not.
  147. class InlineAdvisor {
  148. public:
  149. InlineAdvisor(InlineAdvisor &&) = delete;
  150. virtual ~InlineAdvisor();
  151. /// Get an InlineAdvice containing a recommendation on whether to
  152. /// inline or not. \p CB is assumed to be a direct call. \p FAM is assumed to
  153. /// be up-to-date wrt previous inlining decisions. \p MandatoryOnly indicates
  154. /// only mandatory (always-inline) call sites should be recommended - this
  155. /// allows the InlineAdvisor track such inlininings.
  156. /// Returns:
  157. /// - An InlineAdvice with the inlining recommendation.
  158. /// - Null when no recommendation is made (https://reviews.llvm.org/D110658).
  159. /// TODO: Consider removing the Null return scenario by incorporating the
  160. /// SampleProfile inliner into an InlineAdvisor
  161. std::unique_ptr<InlineAdvice> getAdvice(CallBase &CB,
  162. bool MandatoryOnly = false);
  163. /// This must be called when the Inliner pass is entered, to allow the
  164. /// InlineAdvisor update internal state, as result of function passes run
  165. /// between Inliner pass runs (for the same module).
  166. virtual void onPassEntry(LazyCallGraph::SCC *SCC = nullptr) {}
  167. /// This must be called when the Inliner pass is exited, as function passes
  168. /// may be run subsequently. This allows an implementation of InlineAdvisor
  169. /// to prepare for a partial update, based on the optional SCC.
  170. virtual void onPassExit(LazyCallGraph::SCC *SCC = nullptr) {}
  171. /// Support for printer pass
  172. virtual void print(raw_ostream &OS) const {
  173. OS << "Unimplemented InlineAdvisor print\n";
  174. }
  175. /// NOTE pass name is annotated only when inline advisor constructor provides InlineContext.
  176. const char *getAnnotatedInlinePassName() const {
  177. return AnnotatedInlinePassName.c_str();
  178. }
  179. protected:
  180. InlineAdvisor(Module &M, FunctionAnalysisManager &FAM,
  181. std::optional<InlineContext> IC = std::nullopt);
  182. virtual std::unique_ptr<InlineAdvice> getAdviceImpl(CallBase &CB) = 0;
  183. virtual std::unique_ptr<InlineAdvice> getMandatoryAdvice(CallBase &CB,
  184. bool Advice);
  185. Module &M;
  186. FunctionAnalysisManager &FAM;
  187. const std::optional<InlineContext> IC;
  188. const std::string AnnotatedInlinePassName;
  189. std::unique_ptr<ImportedFunctionsInliningStatistics> ImportedFunctionsStats;
  190. enum class MandatoryInliningKind { NotMandatory, Always, Never };
  191. static MandatoryInliningKind getMandatoryKind(CallBase &CB,
  192. FunctionAnalysisManager &FAM,
  193. OptimizationRemarkEmitter &ORE);
  194. OptimizationRemarkEmitter &getCallerORE(CallBase &CB);
  195. private:
  196. friend class InlineAdvice;
  197. };
  198. /// The default (manual heuristics) implementation of the InlineAdvisor. This
  199. /// implementation does not need to keep state between inliner pass runs, and is
  200. /// reusable as-is for inliner pass test scenarios, as well as for regular use.
  201. class DefaultInlineAdvisor : public InlineAdvisor {
  202. public:
  203. DefaultInlineAdvisor(Module &M, FunctionAnalysisManager &FAM,
  204. InlineParams Params, InlineContext IC)
  205. : InlineAdvisor(M, FAM, IC), Params(Params) {}
  206. private:
  207. std::unique_ptr<InlineAdvice> getAdviceImpl(CallBase &CB) override;
  208. InlineParams Params;
  209. };
  210. /// Used for dynamically registering InlineAdvisors as plugins
  211. ///
  212. /// An advisor plugin adds a new advisor at runtime by registering an instance
  213. /// of PluginInlineAdvisorAnalysis in the current ModuleAnalysisManager.
  214. /// For example, the following code dynamically registers a
  215. /// DefaultInlineAdvisor:
  216. ///
  217. /// namespace {
  218. ///
  219. /// InlineAdvisor *defaultAdvisorFactory(Module &M, FunctionAnalysisManager
  220. /// &FAM,
  221. /// InlineParams Params, InlineContext IC)
  222. /// {
  223. /// return new DefaultInlineAdvisor(M, FAM, Params, IC);
  224. /// }
  225. ///
  226. /// struct DefaultDynamicAdvisor : PassInfoMixin<DefaultDynamicAdvisor> {
  227. /// PreservedAnalyses run(Module &, ModuleAnalysisManager &MAM) {
  228. /// PluginInlineAdvisorAnalysis PA(defaultAdvisorFactory);
  229. /// MAM.registerPass([&] { return PA; });
  230. /// return PreservedAnalyses::all();
  231. /// }
  232. /// };
  233. ///
  234. /// } // namespace
  235. ///
  236. /// extern "C" LLVM_ATTRIBUTE_WEAK ::llvm::PassPluginLibraryInfo
  237. /// llvmGetPassPluginInfo() {
  238. /// return {LLVM_PLUGIN_API_VERSION, "DynamicDefaultAdvisor",
  239. /// LLVM_VERSION_STRING,
  240. /// [](PassBuilder &PB) {
  241. /// PB.registerPipelineStartEPCallback(
  242. /// [](ModulePassManager &MPM, OptimizationLevel Level) {
  243. /// MPM.addPass(DefaultDynamicAdvisor());
  244. /// });
  245. /// }};
  246. /// }
  247. ///
  248. /// A plugin must implement an AdvisorFactory and register it with a
  249. /// PluginInlineAdvisorAnlysis to the provided ModuleanAlysisManager.
  250. ///
  251. /// If such a plugin has been registered
  252. /// InlineAdvisorAnalysis::Result::tryCreate will return the dynamically loaded
  253. /// advisor.
  254. ///
  255. class PluginInlineAdvisorAnalysis
  256. : public AnalysisInfoMixin<PluginInlineAdvisorAnalysis> {
  257. public:
  258. static AnalysisKey Key;
  259. static bool HasBeenRegistered;
  260. typedef InlineAdvisor *(*AdvisorFactory)(Module &M,
  261. FunctionAnalysisManager &FAM,
  262. InlineParams Params,
  263. InlineContext IC);
  264. PluginInlineAdvisorAnalysis(AdvisorFactory Factory) : Factory(Factory) {
  265. HasBeenRegistered = true;
  266. assert(Factory != nullptr &&
  267. "The plugin advisor factory should not be a null pointer.");
  268. }
  269. struct Result {
  270. AdvisorFactory Factory;
  271. };
  272. Result run(Module &M, ModuleAnalysisManager &MAM) { return {Factory}; }
  273. Result getResult() { return {Factory}; }
  274. private:
  275. AdvisorFactory Factory;
  276. };
  277. /// The InlineAdvisorAnalysis is a module pass because the InlineAdvisor
  278. /// needs to capture state right before inlining commences over a module.
  279. class InlineAdvisorAnalysis : public AnalysisInfoMixin<InlineAdvisorAnalysis> {
  280. public:
  281. static AnalysisKey Key;
  282. InlineAdvisorAnalysis() = default;
  283. struct Result {
  284. Result(Module &M, ModuleAnalysisManager &MAM) : M(M), MAM(MAM) {}
  285. bool invalidate(Module &, const PreservedAnalyses &PA,
  286. ModuleAnalysisManager::Invalidator &) {
  287. // Check whether the analysis has been explicitly invalidated. Otherwise,
  288. // it's stateless and remains preserved.
  289. auto PAC = PA.getChecker<InlineAdvisorAnalysis>();
  290. return !PAC.preservedWhenStateless();
  291. }
  292. bool tryCreate(InlineParams Params, InliningAdvisorMode Mode,
  293. const ReplayInlinerSettings &ReplaySettings,
  294. InlineContext IC);
  295. InlineAdvisor *getAdvisor() const { return Advisor.get(); }
  296. private:
  297. Module &M;
  298. ModuleAnalysisManager &MAM;
  299. std::unique_ptr<InlineAdvisor> Advisor;
  300. };
  301. Result run(Module &M, ModuleAnalysisManager &MAM) { return Result(M, MAM); }
  302. };
  303. /// Printer pass for the FunctionPropertiesAnalysis results.
  304. class InlineAdvisorAnalysisPrinterPass
  305. : public PassInfoMixin<InlineAdvisorAnalysisPrinterPass> {
  306. raw_ostream &OS;
  307. public:
  308. explicit InlineAdvisorAnalysisPrinterPass(raw_ostream &OS) : OS(OS) {}
  309. PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
  310. PreservedAnalyses run(LazyCallGraph::SCC &InitialC, CGSCCAnalysisManager &AM,
  311. LazyCallGraph &CG, CGSCCUpdateResult &UR);
  312. };
  313. std::unique_ptr<InlineAdvisor>
  314. getReleaseModeAdvisor(Module &M, ModuleAnalysisManager &MAM);
  315. std::unique_ptr<InlineAdvisor>
  316. getDevelopmentModeAdvisor(Module &M, ModuleAnalysisManager &MAM,
  317. std::function<bool(CallBase &)> GetDefaultAdvice);
  318. // Default (manual policy) decision making helper APIs. Shared with the legacy
  319. // pass manager inliner.
  320. /// Return the cost only if the inliner should attempt to inline at the given
  321. /// CallSite. If we return the cost, we will emit an optimisation remark later
  322. /// using that cost, so we won't do so from this function. Return std::nullopt
  323. /// if inlining should not be attempted.
  324. std::optional<InlineCost>
  325. shouldInline(CallBase &CB, function_ref<InlineCost(CallBase &CB)> GetInlineCost,
  326. OptimizationRemarkEmitter &ORE, bool EnableDeferral = true);
  327. /// Emit ORE message.
  328. void emitInlinedInto(OptimizationRemarkEmitter &ORE, DebugLoc DLoc,
  329. const BasicBlock *Block, const Function &Callee,
  330. const Function &Caller, bool IsMandatory,
  331. function_ref<void(OptimizationRemark &)> ExtraContext = {},
  332. const char *PassName = nullptr);
  333. /// Emit ORE message based in cost (default heuristic).
  334. void emitInlinedIntoBasedOnCost(OptimizationRemarkEmitter &ORE, DebugLoc DLoc,
  335. const BasicBlock *Block, const Function &Callee,
  336. const Function &Caller, const InlineCost &IC,
  337. bool ForProfileContext = false,
  338. const char *PassName = nullptr);
  339. /// Add location info to ORE message.
  340. void addLocationToRemarks(OptimizationRemark &Remark, DebugLoc DLoc);
  341. /// Set the inline-remark attribute.
  342. void setInlineRemark(CallBase &CB, StringRef Message);
  343. /// Utility for extracting the inline cost message to a string.
  344. std::string inlineCostStr(const InlineCost &IC);
  345. } // namespace llvm
  346. #endif // LLVM_ANALYSIS_INLINEADVISOR_H
  347. #ifdef __GNUC__
  348. #pragma GCC diagnostic pop
  349. #endif