InlineAdvisor.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  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_INLINEADVISOR_H_
  15. #define LLVM_INLINEADVISOR_H_
  16. #include "llvm/Analysis/InlineCost.h"
  17. #include "llvm/Config/llvm-config.h"
  18. #include "llvm/IR/PassManager.h"
  19. #include "llvm/Analysis/Utils/ImportedFunctionsInliningStatistics.h"
  20. #include <memory>
  21. #include <unordered_set>
  22. namespace llvm {
  23. class BasicBlock;
  24. class CallBase;
  25. class Function;
  26. class Module;
  27. class OptimizationRemarkEmitter;
  28. /// There are 3 scenarios we can use the InlineAdvisor:
  29. /// - Default - use manual heuristics.
  30. ///
  31. /// - Release mode, the expected mode for production, day to day deployments.
  32. /// In this mode, when building the compiler, we also compile a pre-trained ML
  33. /// model to native code, and link it as a static library. This mode has low
  34. /// overhead and no additional dependencies for the compiler runtime.
  35. ///
  36. /// - Development mode, for training new models.
  37. /// In this mode, we trade off runtime performance for flexibility. This mode
  38. /// requires the full C Tensorflow API library, and evaluates models
  39. /// dynamically. This mode also permits generating training logs, for offline
  40. /// training.
  41. enum class InliningAdvisorMode : int {
  42. Default,
  43. Release,
  44. Development
  45. };
  46. class InlineAdvisor;
  47. /// Capture state between an inlining decision having had been made, and
  48. /// its impact being observable. When collecting model training data, this
  49. /// allows recording features/decisions/partial reward data sets.
  50. ///
  51. /// Derivations of this type are expected to be tightly coupled with their
  52. /// InliningAdvisors. The base type implements the minimal contractual
  53. /// obligations.
  54. class InlineAdvice {
  55. public:
  56. InlineAdvice(InlineAdvisor *Advisor, CallBase &CB,
  57. OptimizationRemarkEmitter &ORE, bool IsInliningRecommended);
  58. InlineAdvice(InlineAdvice &&) = delete;
  59. InlineAdvice(const InlineAdvice &) = delete;
  60. virtual ~InlineAdvice() {
  61. assert(Recorded && "InlineAdvice should have been informed of the "
  62. "inliner's decision in all cases");
  63. }
  64. /// Exactly one of the record* APIs must be called. Implementers may extend
  65. /// behavior by implementing the corresponding record*Impl.
  66. ///
  67. /// Call after inlining succeeded, and did not result in deleting the callee.
  68. void recordInlining();
  69. /// Call after inlining succeeded, and resulted in deleting the callee.
  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 an InlineAdvice with the inlining recommendation.
  136. std::unique_ptr<InlineAdvice> getAdvice(CallBase &CB,
  137. bool MandatoryOnly = false);
  138. /// This must be called when the Inliner pass is entered, to allow the
  139. /// InlineAdvisor update internal state, as result of function passes run
  140. /// between Inliner pass runs (for the same module).
  141. virtual void onPassEntry() {}
  142. /// This must be called when the Inliner pass is exited, as function passes
  143. /// may be run subsequently. This allows an implementation of InlineAdvisor
  144. /// to prepare for a partial update.
  145. virtual void onPassExit() {}
  146. protected:
  147. InlineAdvisor(Module &M, FunctionAnalysisManager &FAM);
  148. virtual std::unique_ptr<InlineAdvice> getAdviceImpl(CallBase &CB) = 0;
  149. virtual std::unique_ptr<InlineAdvice> getMandatoryAdvice(CallBase &CB,
  150. bool Advice);
  151. Module &M;
  152. FunctionAnalysisManager &FAM;
  153. std::unique_ptr<ImportedFunctionsInliningStatistics> ImportedFunctionsStats;
  154. /// We may want to defer deleting functions to after the inlining for a whole
  155. /// module has finished. This allows us to reliably use function pointers as
  156. /// unique identifiers, as an efficient implementation detail of the
  157. /// InlineAdvisor. Otherwise, it is possible the memory allocator
  158. /// re-allocate Function objects at the same address of a deleted Function;
  159. /// and Functions are potentially created during the function passes called
  160. /// after each SCC inlining (e.g. argument promotion does that).
  161. void freeDeletedFunctions();
  162. bool isFunctionDeleted(const Function *F) const {
  163. return DeletedFunctions.count(F);
  164. }
  165. enum class MandatoryInliningKind { NotMandatory, Always, Never };
  166. static MandatoryInliningKind getMandatoryKind(CallBase &CB,
  167. FunctionAnalysisManager &FAM,
  168. OptimizationRemarkEmitter &ORE);
  169. OptimizationRemarkEmitter &getCallerORE(CallBase &CB);
  170. private:
  171. friend class InlineAdvice;
  172. void markFunctionAsDeleted(Function *F);
  173. std::unordered_set<const Function *> DeletedFunctions;
  174. };
  175. /// The default (manual heuristics) implementation of the InlineAdvisor. This
  176. /// implementation does not need to keep state between inliner pass runs, and is
  177. /// reusable as-is for inliner pass test scenarios, as well as for regular use.
  178. class DefaultInlineAdvisor : public InlineAdvisor {
  179. public:
  180. DefaultInlineAdvisor(Module &M, FunctionAnalysisManager &FAM,
  181. InlineParams Params)
  182. : InlineAdvisor(M, FAM), Params(Params) {}
  183. private:
  184. std::unique_ptr<InlineAdvice> getAdviceImpl(CallBase &CB) override;
  185. void onPassExit() override { freeDeletedFunctions(); }
  186. InlineParams Params;
  187. };
  188. /// The InlineAdvisorAnalysis is a module pass because the InlineAdvisor
  189. /// needs to capture state right before inlining commences over a module.
  190. class InlineAdvisorAnalysis : public AnalysisInfoMixin<InlineAdvisorAnalysis> {
  191. public:
  192. static AnalysisKey Key;
  193. InlineAdvisorAnalysis() = default;
  194. struct Result {
  195. Result(Module &M, ModuleAnalysisManager &MAM) : M(M), MAM(MAM) {}
  196. bool invalidate(Module &, const PreservedAnalyses &,
  197. ModuleAnalysisManager::Invalidator &) {
  198. // InlineAdvisor must be preserved across analysis invalidations.
  199. return false;
  200. }
  201. bool tryCreate(InlineParams Params, InliningAdvisorMode Mode,
  202. StringRef ReplayFile);
  203. InlineAdvisor *getAdvisor() const { return Advisor.get(); }
  204. void clear() { Advisor.reset(); }
  205. private:
  206. Module &M;
  207. ModuleAnalysisManager &MAM;
  208. std::unique_ptr<InlineAdvisor> Advisor;
  209. };
  210. Result run(Module &M, ModuleAnalysisManager &MAM) { return Result(M, MAM); }
  211. };
  212. #ifdef LLVM_HAVE_TF_AOT
  213. std::unique_ptr<InlineAdvisor>
  214. getReleaseModeAdvisor(Module &M, ModuleAnalysisManager &MAM);
  215. #endif
  216. #ifdef LLVM_HAVE_TF_API
  217. std::unique_ptr<InlineAdvisor>
  218. getDevelopmentModeAdvisor(Module &M, ModuleAnalysisManager &MAM,
  219. std::function<bool(CallBase &)> GetDefaultAdvice);
  220. #endif
  221. // Default (manual policy) decision making helper APIs. Shared with the legacy
  222. // pass manager inliner.
  223. /// Return the cost only if the inliner should attempt to inline at the given
  224. /// CallSite. If we return the cost, we will emit an optimisation remark later
  225. /// using that cost, so we won't do so from this function. Return None if
  226. /// inlining should not be attempted.
  227. Optional<InlineCost>
  228. shouldInline(CallBase &CB, function_ref<InlineCost(CallBase &CB)> GetInlineCost,
  229. OptimizationRemarkEmitter &ORE, bool EnableDeferral = true);
  230. /// Emit ORE message.
  231. void emitInlinedInto(OptimizationRemarkEmitter &ORE, DebugLoc DLoc,
  232. const BasicBlock *Block, const Function &Callee,
  233. const Function &Caller, const InlineCost &IC,
  234. bool ForProfileContext = false,
  235. const char *PassName = nullptr);
  236. /// get call site location as string
  237. std::string getCallSiteLocation(DebugLoc DLoc);
  238. /// Add location info to ORE message.
  239. void addLocationToRemarks(OptimizationRemark &Remark, DebugLoc DLoc);
  240. /// Set the inline-remark attribute.
  241. void setInlineRemark(CallBase &CB, StringRef Message);
  242. /// Utility for extracting the inline cost message to a string.
  243. std::string inlineCostStr(const InlineCost &IC);
  244. } // namespace llvm
  245. #endif // LLVM_INLINEADVISOR_H_
  246. #ifdef __GNUC__
  247. #pragma GCC diagnostic pop
  248. #endif