//===- CtxProfAnalysis.h - maintain contextual profile info -*- C++ ---*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // #ifndef LLVM_ANALYSIS_CTXPROFANALYSIS_H #define LLVM_ANALYSIS_CTXPROFANALYSIS_H #include "llvm/ADT/DenseMap.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/PassManager.h" #include "llvm/ProfileData/PGOCtxProfReader.h" namespace llvm { class CtxProfAnalysis; // Setting initial capacity to 1 because all contexts must have at least 1 // counter, and then, because all contexts belonging to a function have the same // size, there'll be at most one other heap allocation. using CtxProfFlatProfile = DenseMap>; /// The instrumented contextual profile, produced by the CtxProfAnalysis. class PGOContextualProfile { friend class CtxProfAnalysis; friend class CtxProfAnalysisPrinterPass; struct FunctionInfo { uint32_t NextCounterIndex = 0; uint32_t NextCallsiteIndex = 0; const std::string Name; FunctionInfo(StringRef Name) : Name(Name) {} }; std::optional Profiles; // For the GUIDs in this module, associate metadata about each function which // we'll need when we maintain the profiles during IPO transformations. DenseMap FuncInfo; /// Get the GUID of this Function if it's defined in this module. GlobalValue::GUID getDefinedFunctionGUID(const Function &F) const; // This is meant to be constructed from CtxProfAnalysis, which will also set // its state piecemeal. PGOContextualProfile() = default; public: PGOContextualProfile(const PGOContextualProfile &) = delete; PGOContextualProfile(PGOContextualProfile &&) = default; operator bool() const { return Profiles.has_value(); } const PGOCtxProfContext::CallTargetMapTy &profiles() const { return *Profiles; } bool isFunctionKnown(const Function &F) const { return getDefinedFunctionGUID(F) != 0; } uint32_t allocateNextCounterIndex(const Function &F) { assert(isFunctionKnown(F)); return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCounterIndex++; } uint32_t allocateNextCallsiteIndex(const Function &F) { assert(isFunctionKnown(F)); return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCallsiteIndex++; } const CtxProfFlatProfile flatten() const; bool invalidate(Module &, const PreservedAnalyses &PA, ModuleAnalysisManager::Invalidator &) { // Check whether the analysis has been explicitly invalidated. Otherwise, // it's stateless and remains preserved. auto PAC = PA.getChecker(); return !PAC.preservedWhenStateless(); } }; class CtxProfAnalysis : public AnalysisInfoMixin { StringRef Profile; public: static AnalysisKey Key; explicit CtxProfAnalysis(StringRef Profile = ""); using Result = PGOContextualProfile; PGOContextualProfile run(Module &M, ModuleAnalysisManager &MAM); /// Get the instruction instrumenting a callsite, or nullptr if that cannot be /// found. static InstrProfCallsite *getCallsiteInstrumentation(CallBase &CB); /// Get the instruction instrumenting a BB, or nullptr if not present. static InstrProfIncrementInst *getBBInstrumentation(BasicBlock &BB); }; class CtxProfAnalysisPrinterPass : public PassInfoMixin { raw_ostream &OS; public: explicit CtxProfAnalysisPrinterPass(raw_ostream &OS) : OS(OS) {} PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); static bool isRequired() { return true; } }; /// Assign a GUID to functions as metadata. GUID calculation takes linkage into /// account, which may change especially through and after thinlto. By /// pre-computing and assigning as metadata, this mechanism is resilient to such /// changes (as well as name changes e.g. suffix ".llvm." additions). // FIXME(mtrofin): we can generalize this mechanism to calculate a GUID early in // the pass pipeline, associate it with any Global Value, and then use it for // PGO and ThinLTO. // At that point, this should be moved elsewhere. class AssignGUIDPass : public PassInfoMixin { public: explicit AssignGUIDPass() = default; /// Assign a GUID *if* one is not already assign, as a function metadata named /// `GUIDMetadataName`. PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); static const char *GUIDMetadataName; // This should become GlobalValue::getGUID static uint64_t getGUID(const Function &F); }; } // namespace llvm #endif // LLVM_ANALYSIS_CTXPROFANALYSIS_H