• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- InlineAdvisor.h - Inlining decision making abstraction -*- C++ ---*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 #ifndef LLVM_INLINEADVISOR_H_
10 #define LLVM_INLINEADVISOR_H_
11 
12 #include <memory>
13 #include <unordered_set>
14 #include <vector>
15 
16 #include "llvm/Analysis/InlineCost.h"
17 #include "llvm/Config/llvm-config.h"
18 #include "llvm/IR/PassManager.h"
19 
20 namespace llvm {
21 class BasicBlock;
22 class CallBase;
23 class Function;
24 class Module;
25 class OptimizationRemarkEmitter;
26 
27 /// There are 4 scenarios we can use the InlineAdvisor:
28 /// - Default - use manual heuristics.
29 ///
30 /// - MandatoryOnly - only mandatory inlinings (i.e. AlwaysInline).
31 ///
32 /// - Release mode, the expected mode for production, day to day deployments.
33 /// In this mode, when building the compiler, we also compile a pre-trained ML
34 /// model to native code, and link it as a static library. This mode has low
35 /// overhead and no additional dependencies for the compiler runtime.
36 ///
37 /// - Development mode, for training new models.
38 /// In this mode, we trade off runtime performance for flexibility. This mode
39 /// requires the full C Tensorflow API library, and evaluates models
40 /// dynamically. This mode also permits generating training logs, for offline
41 /// training.
42 enum class InliningAdvisorMode : int {
43   Default,
44   MandatoryOnly,
45   Release,
46   Development
47 };
48 
49 class InlineAdvisor;
50 /// Capture state between an inlining decision having had been made, and
51 /// its impact being observable. When collecting model training data, this
52 /// allows recording features/decisions/partial reward data sets.
53 ///
54 /// Derivations of this type are expected to be tightly coupled with their
55 /// InliningAdvisors. The base type implements the minimal contractual
56 /// obligations.
57 class InlineAdvice {
58 public:
59   InlineAdvice(InlineAdvisor *Advisor, CallBase &CB,
60                OptimizationRemarkEmitter &ORE, bool IsInliningRecommended);
61 
62   InlineAdvice(InlineAdvice &&) = delete;
63   InlineAdvice(const InlineAdvice &) = delete;
~InlineAdvice()64   virtual ~InlineAdvice() {
65     assert(Recorded && "InlineAdvice should have been informed of the "
66                        "inliner's decision in all cases");
67   }
68 
69   /// Exactly one of the record* APIs must be called. Implementers may extend
70   /// behavior by implementing the corresponding record*Impl.
71   ///
72   /// Call after inlining succeeded, and did not result in deleting the callee.
recordInlining()73   void recordInlining() {
74     markRecorded();
75     recordInliningImpl();
76   }
77 
78   /// Call after inlining succeeded, and resulted in deleting the callee.
79   void recordInliningWithCalleeDeleted();
80 
81   /// Call after the decision for a call site was to not inline.
recordUnsuccessfulInlining(const InlineResult & Result)82   void recordUnsuccessfulInlining(const InlineResult &Result) {
83     markRecorded();
84     recordUnsuccessfulInliningImpl(Result);
85   }
86 
87   /// Call to indicate inlining was not attempted.
recordUnattemptedInlining()88   void recordUnattemptedInlining() {
89     markRecorded();
90     recordUnattemptedInliningImpl();
91   }
92 
93   /// Get the inlining recommendation.
isInliningRecommended()94   bool isInliningRecommended() const { return IsInliningRecommended; }
getOriginalCallSiteDebugLoc()95   const DebugLoc &getOriginalCallSiteDebugLoc() const { return DLoc; }
getOriginalCallSiteBasicBlock()96   const BasicBlock *getOriginalCallSiteBasicBlock() const { return Block; }
97 
98 protected:
recordInliningImpl()99   virtual void recordInliningImpl() {}
recordInliningWithCalleeDeletedImpl()100   virtual void recordInliningWithCalleeDeletedImpl() {}
recordUnsuccessfulInliningImpl(const InlineResult & Result)101   virtual void recordUnsuccessfulInliningImpl(const InlineResult &Result) {}
recordUnattemptedInliningImpl()102   virtual void recordUnattemptedInliningImpl() {}
103 
104   InlineAdvisor *const Advisor;
105   /// Caller and Callee are pre-inlining.
106   Function *const Caller;
107   Function *const Callee;
108 
109   // Capture the context of CB before inlining, as a successful inlining may
110   // change that context, and we want to report success or failure in the
111   // original context.
112   const DebugLoc DLoc;
113   const BasicBlock *const Block;
114   OptimizationRemarkEmitter &ORE;
115   const bool IsInliningRecommended;
116 
117 private:
markRecorded()118   void markRecorded() {
119     assert(!Recorded && "Recording should happen exactly once");
120     Recorded = true;
121   }
122 
123   bool Recorded = false;
124 };
125 
126 /// Interface for deciding whether to inline a call site or not.
127 class InlineAdvisor {
128 public:
129   InlineAdvisor(InlineAdvisor &&) = delete;
~InlineAdvisor()130   virtual ~InlineAdvisor() { freeDeletedFunctions(); }
131 
132   /// Get an InlineAdvice containing a recommendation on whether to
133   /// inline or not. \p CB is assumed to be a direct call. \p FAM is assumed to
134   /// be up-to-date wrt previous inlining decisions.
135   /// Returns an InlineAdvice with the inlining recommendation.
136   virtual std::unique_ptr<InlineAdvice> getAdvice(CallBase &CB) = 0;
137 
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).
onPassEntry()141   virtual void onPassEntry() {}
142 
143   /// This must be called when the Inliner pass is exited, as function passes
144   /// may be run subsequently. This allows an implementation of InlineAdvisor
145   /// to prepare for a partial update.
onPassExit()146   virtual void onPassExit() {}
147 
148 protected:
InlineAdvisor(FunctionAnalysisManager & FAM)149   InlineAdvisor(FunctionAnalysisManager &FAM) : FAM(FAM) {}
150 
151   FunctionAnalysisManager &FAM;
152 
153   /// We may want to defer deleting functions to after the inlining for a whole
154   /// module has finished. This allows us to reliably use function pointers as
155   /// unique identifiers, as an efficient implementation detail of the
156   /// InlineAdvisor. Otherwise, it is possible the memory allocator
157   /// re-allocate Function objects at the same address of a deleted Function;
158   /// and Functions are potentially created during the function passes called
159   /// after each SCC inlining (e.g. argument promotion does that).
160   void freeDeletedFunctions();
161 
isFunctionDeleted(const Function * F)162   bool isFunctionDeleted(const Function *F) const {
163     return DeletedFunctions.count(F);
164   }
165 
166 private:
167   friend class InlineAdvice;
168   void markFunctionAsDeleted(Function *F);
169   std::unordered_set<const Function *> DeletedFunctions;
170 };
171 
172 /// The default (manual heuristics) implementation of the InlineAdvisor. This
173 /// implementation does not need to keep state between inliner pass runs, and is
174 /// reusable as-is for inliner pass test scenarios, as well as for regular use.
175 class DefaultInlineAdvisor : public InlineAdvisor {
176 public:
DefaultInlineAdvisor(FunctionAnalysisManager & FAM,InlineParams Params)177   DefaultInlineAdvisor(FunctionAnalysisManager &FAM, InlineParams Params)
178       : InlineAdvisor(FAM), Params(Params) {}
179 
180 private:
181   std::unique_ptr<InlineAdvice> getAdvice(CallBase &CB) override;
182 
onPassExit()183   void onPassExit() override { freeDeletedFunctions(); }
184 
185   InlineParams Params;
186 };
187 
188 /// Advisor recommending only mandatory (AlwaysInline) cases.
189 class MandatoryInlineAdvisor final : public InlineAdvisor {
190   std::unique_ptr<InlineAdvice> getAdvice(CallBase &CB) override;
191 
192 public:
MandatoryInlineAdvisor(FunctionAnalysisManager & FAM)193   MandatoryInlineAdvisor(FunctionAnalysisManager &FAM) : InlineAdvisor(FAM) {}
194 
195   enum class MandatoryInliningKind { NotMandatory, Always, Never };
196 
197   static MandatoryInliningKind getMandatoryKind(CallBase &CB,
198                                                 FunctionAnalysisManager &FAM,
199                                                 OptimizationRemarkEmitter &ORE);
200 };
201 
202 /// The InlineAdvisorAnalysis is a module pass because the InlineAdvisor
203 /// needs to capture state right before inlining commences over a module.
204 class InlineAdvisorAnalysis : public AnalysisInfoMixin<InlineAdvisorAnalysis> {
205 public:
206   static AnalysisKey Key;
207   InlineAdvisorAnalysis() = default;
208   struct Result {
ResultResult209     Result(Module &M, ModuleAnalysisManager &MAM) : M(M), MAM(MAM) {}
invalidateResult210     bool invalidate(Module &, const PreservedAnalyses &,
211                     ModuleAnalysisManager::Invalidator &) {
212       // InlineAdvisor must be preserved across analysis invalidations.
213       return false;
214     }
215     bool tryCreate(InlineParams Params, InliningAdvisorMode Mode);
getAdvisorResult216     InlineAdvisor *getAdvisor() const { return Advisor.get(); }
clearResult217     void clear() { Advisor.reset(); }
218 
219   private:
220     Module &M;
221     ModuleAnalysisManager &MAM;
222     std::unique_ptr<InlineAdvisor> Advisor;
223   };
224 
run(Module & M,ModuleAnalysisManager & MAM)225   Result run(Module &M, ModuleAnalysisManager &MAM) { return Result(M, MAM); }
226 };
227 
228 #ifdef LLVM_HAVE_TF_AOT
229 std::unique_ptr<InlineAdvisor>
230 getReleaseModeAdvisor(Module &M, ModuleAnalysisManager &MAM);
231 #endif
232 
233 #ifdef LLVM_HAVE_TF_API
234 std::unique_ptr<InlineAdvisor>
235 getDevelopmentModeAdvisor(Module &M, ModuleAnalysisManager &MAM,
236                           std::function<bool(CallBase &)> GetDefaultAdvice);
237 #endif
238 
239 // Default (manual policy) decision making helper APIs. Shared with the legacy
240 // pass manager inliner.
241 
242 /// Return the cost only if the inliner should attempt to inline at the given
243 /// CallSite. If we return the cost, we will emit an optimisation remark later
244 /// using that cost, so we won't do so from this function. Return None if
245 /// inlining should not be attempted.
246 Optional<InlineCost>
247 shouldInline(CallBase &CB, function_ref<InlineCost(CallBase &CB)> GetInlineCost,
248              OptimizationRemarkEmitter &ORE, bool EnableDeferral = true);
249 
250 /// Emit ORE message.
251 void emitInlinedInto(OptimizationRemarkEmitter &ORE, DebugLoc DLoc,
252                      const BasicBlock *Block, const Function &Callee,
253                      const Function &Caller, const InlineCost &IC,
254                      bool ForProfileContext = false,
255                      const char *PassName = nullptr);
256 
257 /// get call site location as string
258 std::string getCallSiteLocation(DebugLoc DLoc);
259 
260 /// Add location info to ORE message.
261 void addLocationToRemarks(OptimizationRemark &Remark, DebugLoc DLoc);
262 
263 /// Set the inline-remark attribute.
264 void setInlineRemark(CallBase &CB, StringRef Message);
265 
266 /// Utility for extracting the inline cost message to a string.
267 std::string inlineCostStr(const InlineCost &IC);
268 } // namespace llvm
269 #endif // LLVM_INLINEADVISOR_H_
270