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