InlineAdvisor.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  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/InlineCost.h"
  17. #include "llvm/Analysis/LazyCallGraph.h"
  18. #include "llvm/Analysis/Utils/ImportedFunctionsInliningStatistics.h"
  19. #include "llvm/Config/llvm-config.h"
  20. #include "llvm/IR/PassManager.h"
  21. #include <memory>
  22. #include <unordered_set>
  23. namespace llvm {
  24. class BasicBlock;
  25. class CallBase;
  26. class Function;
  27. class Module;
  28. class OptimizationRemarkEmitter;
  29. struct ReplayInlinerSettings;
  30. /// There are 3 scenarios we can use the InlineAdvisor:
  31. /// - Default - use manual heuristics.
  32. ///
  33. /// - Release mode, the expected mode for production, day to day deployments.
  34. /// In this mode, when building the compiler, we also compile a pre-trained ML
  35. /// model to native code, and link it as a static library. This mode has low
  36. /// overhead and no additional dependencies for the compiler runtime.
  37. ///
  38. /// - Development mode, for training new models.
  39. /// In this mode, we trade off runtime performance for flexibility. This mode
  40. /// requires the full C Tensorflow API library, and evaluates models
  41. /// dynamically. This mode also permits generating training logs, for offline
  42. /// training.
  43. enum class InliningAdvisorMode : int { Default, Release, Development };
  44. class InlineAdvisor;
  45. /// Capture state between an inlining decision having had been made, and
  46. /// its impact being observable. When collecting model training data, this
  47. /// allows recording features/decisions/partial reward data sets.
  48. ///
  49. /// Derivations of this type are expected to be tightly coupled with their
  50. /// InliningAdvisors. The base type implements the minimal contractual
  51. /// obligations.
  52. class InlineAdvice {
  53. public:
  54. InlineAdvice(InlineAdvisor *Advisor, CallBase &CB,
  55. OptimizationRemarkEmitter &ORE, bool IsInliningRecommended);
  56. InlineAdvice(InlineAdvice &&) = delete;
  57. InlineAdvice(const InlineAdvice &) = delete;
  58. virtual ~InlineAdvice() {
  59. assert(Recorded && "InlineAdvice should have been informed of the "
  60. "inliner's decision in all cases");
  61. }
  62. /// Exactly one of the record* APIs must be called. Implementers may extend
  63. /// behavior by implementing the corresponding record*Impl.
  64. ///
  65. /// Call after inlining succeeded, and did not result in deleting the callee.
  66. void recordInlining();
  67. /// Call after inlining succeeded, and results in the callee being
  68. /// delete-able, meaning, it has no more users, and will be cleaned up
  69. /// subsequently.
  70. void recordInliningWithCalleeDeleted();
  71. /// Call after the decision for a call site was to not inline.
  72. void recordUnsuccessfulInlining(const InlineResult &Result) {
  73. markRecorded();
  74. recordUnsuccessfulInliningImpl(Result);
  75. }
  76. /// Call to indicate inlining was not attempted.
  77. void recordUnattemptedInlining() {
  78. markRecorded();
  79. recordUnattemptedInliningImpl();
  80. }
  81. /// Get the inlining recommendation.
  82. bool isInliningRecommended() const { return IsInliningRecommended; }
  83. const DebugLoc &getOriginalCallSiteDebugLoc() const { return DLoc; }
  84. const BasicBlock *getOriginalCallSiteBasicBlock() const { return Block; }
  85. protected:
  86. virtual void recordInliningImpl() {}
  87. virtual void recordInliningWithCalleeDeletedImpl() {}
  88. virtual void recordUnsuccessfulInliningImpl(const InlineResult &Result) {}
  89. virtual void recordUnattemptedInliningImpl() {}
  90. InlineAdvisor *const Advisor;
  91. /// Caller and Callee are pre-inlining.
  92. Function *const Caller;
  93. Function *const Callee;
  94. // Capture the context of CB before inlining, as a successful inlining may
  95. // change that context, and we want to report success or failure in the
  96. // original context.
  97. const DebugLoc DLoc;
  98. const BasicBlock *const Block;
  99. OptimizationRemarkEmitter &ORE;
  100. const bool IsInliningRecommended;
  101. private:
  102. void markRecorded() {
  103. assert(!Recorded && "Recording should happen exactly once");
  104. Recorded = true;
  105. }
  106. void recordInlineStatsIfNeeded();
  107. bool Recorded = false;
  108. };
  109. class DefaultInlineAdvice : public InlineAdvice {
  110. public:
  111. DefaultInlineAdvice(InlineAdvisor *Advisor, CallBase &CB,
  112. Optional<InlineCost> OIC, OptimizationRemarkEmitter &ORE,
  113. bool EmitRemarks = true)
  114. : InlineAdvice(Advisor, CB, ORE, OIC.hasValue()), OriginalCB(&CB),
  115. OIC(OIC), EmitRemarks(EmitRemarks) {}
  116. private:
  117. void recordUnsuccessfulInliningImpl(const InlineResult &Result) override;
  118. void recordInliningWithCalleeDeletedImpl() override;
  119. void recordInliningImpl() override;
  120. private:
  121. CallBase *const OriginalCB;
  122. Optional<InlineCost> OIC;
  123. bool EmitRemarks;
  124. };
  125. /// Interface for deciding whether to inline a call site or not.
  126. class InlineAdvisor {
  127. public:
  128. InlineAdvisor(InlineAdvisor &&) = delete;
  129. virtual ~InlineAdvisor();
  130. /// Get an InlineAdvice containing a recommendation on whether to
  131. /// inline or not. \p CB is assumed to be a direct call. \p FAM is assumed to
  132. /// be up-to-date wrt previous inlining decisions. \p MandatoryOnly indicates
  133. /// only mandatory (always-inline) call sites should be recommended - this
  134. /// allows the InlineAdvisor track such inlininings.
  135. /// Returns:
  136. /// - An InlineAdvice with the inlining recommendation.
  137. /// - Null when no recommendation is made (https://reviews.llvm.org/D110658).
  138. /// TODO: Consider removing the Null return scenario by incorporating the
  139. /// SampleProfile inliner into an InlineAdvisor
  140. std::unique_ptr<InlineAdvice> getAdvice(CallBase &CB,
  141. bool MandatoryOnly = false);
  142. /// This must be called when the Inliner pass is entered, to allow the
  143. /// InlineAdvisor update internal state, as result of function passes run
  144. /// between Inliner pass runs (for the same module).
  145. virtual void onPassEntry() {}
  146. /// This must be called when the Inliner pass is exited, as function passes
  147. /// may be run subsequently. This allows an implementation of InlineAdvisor
  148. /// to prepare for a partial update, based on the optional SCC.
  149. virtual void onPassExit(LazyCallGraph::SCC *SCC = nullptr) {}
  150. /// Support for printer pass
  151. virtual void print(raw_ostream &OS) const {
  152. OS << "Unimplemented InlineAdvisor print\n";
  153. }
  154. protected:
  155. InlineAdvisor(Module &M, FunctionAnalysisManager &FAM);
  156. virtual std::unique_ptr<InlineAdvice> getAdviceImpl(CallBase &CB) = 0;
  157. virtual std::unique_ptr<InlineAdvice> getMandatoryAdvice(CallBase &CB,
  158. bool Advice);
  159. Module &M;
  160. FunctionAnalysisManager &FAM;
  161. std::unique_ptr<ImportedFunctionsInliningStatistics> ImportedFunctionsStats;
  162. enum class MandatoryInliningKind { NotMandatory, Always, Never };
  163. static MandatoryInliningKind getMandatoryKind(CallBase &CB,
  164. FunctionAnalysisManager &FAM,
  165. OptimizationRemarkEmitter &ORE);
  166. OptimizationRemarkEmitter &getCallerORE(CallBase &CB);
  167. private:
  168. friend class InlineAdvice;
  169. };
  170. /// The default (manual heuristics) implementation of the InlineAdvisor. This
  171. /// implementation does not need to keep state between inliner pass runs, and is
  172. /// reusable as-is for inliner pass test scenarios, as well as for regular use.
  173. class DefaultInlineAdvisor : public InlineAdvisor {
  174. public:
  175. DefaultInlineAdvisor(Module &M, FunctionAnalysisManager &FAM,
  176. InlineParams Params)
  177. : InlineAdvisor(M, FAM), Params(Params) {}
  178. private:
  179. std::unique_ptr<InlineAdvice> getAdviceImpl(CallBase &CB) override;
  180. InlineParams Params;
  181. };
  182. /// The InlineAdvisorAnalysis is a module pass because the InlineAdvisor
  183. /// needs to capture state right before inlining commences over a module.
  184. class InlineAdvisorAnalysis : public AnalysisInfoMixin<InlineAdvisorAnalysis> {
  185. public:
  186. static AnalysisKey Key;
  187. InlineAdvisorAnalysis() = default;
  188. struct Result {
  189. Result(Module &M, ModuleAnalysisManager &MAM) : M(M), MAM(MAM) {}
  190. bool invalidate(Module &, const PreservedAnalyses &PA,
  191. ModuleAnalysisManager::Invalidator &) {
  192. // Check whether the analysis has been explicitly invalidated. Otherwise,
  193. // it's stateless and remains preserved.
  194. auto PAC = PA.getChecker<InlineAdvisorAnalysis>();
  195. return !PAC.preservedWhenStateless();
  196. }
  197. bool tryCreate(InlineParams Params, InliningAdvisorMode Mode,
  198. const ReplayInlinerSettings &ReplaySettings);
  199. InlineAdvisor *getAdvisor() const { return Advisor.get(); }
  200. private:
  201. Module &M;
  202. ModuleAnalysisManager &MAM;
  203. std::unique_ptr<InlineAdvisor> Advisor;
  204. };
  205. Result run(Module &M, ModuleAnalysisManager &MAM) { return Result(M, MAM); }
  206. };
  207. /// Printer pass for the FunctionPropertiesAnalysis results.
  208. class InlineAdvisorAnalysisPrinterPass
  209. : public PassInfoMixin<InlineAdvisorAnalysisPrinterPass> {
  210. raw_ostream &OS;
  211. public:
  212. explicit InlineAdvisorAnalysisPrinterPass(raw_ostream &OS) : OS(OS) {}
  213. PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
  214. };
  215. std::unique_ptr<InlineAdvisor>
  216. getReleaseModeAdvisor(Module &M, ModuleAnalysisManager &MAM);
  217. std::unique_ptr<InlineAdvisor>
  218. getDevelopmentModeAdvisor(Module &M, ModuleAnalysisManager &MAM,
  219. std::function<bool(CallBase &)> GetDefaultAdvice);
  220. // Default (manual policy) decision making helper APIs. Shared with the legacy
  221. // pass manager inliner.
  222. /// Return the cost only if the inliner should attempt to inline at the given
  223. /// CallSite. If we return the cost, we will emit an optimisation remark later
  224. /// using that cost, so we won't do so from this function. Return None if
  225. /// inlining should not be attempted.
  226. Optional<InlineCost>
  227. shouldInline(CallBase &CB, function_ref<InlineCost(CallBase &CB)> GetInlineCost,
  228. OptimizationRemarkEmitter &ORE, bool EnableDeferral = true);
  229. /// Emit ORE message.
  230. void emitInlinedInto(OptimizationRemarkEmitter &ORE, DebugLoc DLoc,
  231. const BasicBlock *Block, const Function &Callee,
  232. const Function &Caller, bool IsMandatory,
  233. function_ref<void(OptimizationRemark &)> ExtraContext = {},
  234. const char *PassName = nullptr);
  235. /// Emit ORE message based in cost (default heuristic).
  236. void emitInlinedIntoBasedOnCost(OptimizationRemarkEmitter &ORE, DebugLoc DLoc,
  237. const BasicBlock *Block, const Function &Callee,
  238. const Function &Caller, const InlineCost &IC,
  239. bool ForProfileContext = false,
  240. const char *PassName = nullptr);
  241. /// Add location info to ORE message.
  242. void addLocationToRemarks(OptimizationRemark &Remark, DebugLoc DLoc);
  243. /// Set the inline-remark attribute.
  244. void setInlineRemark(CallBase &CB, StringRef Message);
  245. /// Utility for extracting the inline cost message to a string.
  246. std::string inlineCostStr(const InlineCost &IC);
  247. } // namespace llvm
  248. #endif // LLVM_ANALYSIS_INLINEADVISOR_H
  249. #ifdef __GNUC__
  250. #pragma GCC diagnostic pop
  251. #endif