1 //===- CtxProfAnalysis.h - maintain contextual profile info -*- 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_CTXPROFANALYSIS_H 10 #define LLVM_ANALYSIS_CTXPROFANALYSIS_H 11 12 #include "llvm/ADT/SetVector.h" 13 #include "llvm/IR/GlobalValue.h" 14 #include "llvm/IR/InstrTypes.h" 15 #include "llvm/IR/IntrinsicInst.h" 16 #include "llvm/IR/PassManager.h" 17 #include "llvm/ProfileData/PGOCtxProfReader.h" 18 #include <optional> 19 20 namespace llvm { 21 22 class CtxProfAnalysis; 23 24 // Setting initial capacity to 1 because all contexts must have at least 1 25 // counter, and then, because all contexts belonging to a function have the same 26 // size, there'll be at most one other heap allocation. 27 using CtxProfFlatProfile = 28 std::map<GlobalValue::GUID, SmallVector<uint64_t, 1>>; 29 30 /// The instrumented contextual profile, produced by the CtxProfAnalysis. 31 class PGOContextualProfile { 32 friend class CtxProfAnalysis; 33 friend class CtxProfAnalysisPrinterPass; 34 struct FunctionInfo { 35 uint32_t NextCounterIndex = 0; 36 uint32_t NextCallsiteIndex = 0; 37 const std::string Name; 38 PGOCtxProfContext Index; 39 FunctionInfo(StringRef Name) : Name(Name) {} 40 }; 41 std::optional<PGOCtxProfContext::CallTargetMapTy> Profiles; 42 // For the GUIDs in this module, associate metadata about each function which 43 // we'll need when we maintain the profiles during IPO transformations. 44 std::map<GlobalValue::GUID, FunctionInfo> FuncInfo; 45 46 /// Get the GUID of this Function if it's defined in this module. 47 GlobalValue::GUID getDefinedFunctionGUID(const Function &F) const; 48 49 // This is meant to be constructed from CtxProfAnalysis, which will also set 50 // its state piecemeal. 51 PGOContextualProfile() = default; 52 53 void initIndex(); 54 55 public: 56 PGOContextualProfile(const PGOContextualProfile &) = delete; 57 PGOContextualProfile(PGOContextualProfile &&) = default; 58 59 operator bool() const { return Profiles.has_value(); } 60 61 const PGOCtxProfContext::CallTargetMapTy &profiles() const { 62 return *Profiles; 63 } 64 65 bool isFunctionKnown(const Function &F) const { 66 return getDefinedFunctionGUID(F) != 0; 67 } 68 69 StringRef getFunctionName(GlobalValue::GUID GUID) const { 70 auto It = FuncInfo.find(GUID); 71 if (It == FuncInfo.end()) 72 return ""; 73 return It->second.Name; 74 } 75 76 uint32_t getNumCounters(const Function &F) const { 77 assert(isFunctionKnown(F)); 78 return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCounterIndex; 79 } 80 81 uint32_t getNumCallsites(const Function &F) const { 82 assert(isFunctionKnown(F)); 83 return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCallsiteIndex; 84 } 85 86 uint32_t allocateNextCounterIndex(const Function &F) { 87 assert(isFunctionKnown(F)); 88 return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCounterIndex++; 89 } 90 91 uint32_t allocateNextCallsiteIndex(const Function &F) { 92 assert(isFunctionKnown(F)); 93 return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCallsiteIndex++; 94 } 95 96 using ConstVisitor = function_ref<void(const PGOCtxProfContext &)>; 97 using Visitor = function_ref<void(PGOCtxProfContext &)>; 98 99 void update(Visitor, const Function &F); 100 void visit(ConstVisitor, const Function *F = nullptr) const; 101 102 const CtxProfFlatProfile flatten() const; 103 104 bool invalidate(Module &, const PreservedAnalyses &PA, 105 ModuleAnalysisManager::Invalidator &) { 106 // Check whether the analysis has been explicitly invalidated. Otherwise, 107 // it's stateless and remains preserved. 108 auto PAC = PA.getChecker<CtxProfAnalysis>(); 109 return !PAC.preservedWhenStateless(); 110 } 111 }; 112 113 class CtxProfAnalysis : public AnalysisInfoMixin<CtxProfAnalysis> { 114 const std::optional<StringRef> Profile; 115 116 public: 117 static AnalysisKey Key; 118 explicit CtxProfAnalysis(std::optional<StringRef> Profile = std::nullopt); 119 120 using Result = PGOContextualProfile; 121 122 PGOContextualProfile run(Module &M, ModuleAnalysisManager &MAM); 123 124 /// Get the instruction instrumenting a callsite, or nullptr if that cannot be 125 /// found. 126 static InstrProfCallsite *getCallsiteInstrumentation(CallBase &CB); 127 128 /// Get the instruction instrumenting a BB, or nullptr if not present. 129 static InstrProfIncrementInst *getBBInstrumentation(BasicBlock &BB); 130 131 /// Get the step instrumentation associated with a `select` 132 static InstrProfIncrementInstStep *getSelectInstrumentation(SelectInst &SI); 133 134 // FIXME: refactor to an advisor model, and separate 135 static void collectIndirectCallPromotionList( 136 CallBase &IC, Result &Profile, 137 SetVector<std::pair<CallBase *, Function *>> &Candidates); 138 }; 139 140 class CtxProfAnalysisPrinterPass 141 : public PassInfoMixin<CtxProfAnalysisPrinterPass> { 142 public: 143 enum class PrintMode { Everything, YAML }; 144 explicit CtxProfAnalysisPrinterPass(raw_ostream &OS); 145 146 PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); 147 static bool isRequired() { return true; } 148 149 private: 150 raw_ostream &OS; 151 const PrintMode Mode; 152 }; 153 154 /// Assign a GUID to functions as metadata. GUID calculation takes linkage into 155 /// account, which may change especially through and after thinlto. By 156 /// pre-computing and assigning as metadata, this mechanism is resilient to such 157 /// changes (as well as name changes e.g. suffix ".llvm." additions). 158 159 // FIXME(mtrofin): we can generalize this mechanism to calculate a GUID early in 160 // the pass pipeline, associate it with any Global Value, and then use it for 161 // PGO and ThinLTO. 162 // At that point, this should be moved elsewhere. 163 class AssignGUIDPass : public PassInfoMixin<AssignGUIDPass> { 164 public: 165 explicit AssignGUIDPass() = default; 166 167 /// Assign a GUID *if* one is not already assign, as a function metadata named 168 /// `GUIDMetadataName`. 169 PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); 170 static const char *GUIDMetadataName; 171 // This should become GlobalValue::getGUID 172 static uint64_t getGUID(const Function &F); 173 }; 174 175 } // namespace llvm 176 #endif // LLVM_ANALYSIS_CTXPROFANALYSIS_H 177