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