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