xref: /llvm-project/llvm/include/llvm/Analysis/CtxProfAnalysis.h (revision b15845c0059b06f406e33f278127d7eb41ff5ab6)
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