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