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/DenseMap.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 19 namespace llvm { 20 21 class CtxProfAnalysis; 22 23 // Setting initial capacity to 1 because all contexts must have at least 1 24 // counter, and then, because all contexts belonging to a function have the same 25 // size, there'll be at most one other heap allocation. 26 using CtxProfFlatProfile = 27 DenseMap<GlobalValue::GUID, SmallVector<uint64_t, 1>>; 28 29 /// The instrumented contextual profile, produced by the CtxProfAnalysis. 30 class PGOContextualProfile { 31 friend class CtxProfAnalysis; 32 friend class CtxProfAnalysisPrinterPass; 33 struct FunctionInfo { 34 uint32_t NextCounterIndex = 0; 35 uint32_t NextCallsiteIndex = 0; 36 const std::string Name; 37 FunctionInfoFunctionInfo38 FunctionInfo(StringRef Name) : Name(Name) {} 39 }; 40 std::optional<PGOCtxProfContext::CallTargetMapTy> Profiles; 41 // For the GUIDs in this module, associate metadata about each function which 42 // we'll need when we maintain the profiles during IPO transformations. 43 DenseMap<GlobalValue::GUID, FunctionInfo> FuncInfo; 44 45 /// Get the GUID of this Function if it's defined in this module. 46 GlobalValue::GUID getDefinedFunctionGUID(const Function &F) const; 47 48 // This is meant to be constructed from CtxProfAnalysis, which will also set 49 // its state piecemeal. 50 PGOContextualProfile() = default; 51 52 public: 53 PGOContextualProfile(const PGOContextualProfile &) = delete; 54 PGOContextualProfile(PGOContextualProfile &&) = default; 55 56 operator bool() const { return Profiles.has_value(); } 57 profiles()58 const PGOCtxProfContext::CallTargetMapTy &profiles() const { 59 return *Profiles; 60 } 61 isFunctionKnown(const Function & F)62 bool isFunctionKnown(const Function &F) const { 63 return getDefinedFunctionGUID(F) != 0; 64 } 65 allocateNextCounterIndex(const Function & F)66 uint32_t allocateNextCounterIndex(const Function &F) { 67 assert(isFunctionKnown(F)); 68 return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCounterIndex++; 69 } 70 allocateNextCallsiteIndex(const Function & F)71 uint32_t allocateNextCallsiteIndex(const Function &F) { 72 assert(isFunctionKnown(F)); 73 return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCallsiteIndex++; 74 } 75 76 const CtxProfFlatProfile flatten() const; 77 invalidate(Module &,const PreservedAnalyses & PA,ModuleAnalysisManager::Invalidator &)78 bool invalidate(Module &, const PreservedAnalyses &PA, 79 ModuleAnalysisManager::Invalidator &) { 80 // Check whether the analysis has been explicitly invalidated. Otherwise, 81 // it's stateless and remains preserved. 82 auto PAC = PA.getChecker<CtxProfAnalysis>(); 83 return !PAC.preservedWhenStateless(); 84 } 85 }; 86 87 class CtxProfAnalysis : public AnalysisInfoMixin<CtxProfAnalysis> { 88 StringRef Profile; 89 90 public: 91 static AnalysisKey Key; 92 explicit CtxProfAnalysis(StringRef Profile = ""); 93 94 using Result = PGOContextualProfile; 95 96 PGOContextualProfile run(Module &M, ModuleAnalysisManager &MAM); 97 98 /// Get the instruction instrumenting a callsite, or nullptr if that cannot be 99 /// found. 100 static InstrProfCallsite *getCallsiteInstrumentation(CallBase &CB); 101 102 /// Get the instruction instrumenting a BB, or nullptr if not present. 103 static InstrProfIncrementInst *getBBInstrumentation(BasicBlock &BB); 104 }; 105 106 class CtxProfAnalysisPrinterPass 107 : public PassInfoMixin<CtxProfAnalysisPrinterPass> { 108 raw_ostream &OS; 109 110 public: CtxProfAnalysisPrinterPass(raw_ostream & OS)111 explicit CtxProfAnalysisPrinterPass(raw_ostream &OS) : OS(OS) {} 112 113 PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); isRequired()114 static bool isRequired() { return true; } 115 }; 116 117 /// Assign a GUID to functions as metadata. GUID calculation takes linkage into 118 /// account, which may change especially through and after thinlto. By 119 /// pre-computing and assigning as metadata, this mechanism is resilient to such 120 /// changes (as well as name changes e.g. suffix ".llvm." additions). 121 122 // FIXME(mtrofin): we can generalize this mechanism to calculate a GUID early in 123 // the pass pipeline, associate it with any Global Value, and then use it for 124 // PGO and ThinLTO. 125 // At that point, this should be moved elsewhere. 126 class AssignGUIDPass : public PassInfoMixin<AssignGUIDPass> { 127 public: 128 explicit AssignGUIDPass() = default; 129 130 /// Assign a GUID *if* one is not already assign, as a function metadata named 131 /// `GUIDMetadataName`. 132 PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); 133 static const char *GUIDMetadataName; 134 // This should become GlobalValue::getGUID 135 static uint64_t getGUID(const Function &F); 136 }; 137 138 } // namespace llvm 139 #endif // LLVM_ANALYSIS_CTXPROFANALYSIS_H 140