1dbbf0762SMircea Trofin //===- CtxProfAnalysis.h - maintain contextual profile info -*- C++ ---*-===// 2dbbf0762SMircea Trofin // 3dbbf0762SMircea Trofin // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4dbbf0762SMircea Trofin // See https://llvm.org/LICENSE.txt for license information. 5dbbf0762SMircea Trofin // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6dbbf0762SMircea Trofin // 7dbbf0762SMircea Trofin //===----------------------------------------------------------------------===// 8dbbf0762SMircea Trofin // 9dbbf0762SMircea Trofin #ifndef LLVM_ANALYSIS_CTXPROFANALYSIS_H 10dbbf0762SMircea Trofin #define LLVM_ANALYSIS_CTXPROFANALYSIS_H 11dbbf0762SMircea Trofin 12c8365feeSMircea Trofin #include "llvm/ADT/SetVector.h" 1322d3fb18SMircea Trofin #include "llvm/IR/GlobalValue.h" 14c8a678b1SMircea Trofin #include "llvm/IR/InstrTypes.h" 15c8a678b1SMircea Trofin #include "llvm/IR/IntrinsicInst.h" 16dbbf0762SMircea Trofin #include "llvm/IR/PassManager.h" 17dbbf0762SMircea Trofin #include "llvm/ProfileData/PGOCtxProfReader.h" 1832097666SMircea Trofin #include <optional> 19dbbf0762SMircea Trofin 20dbbf0762SMircea Trofin namespace llvm { 21dbbf0762SMircea Trofin 22dbbf0762SMircea Trofin class CtxProfAnalysis; 23dbbf0762SMircea Trofin 2422d3fb18SMircea Trofin // Setting initial capacity to 1 because all contexts must have at least 1 2522d3fb18SMircea Trofin // counter, and then, because all contexts belonging to a function have the same 2622d3fb18SMircea Trofin // size, there'll be at most one other heap allocation. 2722d3fb18SMircea Trofin using CtxProfFlatProfile = 28fe6c0250SMircea Trofin std::map<GlobalValue::GUID, SmallVector<uint64_t, 1>>; 2922d3fb18SMircea Trofin 30dbbf0762SMircea Trofin /// The instrumented contextual profile, produced by the CtxProfAnalysis. 31dbbf0762SMircea Trofin class PGOContextualProfile { 32aca01bffSMircea Trofin friend class CtxProfAnalysis; 33aca01bffSMircea Trofin friend class CtxProfAnalysisPrinterPass; 34aca01bffSMircea Trofin struct FunctionInfo { 35aca01bffSMircea Trofin uint32_t NextCounterIndex = 0; 36aca01bffSMircea Trofin uint32_t NextCallsiteIndex = 0; 37aca01bffSMircea Trofin const std::string Name; 38c4952e51SMircea Trofin PGOCtxProfContext Index; 39aca01bffSMircea Trofin FunctionInfo(StringRef Name) : Name(Name) {} 40aca01bffSMircea Trofin }; 41dbbf0762SMircea Trofin std::optional<PGOCtxProfContext::CallTargetMapTy> Profiles; 42aca01bffSMircea Trofin // For the GUIDs in this module, associate metadata about each function which 43aca01bffSMircea Trofin // we'll need when we maintain the profiles during IPO transformations. 44644c9020SMircea Trofin std::map<GlobalValue::GUID, FunctionInfo> FuncInfo; 45aca01bffSMircea Trofin 46aca01bffSMircea Trofin /// Get the GUID of this Function if it's defined in this module. 47aca01bffSMircea Trofin GlobalValue::GUID getDefinedFunctionGUID(const Function &F) const; 48aca01bffSMircea Trofin 49aca01bffSMircea Trofin // This is meant to be constructed from CtxProfAnalysis, which will also set 50aca01bffSMircea Trofin // its state piecemeal. 51aca01bffSMircea Trofin PGOContextualProfile() = default; 52dbbf0762SMircea Trofin 53c4952e51SMircea Trofin void initIndex(); 54c4952e51SMircea Trofin 55dbbf0762SMircea Trofin public: 56dbbf0762SMircea Trofin PGOContextualProfile(const PGOContextualProfile &) = delete; 57dbbf0762SMircea Trofin PGOContextualProfile(PGOContextualProfile &&) = default; 58dbbf0762SMircea Trofin 59dbbf0762SMircea Trofin operator bool() const { return Profiles.has_value(); } 60dbbf0762SMircea Trofin 61dbbf0762SMircea Trofin const PGOCtxProfContext::CallTargetMapTy &profiles() const { 62dbbf0762SMircea Trofin return *Profiles; 63dbbf0762SMircea Trofin } 64dbbf0762SMircea Trofin 65aca01bffSMircea Trofin bool isFunctionKnown(const Function &F) const { 66aca01bffSMircea Trofin return getDefinedFunctionGUID(F) != 0; 67aca01bffSMircea Trofin } 68aca01bffSMircea Trofin 69c8365feeSMircea Trofin StringRef getFunctionName(GlobalValue::GUID GUID) const { 70c8365feeSMircea Trofin auto It = FuncInfo.find(GUID); 71c8365feeSMircea Trofin if (It == FuncInfo.end()) 72c8365feeSMircea Trofin return ""; 73c8365feeSMircea Trofin return It->second.Name; 74c8365feeSMircea Trofin } 75c8365feeSMircea Trofin 7632097666SMircea Trofin uint32_t getNumCounters(const Function &F) const { 7732097666SMircea Trofin assert(isFunctionKnown(F)); 7832097666SMircea Trofin return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCounterIndex; 7932097666SMircea Trofin } 8032097666SMircea Trofin 8132097666SMircea Trofin uint32_t getNumCallsites(const Function &F) const { 8232097666SMircea Trofin assert(isFunctionKnown(F)); 8332097666SMircea Trofin return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCallsiteIndex; 8432097666SMircea Trofin } 8532097666SMircea Trofin 86aca01bffSMircea Trofin uint32_t allocateNextCounterIndex(const Function &F) { 87aca01bffSMircea Trofin assert(isFunctionKnown(F)); 88aca01bffSMircea Trofin return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCounterIndex++; 89aca01bffSMircea Trofin } 90aca01bffSMircea Trofin 91aca01bffSMircea Trofin uint32_t allocateNextCallsiteIndex(const Function &F) { 92aca01bffSMircea Trofin assert(isFunctionKnown(F)); 93aca01bffSMircea Trofin return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCallsiteIndex++; 94aca01bffSMircea Trofin } 95aca01bffSMircea Trofin 9673c3b733SMircea Trofin using ConstVisitor = function_ref<void(const PGOCtxProfContext &)>; 9773c3b733SMircea Trofin using Visitor = function_ref<void(PGOCtxProfContext &)>; 9873c3b733SMircea Trofin 99c4952e51SMircea Trofin void update(Visitor, const Function &F); 10073c3b733SMircea Trofin void visit(ConstVisitor, const Function *F = nullptr) const; 10173c3b733SMircea Trofin 10222d3fb18SMircea Trofin const CtxProfFlatProfile flatten() const; 10322d3fb18SMircea Trofin 104dbbf0762SMircea Trofin bool invalidate(Module &, const PreservedAnalyses &PA, 105dbbf0762SMircea Trofin ModuleAnalysisManager::Invalidator &) { 106dbbf0762SMircea Trofin // Check whether the analysis has been explicitly invalidated. Otherwise, 107dbbf0762SMircea Trofin // it's stateless and remains preserved. 108dbbf0762SMircea Trofin auto PAC = PA.getChecker<CtxProfAnalysis>(); 109dbbf0762SMircea Trofin return !PAC.preservedWhenStateless(); 110dbbf0762SMircea Trofin } 111dbbf0762SMircea Trofin }; 112dbbf0762SMircea Trofin 113dbbf0762SMircea Trofin class CtxProfAnalysis : public AnalysisInfoMixin<CtxProfAnalysis> { 11432097666SMircea Trofin const std::optional<StringRef> Profile; 115dbbf0762SMircea Trofin 116dbbf0762SMircea Trofin public: 117dbbf0762SMircea Trofin static AnalysisKey Key; 11832097666SMircea Trofin explicit CtxProfAnalysis(std::optional<StringRef> Profile = std::nullopt); 119dbbf0762SMircea Trofin 120dbbf0762SMircea Trofin using Result = PGOContextualProfile; 121dbbf0762SMircea Trofin 122dbbf0762SMircea Trofin PGOContextualProfile run(Module &M, ModuleAnalysisManager &MAM); 123c8a678b1SMircea Trofin 1241e70122cSMircea Trofin /// Get the instruction instrumenting a callsite, or nullptr if that cannot be 1251e70122cSMircea Trofin /// found. 126c8a678b1SMircea Trofin static InstrProfCallsite *getCallsiteInstrumentation(CallBase &CB); 1271e70122cSMircea Trofin 1281e70122cSMircea Trofin /// Get the instruction instrumenting a BB, or nullptr if not present. 1291e70122cSMircea Trofin static InstrProfIncrementInst *getBBInstrumentation(BasicBlock &BB); 130783bac7fSMircea Trofin 131783bac7fSMircea Trofin /// Get the step instrumentation associated with a `select` 132783bac7fSMircea Trofin static InstrProfIncrementInstStep *getSelectInstrumentation(SelectInst &SI); 133c8365feeSMircea Trofin 134c8365feeSMircea Trofin // FIXME: refactor to an advisor model, and separate 135c8365feeSMircea Trofin static void collectIndirectCallPromotionList( 136c8365feeSMircea Trofin CallBase &IC, Result &Profile, 137c8365feeSMircea Trofin SetVector<std::pair<CallBase *, Function *>> &Candidates); 138dbbf0762SMircea Trofin }; 139dbbf0762SMircea Trofin 140dbbf0762SMircea Trofin class CtxProfAnalysisPrinterPass 141dbbf0762SMircea Trofin : public PassInfoMixin<CtxProfAnalysisPrinterPass> { 142dbbf0762SMircea Trofin public: 143*b15845c0SMircea Trofin enum class PrintMode { Everything, YAML }; 14432097666SMircea Trofin explicit CtxProfAnalysisPrinterPass(raw_ostream &OS); 145dbbf0762SMircea Trofin 146dbbf0762SMircea Trofin PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); 147dbbf0762SMircea Trofin static bool isRequired() { return true; } 14873c3b733SMircea Trofin 14973c3b733SMircea Trofin private: 15073c3b733SMircea Trofin raw_ostream &OS; 15173c3b733SMircea Trofin const PrintMode Mode; 152dbbf0762SMircea Trofin }; 153aca01bffSMircea Trofin 154aca01bffSMircea Trofin /// Assign a GUID to functions as metadata. GUID calculation takes linkage into 155aca01bffSMircea Trofin /// account, which may change especially through and after thinlto. By 156aca01bffSMircea Trofin /// pre-computing and assigning as metadata, this mechanism is resilient to such 157aca01bffSMircea Trofin /// changes (as well as name changes e.g. suffix ".llvm." additions). 158aca01bffSMircea Trofin 159aca01bffSMircea Trofin // FIXME(mtrofin): we can generalize this mechanism to calculate a GUID early in 160aca01bffSMircea Trofin // the pass pipeline, associate it with any Global Value, and then use it for 161aca01bffSMircea Trofin // PGO and ThinLTO. 162aca01bffSMircea Trofin // At that point, this should be moved elsewhere. 163aca01bffSMircea Trofin class AssignGUIDPass : public PassInfoMixin<AssignGUIDPass> { 164aca01bffSMircea Trofin public: 165aca01bffSMircea Trofin explicit AssignGUIDPass() = default; 166aca01bffSMircea Trofin 167aca01bffSMircea Trofin /// Assign a GUID *if* one is not already assign, as a function metadata named 168aca01bffSMircea Trofin /// `GUIDMetadataName`. 169aca01bffSMircea Trofin PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); 170aca01bffSMircea Trofin static const char *GUIDMetadataName; 171aca01bffSMircea Trofin // This should become GlobalValue::getGUID 172aca01bffSMircea Trofin static uint64_t getGUID(const Function &F); 173aca01bffSMircea Trofin }; 174aca01bffSMircea Trofin 175dbbf0762SMircea Trofin } // namespace llvm 176dbbf0762SMircea Trofin #endif // LLVM_ANALYSIS_CTXPROFANALYSIS_H 177