xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1e8d8bef9SDimitry Andric //===- MemProfiler.cpp - memory allocation and access profiler ------------===//
2e8d8bef9SDimitry Andric //
3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e8d8bef9SDimitry Andric //
7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8e8d8bef9SDimitry Andric //
9e8d8bef9SDimitry Andric // This file is a part of MemProfiler. Memory accesses are instrumented
10e8d8bef9SDimitry Andric // to increment the access count held in a shadow memory location, or
11e8d8bef9SDimitry Andric // alternatively to call into the runtime. Memory intrinsic calls (memmove,
12e8d8bef9SDimitry Andric // memcpy, memset) are changed to call the memory profiling runtime version
13e8d8bef9SDimitry Andric // instead.
14e8d8bef9SDimitry Andric //
15e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
16e8d8bef9SDimitry Andric 
17e8d8bef9SDimitry Andric #include "llvm/Transforms/Instrumentation/MemProfiler.h"
18e8d8bef9SDimitry Andric #include "llvm/ADT/SmallVector.h"
19e8d8bef9SDimitry Andric #include "llvm/ADT/Statistic.h"
20e8d8bef9SDimitry Andric #include "llvm/ADT/StringRef.h"
2106c3fb27SDimitry Andric #include "llvm/Analysis/MemoryBuiltins.h"
2206c3fb27SDimitry Andric #include "llvm/Analysis/MemoryProfileInfo.h"
23349cc55cSDimitry Andric #include "llvm/Analysis/ValueTracking.h"
24e8d8bef9SDimitry Andric #include "llvm/IR/Constant.h"
25e8d8bef9SDimitry Andric #include "llvm/IR/DataLayout.h"
2606c3fb27SDimitry Andric #include "llvm/IR/DiagnosticInfo.h"
27e8d8bef9SDimitry Andric #include "llvm/IR/Function.h"
28e8d8bef9SDimitry Andric #include "llvm/IR/GlobalValue.h"
29e8d8bef9SDimitry Andric #include "llvm/IR/IRBuilder.h"
30e8d8bef9SDimitry Andric #include "llvm/IR/Instruction.h"
311fd87a68SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
32e8d8bef9SDimitry Andric #include "llvm/IR/Module.h"
33e8d8bef9SDimitry Andric #include "llvm/IR/Type.h"
34e8d8bef9SDimitry Andric #include "llvm/IR/Value.h"
3581ad6265SDimitry Andric #include "llvm/ProfileData/InstrProf.h"
3606c3fb27SDimitry Andric #include "llvm/ProfileData/InstrProfReader.h"
3706c3fb27SDimitry Andric #include "llvm/Support/BLAKE3.h"
38e8d8bef9SDimitry Andric #include "llvm/Support/CommandLine.h"
39e8d8bef9SDimitry Andric #include "llvm/Support/Debug.h"
4006c3fb27SDimitry Andric #include "llvm/Support/HashBuilder.h"
4106c3fb27SDimitry Andric #include "llvm/Support/VirtualFileSystem.h"
4206c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
43e8d8bef9SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h"
44e8d8bef9SDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h"
4506c3fb27SDimitry Andric #include <map>
4606c3fb27SDimitry Andric #include <set>
47e8d8bef9SDimitry Andric 
48e8d8bef9SDimitry Andric using namespace llvm;
4906c3fb27SDimitry Andric using namespace llvm::memprof;
50e8d8bef9SDimitry Andric 
51e8d8bef9SDimitry Andric #define DEBUG_TYPE "memprof"
52e8d8bef9SDimitry Andric 
5306c3fb27SDimitry Andric namespace llvm {
5406c3fb27SDimitry Andric extern cl::opt<bool> PGOWarnMissing;
5506c3fb27SDimitry Andric extern cl::opt<bool> NoPGOWarnMismatch;
5606c3fb27SDimitry Andric extern cl::opt<bool> NoPGOWarnMismatchComdatWeak;
5706c3fb27SDimitry Andric } // namespace llvm
5806c3fb27SDimitry Andric 
59e8d8bef9SDimitry Andric constexpr int LLVM_MEM_PROFILER_VERSION = 1;
60e8d8bef9SDimitry Andric 
61e8d8bef9SDimitry Andric // Size of memory mapped to a single shadow location.
62*0fca6ea1SDimitry Andric constexpr uint64_t DefaultMemGranularity = 64;
63e8d8bef9SDimitry Andric 
64e8d8bef9SDimitry Andric // Scale from granularity down to shadow size.
65e8d8bef9SDimitry Andric constexpr uint64_t DefaultShadowScale = 3;
66e8d8bef9SDimitry Andric 
67e8d8bef9SDimitry Andric constexpr char MemProfModuleCtorName[] = "memprof.module_ctor";
68e8d8bef9SDimitry Andric constexpr uint64_t MemProfCtorAndDtorPriority = 1;
69e8d8bef9SDimitry Andric // On Emscripten, the system needs more than one priorities for constructors.
70e8d8bef9SDimitry Andric constexpr uint64_t MemProfEmscriptenCtorAndDtorPriority = 50;
71e8d8bef9SDimitry Andric constexpr char MemProfInitName[] = "__memprof_init";
72e8d8bef9SDimitry Andric constexpr char MemProfVersionCheckNamePrefix[] =
73e8d8bef9SDimitry Andric     "__memprof_version_mismatch_check_v";
74e8d8bef9SDimitry Andric 
75e8d8bef9SDimitry Andric constexpr char MemProfShadowMemoryDynamicAddress[] =
76e8d8bef9SDimitry Andric     "__memprof_shadow_memory_dynamic_address";
77e8d8bef9SDimitry Andric 
78e8d8bef9SDimitry Andric constexpr char MemProfFilenameVar[] = "__memprof_profile_filename";
79e8d8bef9SDimitry Andric 
80*0fca6ea1SDimitry Andric constexpr char MemProfHistogramFlagVar[] = "__memprof_histogram";
81*0fca6ea1SDimitry Andric 
82e8d8bef9SDimitry Andric // Command-line flags.
83e8d8bef9SDimitry Andric 
84e8d8bef9SDimitry Andric static cl::opt<bool> ClInsertVersionCheck(
85e8d8bef9SDimitry Andric     "memprof-guard-against-version-mismatch",
86e8d8bef9SDimitry Andric     cl::desc("Guard against compiler/runtime version mismatch."), cl::Hidden,
87e8d8bef9SDimitry Andric     cl::init(true));
88e8d8bef9SDimitry Andric 
89e8d8bef9SDimitry Andric // This flag may need to be replaced with -f[no-]memprof-reads.
90e8d8bef9SDimitry Andric static cl::opt<bool> ClInstrumentReads("memprof-instrument-reads",
91e8d8bef9SDimitry Andric                                        cl::desc("instrument read instructions"),
92e8d8bef9SDimitry Andric                                        cl::Hidden, cl::init(true));
93e8d8bef9SDimitry Andric 
94e8d8bef9SDimitry Andric static cl::opt<bool>
95e8d8bef9SDimitry Andric     ClInstrumentWrites("memprof-instrument-writes",
96e8d8bef9SDimitry Andric                        cl::desc("instrument write instructions"), cl::Hidden,
97e8d8bef9SDimitry Andric                        cl::init(true));
98e8d8bef9SDimitry Andric 
99e8d8bef9SDimitry Andric static cl::opt<bool> ClInstrumentAtomics(
100e8d8bef9SDimitry Andric     "memprof-instrument-atomics",
101e8d8bef9SDimitry Andric     cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden,
102e8d8bef9SDimitry Andric     cl::init(true));
103e8d8bef9SDimitry Andric 
104e8d8bef9SDimitry Andric static cl::opt<bool> ClUseCalls(
105e8d8bef9SDimitry Andric     "memprof-use-callbacks",
106e8d8bef9SDimitry Andric     cl::desc("Use callbacks instead of inline instrumentation sequences."),
107e8d8bef9SDimitry Andric     cl::Hidden, cl::init(false));
108e8d8bef9SDimitry Andric 
109e8d8bef9SDimitry Andric static cl::opt<std::string>
110e8d8bef9SDimitry Andric     ClMemoryAccessCallbackPrefix("memprof-memory-access-callback-prefix",
111e8d8bef9SDimitry Andric                                  cl::desc("Prefix for memory access callbacks"),
112e8d8bef9SDimitry Andric                                  cl::Hidden, cl::init("__memprof_"));
113e8d8bef9SDimitry Andric 
114e8d8bef9SDimitry Andric // These flags allow to change the shadow mapping.
115e8d8bef9SDimitry Andric // The shadow mapping looks like
116e8d8bef9SDimitry Andric //    Shadow = ((Mem & mask) >> scale) + offset
117e8d8bef9SDimitry Andric 
118e8d8bef9SDimitry Andric static cl::opt<int> ClMappingScale("memprof-mapping-scale",
119e8d8bef9SDimitry Andric                                    cl::desc("scale of memprof shadow mapping"),
120e8d8bef9SDimitry Andric                                    cl::Hidden, cl::init(DefaultShadowScale));
121e8d8bef9SDimitry Andric 
122e8d8bef9SDimitry Andric static cl::opt<int>
123e8d8bef9SDimitry Andric     ClMappingGranularity("memprof-mapping-granularity",
124e8d8bef9SDimitry Andric                          cl::desc("granularity of memprof shadow mapping"),
125*0fca6ea1SDimitry Andric                          cl::Hidden, cl::init(DefaultMemGranularity));
126e8d8bef9SDimitry Andric 
127349cc55cSDimitry Andric static cl::opt<bool> ClStack("memprof-instrument-stack",
128349cc55cSDimitry Andric                              cl::desc("Instrument scalar stack variables"),
129349cc55cSDimitry Andric                              cl::Hidden, cl::init(false));
130349cc55cSDimitry Andric 
131e8d8bef9SDimitry Andric // Debug flags.
132e8d8bef9SDimitry Andric 
133e8d8bef9SDimitry Andric static cl::opt<int> ClDebug("memprof-debug", cl::desc("debug"), cl::Hidden,
134e8d8bef9SDimitry Andric                             cl::init(0));
135e8d8bef9SDimitry Andric 
136e8d8bef9SDimitry Andric static cl::opt<std::string> ClDebugFunc("memprof-debug-func", cl::Hidden,
137e8d8bef9SDimitry Andric                                         cl::desc("Debug func"));
138e8d8bef9SDimitry Andric 
139e8d8bef9SDimitry Andric static cl::opt<int> ClDebugMin("memprof-debug-min", cl::desc("Debug min inst"),
140e8d8bef9SDimitry Andric                                cl::Hidden, cl::init(-1));
141e8d8bef9SDimitry Andric 
142e8d8bef9SDimitry Andric static cl::opt<int> ClDebugMax("memprof-debug-max", cl::desc("Debug max inst"),
143e8d8bef9SDimitry Andric                                cl::Hidden, cl::init(-1));
144e8d8bef9SDimitry Andric 
145*0fca6ea1SDimitry Andric // By default disable matching of allocation profiles onto operator new that
146*0fca6ea1SDimitry Andric // already explicitly pass a hot/cold hint, since we don't currently
147*0fca6ea1SDimitry Andric // override these hints anyway.
148*0fca6ea1SDimitry Andric static cl::opt<bool> ClMemProfMatchHotColdNew(
149*0fca6ea1SDimitry Andric     "memprof-match-hot-cold-new",
150*0fca6ea1SDimitry Andric  cl::desc(
151*0fca6ea1SDimitry Andric         "Match allocation profiles onto existing hot/cold operator new calls"),
152*0fca6ea1SDimitry Andric     cl::Hidden, cl::init(false));
153*0fca6ea1SDimitry Andric 
154*0fca6ea1SDimitry Andric static cl::opt<bool> ClHistogram("memprof-histogram",
155*0fca6ea1SDimitry Andric                                  cl::desc("Collect access count histograms"),
156*0fca6ea1SDimitry Andric                                  cl::Hidden, cl::init(false));
157*0fca6ea1SDimitry Andric 
158*0fca6ea1SDimitry Andric static cl::opt<bool>
159*0fca6ea1SDimitry Andric     ClPrintMemProfMatchInfo("memprof-print-match-info",
160*0fca6ea1SDimitry Andric                             cl::desc("Print matching stats for each allocation "
161*0fca6ea1SDimitry Andric                                      "context in this module's profiles"),
162*0fca6ea1SDimitry Andric                             cl::Hidden, cl::init(false));
163*0fca6ea1SDimitry Andric 
164*0fca6ea1SDimitry Andric extern cl::opt<bool> MemProfReportHintedSizes;
165*0fca6ea1SDimitry Andric 
166*0fca6ea1SDimitry Andric // Instrumentation statistics
167e8d8bef9SDimitry Andric STATISTIC(NumInstrumentedReads, "Number of instrumented reads");
168e8d8bef9SDimitry Andric STATISTIC(NumInstrumentedWrites, "Number of instrumented writes");
169349cc55cSDimitry Andric STATISTIC(NumSkippedStackReads, "Number of non-instrumented stack reads");
170349cc55cSDimitry Andric STATISTIC(NumSkippedStackWrites, "Number of non-instrumented stack writes");
171*0fca6ea1SDimitry Andric 
172*0fca6ea1SDimitry Andric // Matching statistics
17306c3fb27SDimitry Andric STATISTIC(NumOfMemProfMissing, "Number of functions without memory profile.");
174*0fca6ea1SDimitry Andric STATISTIC(NumOfMemProfMismatch,
175*0fca6ea1SDimitry Andric           "Number of functions having mismatched memory profile hash.");
176*0fca6ea1SDimitry Andric STATISTIC(NumOfMemProfFunc, "Number of functions having valid memory profile.");
177*0fca6ea1SDimitry Andric STATISTIC(NumOfMemProfAllocContextProfiles,
178*0fca6ea1SDimitry Andric           "Number of alloc contexts in memory profile.");
179*0fca6ea1SDimitry Andric STATISTIC(NumOfMemProfCallSiteProfiles,
180*0fca6ea1SDimitry Andric           "Number of callsites in memory profile.");
181*0fca6ea1SDimitry Andric STATISTIC(NumOfMemProfMatchedAllocContexts,
182*0fca6ea1SDimitry Andric           "Number of matched memory profile alloc contexts.");
183*0fca6ea1SDimitry Andric STATISTIC(NumOfMemProfMatchedAllocs,
184*0fca6ea1SDimitry Andric           "Number of matched memory profile allocs.");
185*0fca6ea1SDimitry Andric STATISTIC(NumOfMemProfMatchedCallSites,
186*0fca6ea1SDimitry Andric           "Number of matched memory profile callsites.");
187e8d8bef9SDimitry Andric 
188e8d8bef9SDimitry Andric namespace {
189e8d8bef9SDimitry Andric 
190e8d8bef9SDimitry Andric /// This struct defines the shadow mapping using the rule:
191e8d8bef9SDimitry Andric ///   shadow = ((mem & mask) >> Scale) ADD DynamicShadowOffset.
192e8d8bef9SDimitry Andric struct ShadowMapping {
193e8d8bef9SDimitry Andric   ShadowMapping() {
194e8d8bef9SDimitry Andric     Scale = ClMappingScale;
195e8d8bef9SDimitry Andric     Granularity = ClMappingGranularity;
196e8d8bef9SDimitry Andric     Mask = ~(Granularity - 1);
197e8d8bef9SDimitry Andric   }
198e8d8bef9SDimitry Andric 
199e8d8bef9SDimitry Andric   int Scale;
200e8d8bef9SDimitry Andric   int Granularity;
201e8d8bef9SDimitry Andric   uint64_t Mask; // Computed as ~(Granularity-1)
202e8d8bef9SDimitry Andric };
203e8d8bef9SDimitry Andric 
204e8d8bef9SDimitry Andric static uint64_t getCtorAndDtorPriority(Triple &TargetTriple) {
205e8d8bef9SDimitry Andric   return TargetTriple.isOSEmscripten() ? MemProfEmscriptenCtorAndDtorPriority
206e8d8bef9SDimitry Andric                                        : MemProfCtorAndDtorPriority;
207e8d8bef9SDimitry Andric }
208e8d8bef9SDimitry Andric 
209e8d8bef9SDimitry Andric struct InterestingMemoryAccess {
210e8d8bef9SDimitry Andric   Value *Addr = nullptr;
211e8d8bef9SDimitry Andric   bool IsWrite;
21204eeddc0SDimitry Andric   Type *AccessTy;
213e8d8bef9SDimitry Andric   Value *MaybeMask = nullptr;
214e8d8bef9SDimitry Andric };
215e8d8bef9SDimitry Andric 
216e8d8bef9SDimitry Andric /// Instrument the code in module to profile memory accesses.
217e8d8bef9SDimitry Andric class MemProfiler {
218e8d8bef9SDimitry Andric public:
219e8d8bef9SDimitry Andric   MemProfiler(Module &M) {
220e8d8bef9SDimitry Andric     C = &(M.getContext());
221e8d8bef9SDimitry Andric     LongSize = M.getDataLayout().getPointerSizeInBits();
222e8d8bef9SDimitry Andric     IntptrTy = Type::getIntNTy(*C, LongSize);
2235f757f3fSDimitry Andric     PtrTy = PointerType::getUnqual(*C);
224e8d8bef9SDimitry Andric   }
225e8d8bef9SDimitry Andric 
226e8d8bef9SDimitry Andric   /// If it is an interesting memory access, populate information
227e8d8bef9SDimitry Andric   /// about the access and return a InterestingMemoryAccess struct.
228bdd1243dSDimitry Andric   /// Otherwise return std::nullopt.
229bdd1243dSDimitry Andric   std::optional<InterestingMemoryAccess>
230e8d8bef9SDimitry Andric   isInterestingMemoryAccess(Instruction *I) const;
231e8d8bef9SDimitry Andric 
232e8d8bef9SDimitry Andric   void instrumentMop(Instruction *I, const DataLayout &DL,
233e8d8bef9SDimitry Andric                      InterestingMemoryAccess &Access);
234e8d8bef9SDimitry Andric   void instrumentAddress(Instruction *OrigIns, Instruction *InsertBefore,
235*0fca6ea1SDimitry Andric                          Value *Addr, bool IsWrite);
236e8d8bef9SDimitry Andric   void instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask,
23781ad6265SDimitry Andric                                    Instruction *I, Value *Addr, Type *AccessTy,
238e8d8bef9SDimitry Andric                                    bool IsWrite);
239e8d8bef9SDimitry Andric   void instrumentMemIntrinsic(MemIntrinsic *MI);
240e8d8bef9SDimitry Andric   Value *memToShadow(Value *Shadow, IRBuilder<> &IRB);
241e8d8bef9SDimitry Andric   bool instrumentFunction(Function &F);
242e8d8bef9SDimitry Andric   bool maybeInsertMemProfInitAtFunctionEntry(Function &F);
243e8d8bef9SDimitry Andric   bool insertDynamicShadowAtFunctionEntry(Function &F);
244e8d8bef9SDimitry Andric 
245e8d8bef9SDimitry Andric private:
246e8d8bef9SDimitry Andric   void initializeCallbacks(Module &M);
247e8d8bef9SDimitry Andric 
248e8d8bef9SDimitry Andric   LLVMContext *C;
249e8d8bef9SDimitry Andric   int LongSize;
250e8d8bef9SDimitry Andric   Type *IntptrTy;
2515f757f3fSDimitry Andric   PointerType *PtrTy;
252e8d8bef9SDimitry Andric   ShadowMapping Mapping;
253e8d8bef9SDimitry Andric 
254e8d8bef9SDimitry Andric   // These arrays is indexed by AccessIsWrite
255e8d8bef9SDimitry Andric   FunctionCallee MemProfMemoryAccessCallback[2];
256e8d8bef9SDimitry Andric 
257e8d8bef9SDimitry Andric   FunctionCallee MemProfMemmove, MemProfMemcpy, MemProfMemset;
258e8d8bef9SDimitry Andric   Value *DynamicShadowOffset = nullptr;
259e8d8bef9SDimitry Andric };
260e8d8bef9SDimitry Andric 
261e8d8bef9SDimitry Andric class ModuleMemProfiler {
262e8d8bef9SDimitry Andric public:
263e8d8bef9SDimitry Andric   ModuleMemProfiler(Module &M) { TargetTriple = Triple(M.getTargetTriple()); }
264e8d8bef9SDimitry Andric 
265e8d8bef9SDimitry Andric   bool instrumentModule(Module &);
266e8d8bef9SDimitry Andric 
267e8d8bef9SDimitry Andric private:
268e8d8bef9SDimitry Andric   Triple TargetTriple;
269e8d8bef9SDimitry Andric   ShadowMapping Mapping;
270e8d8bef9SDimitry Andric   Function *MemProfCtorFunction = nullptr;
271e8d8bef9SDimitry Andric };
272e8d8bef9SDimitry Andric 
273e8d8bef9SDimitry Andric } // end anonymous namespace
274e8d8bef9SDimitry Andric 
27581ad6265SDimitry Andric MemProfilerPass::MemProfilerPass() = default;
276e8d8bef9SDimitry Andric 
277e8d8bef9SDimitry Andric PreservedAnalyses MemProfilerPass::run(Function &F,
278e8d8bef9SDimitry Andric                                        AnalysisManager<Function> &AM) {
279e8d8bef9SDimitry Andric   Module &M = *F.getParent();
280e8d8bef9SDimitry Andric   MemProfiler Profiler(M);
281e8d8bef9SDimitry Andric   if (Profiler.instrumentFunction(F))
282e8d8bef9SDimitry Andric     return PreservedAnalyses::none();
283e8d8bef9SDimitry Andric   return PreservedAnalyses::all();
284e8d8bef9SDimitry Andric }
285e8d8bef9SDimitry Andric 
28681ad6265SDimitry Andric ModuleMemProfilerPass::ModuleMemProfilerPass() = default;
287e8d8bef9SDimitry Andric 
288e8d8bef9SDimitry Andric PreservedAnalyses ModuleMemProfilerPass::run(Module &M,
289e8d8bef9SDimitry Andric                                              AnalysisManager<Module> &AM) {
290*0fca6ea1SDimitry Andric 
291*0fca6ea1SDimitry Andric   assert((!ClHistogram || (ClHistogram && ClUseCalls)) &&
292*0fca6ea1SDimitry Andric          "Cannot use -memprof-histogram without Callbacks. Set "
293*0fca6ea1SDimitry Andric          "memprof-use-callbacks");
294*0fca6ea1SDimitry Andric 
295e8d8bef9SDimitry Andric   ModuleMemProfiler Profiler(M);
296e8d8bef9SDimitry Andric   if (Profiler.instrumentModule(M))
297e8d8bef9SDimitry Andric     return PreservedAnalyses::none();
298e8d8bef9SDimitry Andric   return PreservedAnalyses::all();
299e8d8bef9SDimitry Andric }
300e8d8bef9SDimitry Andric 
301e8d8bef9SDimitry Andric Value *MemProfiler::memToShadow(Value *Shadow, IRBuilder<> &IRB) {
302e8d8bef9SDimitry Andric   // (Shadow & mask) >> scale
303e8d8bef9SDimitry Andric   Shadow = IRB.CreateAnd(Shadow, Mapping.Mask);
304e8d8bef9SDimitry Andric   Shadow = IRB.CreateLShr(Shadow, Mapping.Scale);
305e8d8bef9SDimitry Andric   // (Shadow >> scale) | offset
306e8d8bef9SDimitry Andric   assert(DynamicShadowOffset);
307e8d8bef9SDimitry Andric   return IRB.CreateAdd(Shadow, DynamicShadowOffset);
308e8d8bef9SDimitry Andric }
309e8d8bef9SDimitry Andric 
310e8d8bef9SDimitry Andric // Instrument memset/memmove/memcpy
311e8d8bef9SDimitry Andric void MemProfiler::instrumentMemIntrinsic(MemIntrinsic *MI) {
312e8d8bef9SDimitry Andric   IRBuilder<> IRB(MI);
313e8d8bef9SDimitry Andric   if (isa<MemTransferInst>(MI)) {
3145f757f3fSDimitry Andric     IRB.CreateCall(isa<MemMoveInst>(MI) ? MemProfMemmove : MemProfMemcpy,
3155f757f3fSDimitry Andric                    {MI->getOperand(0), MI->getOperand(1),
316e8d8bef9SDimitry Andric                     IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)});
317e8d8bef9SDimitry Andric   } else if (isa<MemSetInst>(MI)) {
318e8d8bef9SDimitry Andric     IRB.CreateCall(
319e8d8bef9SDimitry Andric         MemProfMemset,
3205f757f3fSDimitry Andric         {MI->getOperand(0),
321e8d8bef9SDimitry Andric          IRB.CreateIntCast(MI->getOperand(1), IRB.getInt32Ty(), false),
322e8d8bef9SDimitry Andric          IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)});
323e8d8bef9SDimitry Andric   }
324e8d8bef9SDimitry Andric   MI->eraseFromParent();
325e8d8bef9SDimitry Andric }
326e8d8bef9SDimitry Andric 
327bdd1243dSDimitry Andric std::optional<InterestingMemoryAccess>
328e8d8bef9SDimitry Andric MemProfiler::isInterestingMemoryAccess(Instruction *I) const {
329e8d8bef9SDimitry Andric   // Do not instrument the load fetching the dynamic shadow address.
330e8d8bef9SDimitry Andric   if (DynamicShadowOffset == I)
331bdd1243dSDimitry Andric     return std::nullopt;
332e8d8bef9SDimitry Andric 
333e8d8bef9SDimitry Andric   InterestingMemoryAccess Access;
334e8d8bef9SDimitry Andric 
335e8d8bef9SDimitry Andric   if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
336e8d8bef9SDimitry Andric     if (!ClInstrumentReads)
337bdd1243dSDimitry Andric       return std::nullopt;
338e8d8bef9SDimitry Andric     Access.IsWrite = false;
33904eeddc0SDimitry Andric     Access.AccessTy = LI->getType();
340e8d8bef9SDimitry Andric     Access.Addr = LI->getPointerOperand();
341e8d8bef9SDimitry Andric   } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
342e8d8bef9SDimitry Andric     if (!ClInstrumentWrites)
343bdd1243dSDimitry Andric       return std::nullopt;
344e8d8bef9SDimitry Andric     Access.IsWrite = true;
34504eeddc0SDimitry Andric     Access.AccessTy = SI->getValueOperand()->getType();
346e8d8bef9SDimitry Andric     Access.Addr = SI->getPointerOperand();
347e8d8bef9SDimitry Andric   } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
348e8d8bef9SDimitry Andric     if (!ClInstrumentAtomics)
349bdd1243dSDimitry Andric       return std::nullopt;
350e8d8bef9SDimitry Andric     Access.IsWrite = true;
35104eeddc0SDimitry Andric     Access.AccessTy = RMW->getValOperand()->getType();
352e8d8bef9SDimitry Andric     Access.Addr = RMW->getPointerOperand();
353e8d8bef9SDimitry Andric   } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
354e8d8bef9SDimitry Andric     if (!ClInstrumentAtomics)
355bdd1243dSDimitry Andric       return std::nullopt;
356e8d8bef9SDimitry Andric     Access.IsWrite = true;
35704eeddc0SDimitry Andric     Access.AccessTy = XCHG->getCompareOperand()->getType();
358e8d8bef9SDimitry Andric     Access.Addr = XCHG->getPointerOperand();
359e8d8bef9SDimitry Andric   } else if (auto *CI = dyn_cast<CallInst>(I)) {
360e8d8bef9SDimitry Andric     auto *F = CI->getCalledFunction();
361e8d8bef9SDimitry Andric     if (F && (F->getIntrinsicID() == Intrinsic::masked_load ||
362e8d8bef9SDimitry Andric               F->getIntrinsicID() == Intrinsic::masked_store)) {
363e8d8bef9SDimitry Andric       unsigned OpOffset = 0;
364e8d8bef9SDimitry Andric       if (F->getIntrinsicID() == Intrinsic::masked_store) {
365e8d8bef9SDimitry Andric         if (!ClInstrumentWrites)
366bdd1243dSDimitry Andric           return std::nullopt;
367e8d8bef9SDimitry Andric         // Masked store has an initial operand for the value.
368e8d8bef9SDimitry Andric         OpOffset = 1;
36904eeddc0SDimitry Andric         Access.AccessTy = CI->getArgOperand(0)->getType();
370e8d8bef9SDimitry Andric         Access.IsWrite = true;
371e8d8bef9SDimitry Andric       } else {
372e8d8bef9SDimitry Andric         if (!ClInstrumentReads)
373bdd1243dSDimitry Andric           return std::nullopt;
37404eeddc0SDimitry Andric         Access.AccessTy = CI->getType();
375e8d8bef9SDimitry Andric         Access.IsWrite = false;
376e8d8bef9SDimitry Andric       }
377e8d8bef9SDimitry Andric 
378e8d8bef9SDimitry Andric       auto *BasePtr = CI->getOperand(0 + OpOffset);
379e8d8bef9SDimitry Andric       Access.MaybeMask = CI->getOperand(2 + OpOffset);
380e8d8bef9SDimitry Andric       Access.Addr = BasePtr;
381e8d8bef9SDimitry Andric     }
382e8d8bef9SDimitry Andric   }
383e8d8bef9SDimitry Andric 
384e8d8bef9SDimitry Andric   if (!Access.Addr)
385bdd1243dSDimitry Andric     return std::nullopt;
386e8d8bef9SDimitry Andric 
387bdd1243dSDimitry Andric   // Do not instrument accesses from different address spaces; we cannot deal
388e8d8bef9SDimitry Andric   // with them.
389e8d8bef9SDimitry Andric   Type *PtrTy = cast<PointerType>(Access.Addr->getType()->getScalarType());
390e8d8bef9SDimitry Andric   if (PtrTy->getPointerAddressSpace() != 0)
391bdd1243dSDimitry Andric     return std::nullopt;
392e8d8bef9SDimitry Andric 
393e8d8bef9SDimitry Andric   // Ignore swifterror addresses.
394e8d8bef9SDimitry Andric   // swifterror memory addresses are mem2reg promoted by instruction
395e8d8bef9SDimitry Andric   // selection. As such they cannot have regular uses like an instrumentation
396e8d8bef9SDimitry Andric   // function and it makes no sense to track them as memory.
397e8d8bef9SDimitry Andric   if (Access.Addr->isSwiftError())
398bdd1243dSDimitry Andric     return std::nullopt;
399e8d8bef9SDimitry Andric 
40081ad6265SDimitry Andric   // Peel off GEPs and BitCasts.
40181ad6265SDimitry Andric   auto *Addr = Access.Addr->stripInBoundsOffsets();
40281ad6265SDimitry Andric 
40381ad6265SDimitry Andric   if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Addr)) {
40481ad6265SDimitry Andric     // Do not instrument PGO counter updates.
40581ad6265SDimitry Andric     if (GV->hasSection()) {
40681ad6265SDimitry Andric       StringRef SectionName = GV->getSection();
40781ad6265SDimitry Andric       // Check if the global is in the PGO counters section.
40881ad6265SDimitry Andric       auto OF = Triple(I->getModule()->getTargetTriple()).getObjectFormat();
4095f757f3fSDimitry Andric       if (SectionName.ends_with(
41081ad6265SDimitry Andric               getInstrProfSectionName(IPSK_cnts, OF, /*AddSegmentInfo=*/false)))
411bdd1243dSDimitry Andric         return std::nullopt;
41281ad6265SDimitry Andric     }
41381ad6265SDimitry Andric 
41481ad6265SDimitry Andric     // Do not instrument accesses to LLVM internal variables.
4155f757f3fSDimitry Andric     if (GV->getName().starts_with("__llvm"))
416bdd1243dSDimitry Andric       return std::nullopt;
41781ad6265SDimitry Andric   }
41881ad6265SDimitry Andric 
419e8d8bef9SDimitry Andric   return Access;
420e8d8bef9SDimitry Andric }
421e8d8bef9SDimitry Andric 
422e8d8bef9SDimitry Andric void MemProfiler::instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask,
423e8d8bef9SDimitry Andric                                               Instruction *I, Value *Addr,
42404eeddc0SDimitry Andric                                               Type *AccessTy, bool IsWrite) {
42504eeddc0SDimitry Andric   auto *VTy = cast<FixedVectorType>(AccessTy);
426e8d8bef9SDimitry Andric   unsigned Num = VTy->getNumElements();
427e8d8bef9SDimitry Andric   auto *Zero = ConstantInt::get(IntptrTy, 0);
428e8d8bef9SDimitry Andric   for (unsigned Idx = 0; Idx < Num; ++Idx) {
429e8d8bef9SDimitry Andric     Value *InstrumentedAddress = nullptr;
430e8d8bef9SDimitry Andric     Instruction *InsertBefore = I;
431e8d8bef9SDimitry Andric     if (auto *Vector = dyn_cast<ConstantVector>(Mask)) {
432e8d8bef9SDimitry Andric       // dyn_cast as we might get UndefValue
433e8d8bef9SDimitry Andric       if (auto *Masked = dyn_cast<ConstantInt>(Vector->getOperand(Idx))) {
434e8d8bef9SDimitry Andric         if (Masked->isZero())
435e8d8bef9SDimitry Andric           // Mask is constant false, so no instrumentation needed.
436e8d8bef9SDimitry Andric           continue;
437e8d8bef9SDimitry Andric         // If we have a true or undef value, fall through to instrumentAddress.
438e8d8bef9SDimitry Andric         // with InsertBefore == I
439e8d8bef9SDimitry Andric       }
440e8d8bef9SDimitry Andric     } else {
441e8d8bef9SDimitry Andric       IRBuilder<> IRB(I);
442e8d8bef9SDimitry Andric       Value *MaskElem = IRB.CreateExtractElement(Mask, Idx);
443e8d8bef9SDimitry Andric       Instruction *ThenTerm = SplitBlockAndInsertIfThen(MaskElem, I, false);
444e8d8bef9SDimitry Andric       InsertBefore = ThenTerm;
445e8d8bef9SDimitry Andric     }
446e8d8bef9SDimitry Andric 
447e8d8bef9SDimitry Andric     IRBuilder<> IRB(InsertBefore);
448e8d8bef9SDimitry Andric     InstrumentedAddress =
449e8d8bef9SDimitry Andric         IRB.CreateGEP(VTy, Addr, {Zero, ConstantInt::get(IntptrTy, Idx)});
450*0fca6ea1SDimitry Andric     instrumentAddress(I, InsertBefore, InstrumentedAddress, IsWrite);
451e8d8bef9SDimitry Andric   }
452e8d8bef9SDimitry Andric }
453e8d8bef9SDimitry Andric 
454e8d8bef9SDimitry Andric void MemProfiler::instrumentMop(Instruction *I, const DataLayout &DL,
455e8d8bef9SDimitry Andric                                 InterestingMemoryAccess &Access) {
456349cc55cSDimitry Andric   // Skip instrumentation of stack accesses unless requested.
457349cc55cSDimitry Andric   if (!ClStack && isa<AllocaInst>(getUnderlyingObject(Access.Addr))) {
458349cc55cSDimitry Andric     if (Access.IsWrite)
459349cc55cSDimitry Andric       ++NumSkippedStackWrites;
460349cc55cSDimitry Andric     else
461349cc55cSDimitry Andric       ++NumSkippedStackReads;
462349cc55cSDimitry Andric     return;
463349cc55cSDimitry Andric   }
464349cc55cSDimitry Andric 
465e8d8bef9SDimitry Andric   if (Access.IsWrite)
466e8d8bef9SDimitry Andric     NumInstrumentedWrites++;
467e8d8bef9SDimitry Andric   else
468e8d8bef9SDimitry Andric     NumInstrumentedReads++;
469e8d8bef9SDimitry Andric 
470e8d8bef9SDimitry Andric   if (Access.MaybeMask) {
471e8d8bef9SDimitry Andric     instrumentMaskedLoadOrStore(DL, Access.MaybeMask, I, Access.Addr,
47281ad6265SDimitry Andric                                 Access.AccessTy, Access.IsWrite);
473e8d8bef9SDimitry Andric   } else {
474e8d8bef9SDimitry Andric     // Since the access counts will be accumulated across the entire allocation,
475e8d8bef9SDimitry Andric     // we only update the shadow access count for the first location and thus
476e8d8bef9SDimitry Andric     // don't need to worry about alignment and type size.
477*0fca6ea1SDimitry Andric     instrumentAddress(I, I, Access.Addr, Access.IsWrite);
478e8d8bef9SDimitry Andric   }
479e8d8bef9SDimitry Andric }
480e8d8bef9SDimitry Andric 
481e8d8bef9SDimitry Andric void MemProfiler::instrumentAddress(Instruction *OrigIns,
482e8d8bef9SDimitry Andric                                     Instruction *InsertBefore, Value *Addr,
483*0fca6ea1SDimitry Andric                                     bool IsWrite) {
484e8d8bef9SDimitry Andric   IRBuilder<> IRB(InsertBefore);
485e8d8bef9SDimitry Andric   Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
486e8d8bef9SDimitry Andric 
487e8d8bef9SDimitry Andric   if (ClUseCalls) {
488e8d8bef9SDimitry Andric     IRB.CreateCall(MemProfMemoryAccessCallback[IsWrite], AddrLong);
489e8d8bef9SDimitry Andric     return;
490e8d8bef9SDimitry Andric   }
491e8d8bef9SDimitry Andric 
492e8d8bef9SDimitry Andric   // Create an inline sequence to compute shadow location, and increment the
493e8d8bef9SDimitry Andric   // value by one.
494e8d8bef9SDimitry Andric   Type *ShadowTy = Type::getInt64Ty(*C);
495e8d8bef9SDimitry Andric   Type *ShadowPtrTy = PointerType::get(ShadowTy, 0);
496e8d8bef9SDimitry Andric   Value *ShadowPtr = memToShadow(AddrLong, IRB);
497e8d8bef9SDimitry Andric   Value *ShadowAddr = IRB.CreateIntToPtr(ShadowPtr, ShadowPtrTy);
498e8d8bef9SDimitry Andric   Value *ShadowValue = IRB.CreateLoad(ShadowTy, ShadowAddr);
499e8d8bef9SDimitry Andric   Value *Inc = ConstantInt::get(Type::getInt64Ty(*C), 1);
500e8d8bef9SDimitry Andric   ShadowValue = IRB.CreateAdd(ShadowValue, Inc);
501e8d8bef9SDimitry Andric   IRB.CreateStore(ShadowValue, ShadowAddr);
502e8d8bef9SDimitry Andric }
503e8d8bef9SDimitry Andric 
504e8d8bef9SDimitry Andric // Create the variable for the profile file name.
505e8d8bef9SDimitry Andric void createProfileFileNameVar(Module &M) {
506e8d8bef9SDimitry Andric   const MDString *MemProfFilename =
507e8d8bef9SDimitry Andric       dyn_cast_or_null<MDString>(M.getModuleFlag("MemProfProfileFilename"));
508e8d8bef9SDimitry Andric   if (!MemProfFilename)
509e8d8bef9SDimitry Andric     return;
510e8d8bef9SDimitry Andric   assert(!MemProfFilename->getString().empty() &&
511e8d8bef9SDimitry Andric          "Unexpected MemProfProfileFilename metadata with empty string");
512e8d8bef9SDimitry Andric   Constant *ProfileNameConst = ConstantDataArray::getString(
513e8d8bef9SDimitry Andric       M.getContext(), MemProfFilename->getString(), true);
514e8d8bef9SDimitry Andric   GlobalVariable *ProfileNameVar = new GlobalVariable(
515e8d8bef9SDimitry Andric       M, ProfileNameConst->getType(), /*isConstant=*/true,
516e8d8bef9SDimitry Andric       GlobalValue::WeakAnyLinkage, ProfileNameConst, MemProfFilenameVar);
517e8d8bef9SDimitry Andric   Triple TT(M.getTargetTriple());
518e8d8bef9SDimitry Andric   if (TT.supportsCOMDAT()) {
519e8d8bef9SDimitry Andric     ProfileNameVar->setLinkage(GlobalValue::ExternalLinkage);
520e8d8bef9SDimitry Andric     ProfileNameVar->setComdat(M.getOrInsertComdat(MemProfFilenameVar));
521e8d8bef9SDimitry Andric   }
522e8d8bef9SDimitry Andric }
523e8d8bef9SDimitry Andric 
524*0fca6ea1SDimitry Andric // Set MemprofHistogramFlag as a Global veriable in IR. This makes it accessible
525*0fca6ea1SDimitry Andric // to the runtime, changing shadow count behavior.
526*0fca6ea1SDimitry Andric void createMemprofHistogramFlagVar(Module &M) {
527*0fca6ea1SDimitry Andric   const StringRef VarName(MemProfHistogramFlagVar);
528*0fca6ea1SDimitry Andric   Type *IntTy1 = Type::getInt1Ty(M.getContext());
529*0fca6ea1SDimitry Andric   auto MemprofHistogramFlag = new GlobalVariable(
530*0fca6ea1SDimitry Andric       M, IntTy1, true, GlobalValue::WeakAnyLinkage,
531*0fca6ea1SDimitry Andric       Constant::getIntegerValue(IntTy1, APInt(1, ClHistogram)), VarName);
532*0fca6ea1SDimitry Andric   Triple TT(M.getTargetTriple());
533*0fca6ea1SDimitry Andric   if (TT.supportsCOMDAT()) {
534*0fca6ea1SDimitry Andric     MemprofHistogramFlag->setLinkage(GlobalValue::ExternalLinkage);
535*0fca6ea1SDimitry Andric     MemprofHistogramFlag->setComdat(M.getOrInsertComdat(VarName));
536*0fca6ea1SDimitry Andric   }
537*0fca6ea1SDimitry Andric   appendToCompilerUsed(M, MemprofHistogramFlag);
538*0fca6ea1SDimitry Andric }
539*0fca6ea1SDimitry Andric 
540e8d8bef9SDimitry Andric bool ModuleMemProfiler::instrumentModule(Module &M) {
541*0fca6ea1SDimitry Andric 
542e8d8bef9SDimitry Andric   // Create a module constructor.
543e8d8bef9SDimitry Andric   std::string MemProfVersion = std::to_string(LLVM_MEM_PROFILER_VERSION);
544e8d8bef9SDimitry Andric   std::string VersionCheckName =
545e8d8bef9SDimitry Andric       ClInsertVersionCheck ? (MemProfVersionCheckNamePrefix + MemProfVersion)
546e8d8bef9SDimitry Andric                            : "";
547e8d8bef9SDimitry Andric   std::tie(MemProfCtorFunction, std::ignore) =
548e8d8bef9SDimitry Andric       createSanitizerCtorAndInitFunctions(M, MemProfModuleCtorName,
549e8d8bef9SDimitry Andric                                           MemProfInitName, /*InitArgTypes=*/{},
550e8d8bef9SDimitry Andric                                           /*InitArgs=*/{}, VersionCheckName);
551e8d8bef9SDimitry Andric 
552e8d8bef9SDimitry Andric   const uint64_t Priority = getCtorAndDtorPriority(TargetTriple);
553e8d8bef9SDimitry Andric   appendToGlobalCtors(M, MemProfCtorFunction, Priority);
554e8d8bef9SDimitry Andric 
555e8d8bef9SDimitry Andric   createProfileFileNameVar(M);
556e8d8bef9SDimitry Andric 
557*0fca6ea1SDimitry Andric   createMemprofHistogramFlagVar(M);
558*0fca6ea1SDimitry Andric 
559e8d8bef9SDimitry Andric   return true;
560e8d8bef9SDimitry Andric }
561e8d8bef9SDimitry Andric 
562e8d8bef9SDimitry Andric void MemProfiler::initializeCallbacks(Module &M) {
563e8d8bef9SDimitry Andric   IRBuilder<> IRB(*C);
564e8d8bef9SDimitry Andric 
565e8d8bef9SDimitry Andric   for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
566e8d8bef9SDimitry Andric     const std::string TypeStr = AccessIsWrite ? "store" : "load";
567*0fca6ea1SDimitry Andric     const std::string HistPrefix = ClHistogram ? "hist_" : "";
568e8d8bef9SDimitry Andric 
569e8d8bef9SDimitry Andric     SmallVector<Type *, 2> Args1{1, IntptrTy};
570*0fca6ea1SDimitry Andric     MemProfMemoryAccessCallback[AccessIsWrite] = M.getOrInsertFunction(
571*0fca6ea1SDimitry Andric         ClMemoryAccessCallbackPrefix + HistPrefix + TypeStr,
572e8d8bef9SDimitry Andric         FunctionType::get(IRB.getVoidTy(), Args1, false));
573e8d8bef9SDimitry Andric   }
574e8d8bef9SDimitry Andric   MemProfMemmove = M.getOrInsertFunction(
5755f757f3fSDimitry Andric       ClMemoryAccessCallbackPrefix + "memmove", PtrTy, PtrTy, PtrTy, IntptrTy);
576e8d8bef9SDimitry Andric   MemProfMemcpy = M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + "memcpy",
5775f757f3fSDimitry Andric                                         PtrTy, PtrTy, PtrTy, IntptrTy);
5785f757f3fSDimitry Andric   MemProfMemset =
5795f757f3fSDimitry Andric       M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + "memset", PtrTy,
5805f757f3fSDimitry Andric                             PtrTy, IRB.getInt32Ty(), IntptrTy);
581e8d8bef9SDimitry Andric }
582e8d8bef9SDimitry Andric 
583e8d8bef9SDimitry Andric bool MemProfiler::maybeInsertMemProfInitAtFunctionEntry(Function &F) {
584e8d8bef9SDimitry Andric   // For each NSObject descendant having a +load method, this method is invoked
585e8d8bef9SDimitry Andric   // by the ObjC runtime before any of the static constructors is called.
586e8d8bef9SDimitry Andric   // Therefore we need to instrument such methods with a call to __memprof_init
587e8d8bef9SDimitry Andric   // at the beginning in order to initialize our runtime before any access to
588e8d8bef9SDimitry Andric   // the shadow memory.
589e8d8bef9SDimitry Andric   // We cannot just ignore these methods, because they may call other
590e8d8bef9SDimitry Andric   // instrumented functions.
591cb14a3feSDimitry Andric   if (F.getName().contains(" load]")) {
592e8d8bef9SDimitry Andric     FunctionCallee MemProfInitFunction =
593e8d8bef9SDimitry Andric         declareSanitizerInitFunction(*F.getParent(), MemProfInitName, {});
594e8d8bef9SDimitry Andric     IRBuilder<> IRB(&F.front(), F.front().begin());
595e8d8bef9SDimitry Andric     IRB.CreateCall(MemProfInitFunction, {});
596e8d8bef9SDimitry Andric     return true;
597e8d8bef9SDimitry Andric   }
598e8d8bef9SDimitry Andric   return false;
599e8d8bef9SDimitry Andric }
600e8d8bef9SDimitry Andric 
601e8d8bef9SDimitry Andric bool MemProfiler::insertDynamicShadowAtFunctionEntry(Function &F) {
602e8d8bef9SDimitry Andric   IRBuilder<> IRB(&F.front().front());
603e8d8bef9SDimitry Andric   Value *GlobalDynamicAddress = F.getParent()->getOrInsertGlobal(
604e8d8bef9SDimitry Andric       MemProfShadowMemoryDynamicAddress, IntptrTy);
605e8d8bef9SDimitry Andric   if (F.getParent()->getPICLevel() == PICLevel::NotPIC)
606e8d8bef9SDimitry Andric     cast<GlobalVariable>(GlobalDynamicAddress)->setDSOLocal(true);
607e8d8bef9SDimitry Andric   DynamicShadowOffset = IRB.CreateLoad(IntptrTy, GlobalDynamicAddress);
608e8d8bef9SDimitry Andric   return true;
609e8d8bef9SDimitry Andric }
610e8d8bef9SDimitry Andric 
611e8d8bef9SDimitry Andric bool MemProfiler::instrumentFunction(Function &F) {
612e8d8bef9SDimitry Andric   if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage)
613e8d8bef9SDimitry Andric     return false;
614e8d8bef9SDimitry Andric   if (ClDebugFunc == F.getName())
615e8d8bef9SDimitry Andric     return false;
6165f757f3fSDimitry Andric   if (F.getName().starts_with("__memprof_"))
617e8d8bef9SDimitry Andric     return false;
618e8d8bef9SDimitry Andric 
619e8d8bef9SDimitry Andric   bool FunctionModified = false;
620e8d8bef9SDimitry Andric 
621e8d8bef9SDimitry Andric   // If needed, insert __memprof_init.
622e8d8bef9SDimitry Andric   // This function needs to be called even if the function body is not
623e8d8bef9SDimitry Andric   // instrumented.
624e8d8bef9SDimitry Andric   if (maybeInsertMemProfInitAtFunctionEntry(F))
625e8d8bef9SDimitry Andric     FunctionModified = true;
626e8d8bef9SDimitry Andric 
627e8d8bef9SDimitry Andric   LLVM_DEBUG(dbgs() << "MEMPROF instrumenting:\n" << F << "\n");
628e8d8bef9SDimitry Andric 
629e8d8bef9SDimitry Andric   initializeCallbacks(*F.getParent());
630e8d8bef9SDimitry Andric 
631e8d8bef9SDimitry Andric   SmallVector<Instruction *, 16> ToInstrument;
632e8d8bef9SDimitry Andric 
633e8d8bef9SDimitry Andric   // Fill the set of memory operations to instrument.
634e8d8bef9SDimitry Andric   for (auto &BB : F) {
635e8d8bef9SDimitry Andric     for (auto &Inst : BB) {
636e8d8bef9SDimitry Andric       if (isInterestingMemoryAccess(&Inst) || isa<MemIntrinsic>(Inst))
637e8d8bef9SDimitry Andric         ToInstrument.push_back(&Inst);
638e8d8bef9SDimitry Andric     }
639e8d8bef9SDimitry Andric   }
640e8d8bef9SDimitry Andric 
64181ad6265SDimitry Andric   if (ToInstrument.empty()) {
64281ad6265SDimitry Andric     LLVM_DEBUG(dbgs() << "MEMPROF done instrumenting: " << FunctionModified
64381ad6265SDimitry Andric                       << " " << F << "\n");
64481ad6265SDimitry Andric 
64581ad6265SDimitry Andric     return FunctionModified;
64681ad6265SDimitry Andric   }
64781ad6265SDimitry Andric 
64881ad6265SDimitry Andric   FunctionModified |= insertDynamicShadowAtFunctionEntry(F);
64981ad6265SDimitry Andric 
650e8d8bef9SDimitry Andric   int NumInstrumented = 0;
651e8d8bef9SDimitry Andric   for (auto *Inst : ToInstrument) {
652e8d8bef9SDimitry Andric     if (ClDebugMin < 0 || ClDebugMax < 0 ||
653e8d8bef9SDimitry Andric         (NumInstrumented >= ClDebugMin && NumInstrumented <= ClDebugMax)) {
654bdd1243dSDimitry Andric       std::optional<InterestingMemoryAccess> Access =
655e8d8bef9SDimitry Andric           isInterestingMemoryAccess(Inst);
656e8d8bef9SDimitry Andric       if (Access)
657*0fca6ea1SDimitry Andric         instrumentMop(Inst, F.getDataLayout(), *Access);
658e8d8bef9SDimitry Andric       else
659e8d8bef9SDimitry Andric         instrumentMemIntrinsic(cast<MemIntrinsic>(Inst));
660e8d8bef9SDimitry Andric     }
661e8d8bef9SDimitry Andric     NumInstrumented++;
662e8d8bef9SDimitry Andric   }
663e8d8bef9SDimitry Andric 
664e8d8bef9SDimitry Andric   if (NumInstrumented > 0)
665e8d8bef9SDimitry Andric     FunctionModified = true;
666e8d8bef9SDimitry Andric 
667e8d8bef9SDimitry Andric   LLVM_DEBUG(dbgs() << "MEMPROF done instrumenting: " << FunctionModified << " "
668e8d8bef9SDimitry Andric                     << F << "\n");
669e8d8bef9SDimitry Andric 
670e8d8bef9SDimitry Andric   return FunctionModified;
671e8d8bef9SDimitry Andric }
67206c3fb27SDimitry Andric 
67306c3fb27SDimitry Andric static void addCallsiteMetadata(Instruction &I,
67406c3fb27SDimitry Andric                                 std::vector<uint64_t> &InlinedCallStack,
67506c3fb27SDimitry Andric                                 LLVMContext &Ctx) {
67606c3fb27SDimitry Andric   I.setMetadata(LLVMContext::MD_callsite,
67706c3fb27SDimitry Andric                 buildCallstackMetadata(InlinedCallStack, Ctx));
67806c3fb27SDimitry Andric }
67906c3fb27SDimitry Andric 
68006c3fb27SDimitry Andric static uint64_t computeStackId(GlobalValue::GUID Function, uint32_t LineOffset,
68106c3fb27SDimitry Andric                                uint32_t Column) {
6825f757f3fSDimitry Andric   llvm::HashBuilder<llvm::TruncatedBLAKE3<8>, llvm::endianness::little>
68306c3fb27SDimitry Andric       HashBuilder;
68406c3fb27SDimitry Andric   HashBuilder.add(Function, LineOffset, Column);
68506c3fb27SDimitry Andric   llvm::BLAKE3Result<8> Hash = HashBuilder.final();
68606c3fb27SDimitry Andric   uint64_t Id;
68706c3fb27SDimitry Andric   std::memcpy(&Id, Hash.data(), sizeof(Hash));
68806c3fb27SDimitry Andric   return Id;
68906c3fb27SDimitry Andric }
69006c3fb27SDimitry Andric 
69106c3fb27SDimitry Andric static uint64_t computeStackId(const memprof::Frame &Frame) {
69206c3fb27SDimitry Andric   return computeStackId(Frame.Function, Frame.LineOffset, Frame.Column);
69306c3fb27SDimitry Andric }
69406c3fb27SDimitry Andric 
695*0fca6ea1SDimitry Andric // Helper to generate a single hash id for a given callstack, used for emitting
696*0fca6ea1SDimitry Andric // matching statistics and useful for uniquing such statistics across modules.
697*0fca6ea1SDimitry Andric static uint64_t
698*0fca6ea1SDimitry Andric computeFullStackId(const std::vector<memprof::Frame> &CallStack) {
699*0fca6ea1SDimitry Andric   llvm::HashBuilder<llvm::TruncatedBLAKE3<8>, llvm::endianness::little>
700*0fca6ea1SDimitry Andric       HashBuilder;
701*0fca6ea1SDimitry Andric   for (auto &F : CallStack)
702*0fca6ea1SDimitry Andric     HashBuilder.add(F.Function, F.LineOffset, F.Column);
703*0fca6ea1SDimitry Andric   llvm::BLAKE3Result<8> Hash = HashBuilder.final();
704*0fca6ea1SDimitry Andric   uint64_t Id;
705*0fca6ea1SDimitry Andric   std::memcpy(&Id, Hash.data(), sizeof(Hash));
706*0fca6ea1SDimitry Andric   return Id;
707*0fca6ea1SDimitry Andric }
708*0fca6ea1SDimitry Andric 
709*0fca6ea1SDimitry Andric static AllocationType addCallStack(CallStackTrie &AllocTrie,
71006c3fb27SDimitry Andric                                    const AllocationInfo *AllocInfo) {
71106c3fb27SDimitry Andric   SmallVector<uint64_t> StackIds;
71206c3fb27SDimitry Andric   for (const auto &StackFrame : AllocInfo->CallStack)
71306c3fb27SDimitry Andric     StackIds.push_back(computeStackId(StackFrame));
71406c3fb27SDimitry Andric   auto AllocType = getAllocType(AllocInfo->Info.getTotalLifetimeAccessDensity(),
71506c3fb27SDimitry Andric                                 AllocInfo->Info.getAllocCount(),
71606c3fb27SDimitry Andric                                 AllocInfo->Info.getTotalLifetime());
717*0fca6ea1SDimitry Andric   uint64_t TotalSize = 0;
718*0fca6ea1SDimitry Andric   if (MemProfReportHintedSizes) {
719*0fca6ea1SDimitry Andric     TotalSize = AllocInfo->Info.getTotalSize();
720*0fca6ea1SDimitry Andric     assert(TotalSize);
721*0fca6ea1SDimitry Andric   }
722*0fca6ea1SDimitry Andric   AllocTrie.addCallStack(AllocType, StackIds, TotalSize);
723*0fca6ea1SDimitry Andric   return AllocType;
72406c3fb27SDimitry Andric }
72506c3fb27SDimitry Andric 
72606c3fb27SDimitry Andric // Helper to compare the InlinedCallStack computed from an instruction's debug
72706c3fb27SDimitry Andric // info to a list of Frames from profile data (either the allocation data or a
72806c3fb27SDimitry Andric // callsite). For callsites, the StartIndex to use in the Frame array may be
72906c3fb27SDimitry Andric // non-zero.
73006c3fb27SDimitry Andric static bool
73106c3fb27SDimitry Andric stackFrameIncludesInlinedCallStack(ArrayRef<Frame> ProfileCallStack,
73206c3fb27SDimitry Andric                                    ArrayRef<uint64_t> InlinedCallStack,
73306c3fb27SDimitry Andric                                    unsigned StartIndex = 0) {
73406c3fb27SDimitry Andric   auto StackFrame = ProfileCallStack.begin() + StartIndex;
73506c3fb27SDimitry Andric   auto InlCallStackIter = InlinedCallStack.begin();
73606c3fb27SDimitry Andric   for (; StackFrame != ProfileCallStack.end() &&
73706c3fb27SDimitry Andric          InlCallStackIter != InlinedCallStack.end();
73806c3fb27SDimitry Andric        ++StackFrame, ++InlCallStackIter) {
73906c3fb27SDimitry Andric     uint64_t StackId = computeStackId(*StackFrame);
74006c3fb27SDimitry Andric     if (StackId != *InlCallStackIter)
74106c3fb27SDimitry Andric       return false;
74206c3fb27SDimitry Andric   }
74306c3fb27SDimitry Andric   // Return true if we found and matched all stack ids from the call
74406c3fb27SDimitry Andric   // instruction.
74506c3fb27SDimitry Andric   return InlCallStackIter == InlinedCallStack.end();
74606c3fb27SDimitry Andric }
74706c3fb27SDimitry Andric 
748*0fca6ea1SDimitry Andric static bool isNewWithHotColdVariant(Function *Callee,
74906c3fb27SDimitry Andric                                     const TargetLibraryInfo &TLI) {
750*0fca6ea1SDimitry Andric   if (!Callee)
751*0fca6ea1SDimitry Andric     return false;
752*0fca6ea1SDimitry Andric   LibFunc Func;
753*0fca6ea1SDimitry Andric   if (!TLI.getLibFunc(*Callee, Func))
754*0fca6ea1SDimitry Andric     return false;
755*0fca6ea1SDimitry Andric   switch (Func) {
756*0fca6ea1SDimitry Andric   case LibFunc_Znwm:
757*0fca6ea1SDimitry Andric   case LibFunc_ZnwmRKSt9nothrow_t:
758*0fca6ea1SDimitry Andric   case LibFunc_ZnwmSt11align_val_t:
759*0fca6ea1SDimitry Andric   case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t:
760*0fca6ea1SDimitry Andric   case LibFunc_Znam:
761*0fca6ea1SDimitry Andric   case LibFunc_ZnamRKSt9nothrow_t:
762*0fca6ea1SDimitry Andric   case LibFunc_ZnamSt11align_val_t:
763*0fca6ea1SDimitry Andric   case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t:
764*0fca6ea1SDimitry Andric     return true;
765*0fca6ea1SDimitry Andric   case LibFunc_Znwm12__hot_cold_t:
766*0fca6ea1SDimitry Andric   case LibFunc_ZnwmRKSt9nothrow_t12__hot_cold_t:
767*0fca6ea1SDimitry Andric   case LibFunc_ZnwmSt11align_val_t12__hot_cold_t:
768*0fca6ea1SDimitry Andric   case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t12__hot_cold_t:
769*0fca6ea1SDimitry Andric   case LibFunc_Znam12__hot_cold_t:
770*0fca6ea1SDimitry Andric   case LibFunc_ZnamRKSt9nothrow_t12__hot_cold_t:
771*0fca6ea1SDimitry Andric   case LibFunc_ZnamSt11align_val_t12__hot_cold_t:
772*0fca6ea1SDimitry Andric   case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t12__hot_cold_t:
773*0fca6ea1SDimitry Andric     return ClMemProfMatchHotColdNew;
774*0fca6ea1SDimitry Andric   default:
775*0fca6ea1SDimitry Andric     return false;
776*0fca6ea1SDimitry Andric   }
777*0fca6ea1SDimitry Andric }
778*0fca6ea1SDimitry Andric 
779*0fca6ea1SDimitry Andric struct AllocMatchInfo {
780*0fca6ea1SDimitry Andric   uint64_t TotalSize = 0;
781*0fca6ea1SDimitry Andric   AllocationType AllocType = AllocationType::None;
782*0fca6ea1SDimitry Andric   bool Matched = false;
783*0fca6ea1SDimitry Andric };
784*0fca6ea1SDimitry Andric 
785*0fca6ea1SDimitry Andric static void
786*0fca6ea1SDimitry Andric readMemprof(Module &M, Function &F, IndexedInstrProfReader *MemProfReader,
787*0fca6ea1SDimitry Andric             const TargetLibraryInfo &TLI,
788*0fca6ea1SDimitry Andric             std::map<uint64_t, AllocMatchInfo> &FullStackIdToAllocMatchInfo) {
78906c3fb27SDimitry Andric   auto &Ctx = M.getContext();
7905f757f3fSDimitry Andric   // Previously we used getIRPGOFuncName() here. If F is local linkage,
7915f757f3fSDimitry Andric   // getIRPGOFuncName() returns FuncName with prefix 'FileName;'. But
7925f757f3fSDimitry Andric   // llvm-profdata uses FuncName in dwarf to create GUID which doesn't
7935f757f3fSDimitry Andric   // contain FileName's prefix. It caused local linkage function can't
7945f757f3fSDimitry Andric   // find MemProfRecord. So we use getName() now.
7955f757f3fSDimitry Andric   // 'unique-internal-linkage-names' can make MemProf work better for local
7965f757f3fSDimitry Andric   // linkage function.
7975f757f3fSDimitry Andric   auto FuncName = F.getName();
79806c3fb27SDimitry Andric   auto FuncGUID = Function::getGUID(FuncName);
7995f757f3fSDimitry Andric   std::optional<memprof::MemProfRecord> MemProfRec;
8005f757f3fSDimitry Andric   auto Err = MemProfReader->getMemProfRecord(FuncGUID).moveInto(MemProfRec);
8015f757f3fSDimitry Andric   if (Err) {
8025f757f3fSDimitry Andric     handleAllErrors(std::move(Err), [&](const InstrProfError &IPE) {
80306c3fb27SDimitry Andric       auto Err = IPE.get();
80406c3fb27SDimitry Andric       bool SkipWarning = false;
80506c3fb27SDimitry Andric       LLVM_DEBUG(dbgs() << "Error in reading profile for Func " << FuncName
80606c3fb27SDimitry Andric                         << ": ");
80706c3fb27SDimitry Andric       if (Err == instrprof_error::unknown_function) {
80806c3fb27SDimitry Andric         NumOfMemProfMissing++;
80906c3fb27SDimitry Andric         SkipWarning = !PGOWarnMissing;
81006c3fb27SDimitry Andric         LLVM_DEBUG(dbgs() << "unknown function");
81106c3fb27SDimitry Andric       } else if (Err == instrprof_error::hash_mismatch) {
812*0fca6ea1SDimitry Andric         NumOfMemProfMismatch++;
81306c3fb27SDimitry Andric         SkipWarning =
81406c3fb27SDimitry Andric             NoPGOWarnMismatch ||
81506c3fb27SDimitry Andric             (NoPGOWarnMismatchComdatWeak &&
81606c3fb27SDimitry Andric              (F.hasComdat() ||
81706c3fb27SDimitry Andric               F.getLinkage() == GlobalValue::AvailableExternallyLinkage));
81806c3fb27SDimitry Andric         LLVM_DEBUG(dbgs() << "hash mismatch (skip=" << SkipWarning << ")");
81906c3fb27SDimitry Andric       }
82006c3fb27SDimitry Andric 
82106c3fb27SDimitry Andric       if (SkipWarning)
82206c3fb27SDimitry Andric         return;
82306c3fb27SDimitry Andric 
82406c3fb27SDimitry Andric       std::string Msg = (IPE.message() + Twine(" ") + F.getName().str() +
82506c3fb27SDimitry Andric                          Twine(" Hash = ") + std::to_string(FuncGUID))
82606c3fb27SDimitry Andric                             .str();
82706c3fb27SDimitry Andric 
82806c3fb27SDimitry Andric       Ctx.diagnose(
82906c3fb27SDimitry Andric           DiagnosticInfoPGOProfile(M.getName().data(), Msg, DS_Warning));
83006c3fb27SDimitry Andric     });
83106c3fb27SDimitry Andric     return;
83206c3fb27SDimitry Andric   }
83306c3fb27SDimitry Andric 
834*0fca6ea1SDimitry Andric   NumOfMemProfFunc++;
835*0fca6ea1SDimitry Andric 
8365f757f3fSDimitry Andric   // Detect if there are non-zero column numbers in the profile. If not,
8375f757f3fSDimitry Andric   // treat all column numbers as 0 when matching (i.e. ignore any non-zero
8385f757f3fSDimitry Andric   // columns in the IR). The profiled binary might have been built with
8395f757f3fSDimitry Andric   // column numbers disabled, for example.
8405f757f3fSDimitry Andric   bool ProfileHasColumns = false;
8415f757f3fSDimitry Andric 
84206c3fb27SDimitry Andric   // Build maps of the location hash to all profile data with that leaf location
84306c3fb27SDimitry Andric   // (allocation info and the callsites).
84406c3fb27SDimitry Andric   std::map<uint64_t, std::set<const AllocationInfo *>> LocHashToAllocInfo;
84506c3fb27SDimitry Andric   // For the callsites we need to record the index of the associated frame in
84606c3fb27SDimitry Andric   // the frame array (see comments below where the map entries are added).
847*0fca6ea1SDimitry Andric   std::map<uint64_t, std::set<std::pair<const std::vector<Frame> *, unsigned>>>
84806c3fb27SDimitry Andric       LocHashToCallSites;
8495f757f3fSDimitry Andric   for (auto &AI : MemProfRec->AllocSites) {
850*0fca6ea1SDimitry Andric     NumOfMemProfAllocContextProfiles++;
85106c3fb27SDimitry Andric     // Associate the allocation info with the leaf frame. The later matching
85206c3fb27SDimitry Andric     // code will match any inlined call sequences in the IR with a longer prefix
85306c3fb27SDimitry Andric     // of call stack frames.
85406c3fb27SDimitry Andric     uint64_t StackId = computeStackId(AI.CallStack[0]);
85506c3fb27SDimitry Andric     LocHashToAllocInfo[StackId].insert(&AI);
8565f757f3fSDimitry Andric     ProfileHasColumns |= AI.CallStack[0].Column;
85706c3fb27SDimitry Andric   }
8585f757f3fSDimitry Andric   for (auto &CS : MemProfRec->CallSites) {
859*0fca6ea1SDimitry Andric     NumOfMemProfCallSiteProfiles++;
86006c3fb27SDimitry Andric     // Need to record all frames from leaf up to and including this function,
86106c3fb27SDimitry Andric     // as any of these may or may not have been inlined at this point.
86206c3fb27SDimitry Andric     unsigned Idx = 0;
86306c3fb27SDimitry Andric     for (auto &StackFrame : CS) {
86406c3fb27SDimitry Andric       uint64_t StackId = computeStackId(StackFrame);
86506c3fb27SDimitry Andric       LocHashToCallSites[StackId].insert(std::make_pair(&CS, Idx++));
8665f757f3fSDimitry Andric       ProfileHasColumns |= StackFrame.Column;
86706c3fb27SDimitry Andric       // Once we find this function, we can stop recording.
86806c3fb27SDimitry Andric       if (StackFrame.Function == FuncGUID)
86906c3fb27SDimitry Andric         break;
87006c3fb27SDimitry Andric     }
87106c3fb27SDimitry Andric     assert(Idx <= CS.size() && CS[Idx - 1].Function == FuncGUID);
87206c3fb27SDimitry Andric   }
87306c3fb27SDimitry Andric 
87406c3fb27SDimitry Andric   auto GetOffset = [](const DILocation *DIL) {
87506c3fb27SDimitry Andric     return (DIL->getLine() - DIL->getScope()->getSubprogram()->getLine()) &
87606c3fb27SDimitry Andric            0xffff;
87706c3fb27SDimitry Andric   };
87806c3fb27SDimitry Andric 
87906c3fb27SDimitry Andric   // Now walk the instructions, looking up the associated profile data using
880*0fca6ea1SDimitry Andric   // debug locations.
88106c3fb27SDimitry Andric   for (auto &BB : F) {
88206c3fb27SDimitry Andric     for (auto &I : BB) {
88306c3fb27SDimitry Andric       if (I.isDebugOrPseudoInst())
88406c3fb27SDimitry Andric         continue;
88506c3fb27SDimitry Andric       // We are only interested in calls (allocation or interior call stack
88606c3fb27SDimitry Andric       // context calls).
88706c3fb27SDimitry Andric       auto *CI = dyn_cast<CallBase>(&I);
88806c3fb27SDimitry Andric       if (!CI)
88906c3fb27SDimitry Andric         continue;
89006c3fb27SDimitry Andric       auto *CalledFunction = CI->getCalledFunction();
89106c3fb27SDimitry Andric       if (CalledFunction && CalledFunction->isIntrinsic())
89206c3fb27SDimitry Andric         continue;
89306c3fb27SDimitry Andric       // List of call stack ids computed from the location hashes on debug
89406c3fb27SDimitry Andric       // locations (leaf to inlined at root).
89506c3fb27SDimitry Andric       std::vector<uint64_t> InlinedCallStack;
89606c3fb27SDimitry Andric       // Was the leaf location found in one of the profile maps?
89706c3fb27SDimitry Andric       bool LeafFound = false;
89806c3fb27SDimitry Andric       // If leaf was found in a map, iterators pointing to its location in both
89906c3fb27SDimitry Andric       // of the maps. It might exist in neither, one, or both (the latter case
90006c3fb27SDimitry Andric       // can happen because we don't currently have discriminators to
90106c3fb27SDimitry Andric       // distinguish the case when a single line/col maps to both an allocation
90206c3fb27SDimitry Andric       // and another callsite).
90306c3fb27SDimitry Andric       std::map<uint64_t, std::set<const AllocationInfo *>>::iterator
90406c3fb27SDimitry Andric           AllocInfoIter;
905*0fca6ea1SDimitry Andric       std::map<uint64_t, std::set<std::pair<const std::vector<Frame> *,
90606c3fb27SDimitry Andric                                             unsigned>>>::iterator CallSitesIter;
90706c3fb27SDimitry Andric       for (const DILocation *DIL = I.getDebugLoc(); DIL != nullptr;
90806c3fb27SDimitry Andric            DIL = DIL->getInlinedAt()) {
90906c3fb27SDimitry Andric         // Use C++ linkage name if possible. Need to compile with
91006c3fb27SDimitry Andric         // -fdebug-info-for-profiling to get linkage name.
91106c3fb27SDimitry Andric         StringRef Name = DIL->getScope()->getSubprogram()->getLinkageName();
91206c3fb27SDimitry Andric         if (Name.empty())
91306c3fb27SDimitry Andric           Name = DIL->getScope()->getSubprogram()->getName();
91406c3fb27SDimitry Andric         auto CalleeGUID = Function::getGUID(Name);
9155f757f3fSDimitry Andric         auto StackId = computeStackId(CalleeGUID, GetOffset(DIL),
9165f757f3fSDimitry Andric                                       ProfileHasColumns ? DIL->getColumn() : 0);
9175f757f3fSDimitry Andric         // Check if we have found the profile's leaf frame. If yes, collect
9185f757f3fSDimitry Andric         // the rest of the call's inlined context starting here. If not, see if
9195f757f3fSDimitry Andric         // we find a match further up the inlined context (in case the profile
9205f757f3fSDimitry Andric         // was missing debug frames at the leaf).
92106c3fb27SDimitry Andric         if (!LeafFound) {
92206c3fb27SDimitry Andric           AllocInfoIter = LocHashToAllocInfo.find(StackId);
92306c3fb27SDimitry Andric           CallSitesIter = LocHashToCallSites.find(StackId);
9245f757f3fSDimitry Andric           if (AllocInfoIter != LocHashToAllocInfo.end() ||
9255f757f3fSDimitry Andric               CallSitesIter != LocHashToCallSites.end())
92606c3fb27SDimitry Andric             LeafFound = true;
92706c3fb27SDimitry Andric         }
9285f757f3fSDimitry Andric         if (LeafFound)
92906c3fb27SDimitry Andric           InlinedCallStack.push_back(StackId);
93006c3fb27SDimitry Andric       }
93106c3fb27SDimitry Andric       // If leaf not in either of the maps, skip inst.
93206c3fb27SDimitry Andric       if (!LeafFound)
93306c3fb27SDimitry Andric         continue;
93406c3fb27SDimitry Andric 
93506c3fb27SDimitry Andric       // First add !memprof metadata from allocation info, if we found the
93606c3fb27SDimitry Andric       // instruction's leaf location in that map, and if the rest of the
93706c3fb27SDimitry Andric       // instruction's locations match the prefix Frame locations on an
93806c3fb27SDimitry Andric       // allocation context with the same leaf.
93906c3fb27SDimitry Andric       if (AllocInfoIter != LocHashToAllocInfo.end()) {
94006c3fb27SDimitry Andric         // Only consider allocations via new, to reduce unnecessary metadata,
94106c3fb27SDimitry Andric         // since those are the only allocations that will be targeted initially.
942*0fca6ea1SDimitry Andric         if (!isNewWithHotColdVariant(CI->getCalledFunction(), TLI))
94306c3fb27SDimitry Andric           continue;
94406c3fb27SDimitry Andric         // We may match this instruction's location list to multiple MIB
94506c3fb27SDimitry Andric         // contexts. Add them to a Trie specialized for trimming the contexts to
94606c3fb27SDimitry Andric         // the minimal needed to disambiguate contexts with unique behavior.
94706c3fb27SDimitry Andric         CallStackTrie AllocTrie;
94806c3fb27SDimitry Andric         for (auto *AllocInfo : AllocInfoIter->second) {
94906c3fb27SDimitry Andric           // Check the full inlined call stack against this one.
95006c3fb27SDimitry Andric           // If we found and thus matched all frames on the call, include
95106c3fb27SDimitry Andric           // this MIB.
95206c3fb27SDimitry Andric           if (stackFrameIncludesInlinedCallStack(AllocInfo->CallStack,
953*0fca6ea1SDimitry Andric                                                  InlinedCallStack)) {
954*0fca6ea1SDimitry Andric             NumOfMemProfMatchedAllocContexts++;
955*0fca6ea1SDimitry Andric             auto AllocType = addCallStack(AllocTrie, AllocInfo);
956*0fca6ea1SDimitry Andric             // Record information about the allocation if match info printing
957*0fca6ea1SDimitry Andric             // was requested.
958*0fca6ea1SDimitry Andric             if (ClPrintMemProfMatchInfo) {
959*0fca6ea1SDimitry Andric               auto FullStackId = computeFullStackId(AllocInfo->CallStack);
960*0fca6ea1SDimitry Andric               FullStackIdToAllocMatchInfo[FullStackId] = {
961*0fca6ea1SDimitry Andric                   AllocInfo->Info.getTotalSize(), AllocType, /*Matched=*/true};
962*0fca6ea1SDimitry Andric             }
963*0fca6ea1SDimitry Andric           }
96406c3fb27SDimitry Andric         }
96506c3fb27SDimitry Andric         // We might not have matched any to the full inlined call stack.
96606c3fb27SDimitry Andric         // But if we did, create and attach metadata, or a function attribute if
96706c3fb27SDimitry Andric         // all contexts have identical profiled behavior.
96806c3fb27SDimitry Andric         if (!AllocTrie.empty()) {
969*0fca6ea1SDimitry Andric           NumOfMemProfMatchedAllocs++;
97006c3fb27SDimitry Andric           // MemprofMDAttached will be false if a function attribute was
97106c3fb27SDimitry Andric           // attached.
97206c3fb27SDimitry Andric           bool MemprofMDAttached = AllocTrie.buildAndAttachMIBMetadata(CI);
97306c3fb27SDimitry Andric           assert(MemprofMDAttached == I.hasMetadata(LLVMContext::MD_memprof));
97406c3fb27SDimitry Andric           if (MemprofMDAttached) {
97506c3fb27SDimitry Andric             // Add callsite metadata for the instruction's location list so that
97606c3fb27SDimitry Andric             // it simpler later on to identify which part of the MIB contexts
97706c3fb27SDimitry Andric             // are from this particular instruction (including during inlining,
978*0fca6ea1SDimitry Andric             // when the callsite metadata will be updated appropriately).
97906c3fb27SDimitry Andric             // FIXME: can this be changed to strip out the matching stack
98006c3fb27SDimitry Andric             // context ids from the MIB contexts and not add any callsite
98106c3fb27SDimitry Andric             // metadata here to save space?
98206c3fb27SDimitry Andric             addCallsiteMetadata(I, InlinedCallStack, Ctx);
98306c3fb27SDimitry Andric           }
98406c3fb27SDimitry Andric         }
98506c3fb27SDimitry Andric         continue;
98606c3fb27SDimitry Andric       }
98706c3fb27SDimitry Andric 
98806c3fb27SDimitry Andric       // Otherwise, add callsite metadata. If we reach here then we found the
98906c3fb27SDimitry Andric       // instruction's leaf location in the callsites map and not the allocation
99006c3fb27SDimitry Andric       // map.
99106c3fb27SDimitry Andric       assert(CallSitesIter != LocHashToCallSites.end());
99206c3fb27SDimitry Andric       for (auto CallStackIdx : CallSitesIter->second) {
99306c3fb27SDimitry Andric         // If we found and thus matched all frames on the call, create and
99406c3fb27SDimitry Andric         // attach call stack metadata.
99506c3fb27SDimitry Andric         if (stackFrameIncludesInlinedCallStack(
99606c3fb27SDimitry Andric                 *CallStackIdx.first, InlinedCallStack, CallStackIdx.second)) {
997*0fca6ea1SDimitry Andric           NumOfMemProfMatchedCallSites++;
99806c3fb27SDimitry Andric           addCallsiteMetadata(I, InlinedCallStack, Ctx);
99906c3fb27SDimitry Andric           // Only need to find one with a matching call stack and add a single
100006c3fb27SDimitry Andric           // callsite metadata.
100106c3fb27SDimitry Andric           break;
100206c3fb27SDimitry Andric         }
100306c3fb27SDimitry Andric       }
100406c3fb27SDimitry Andric     }
100506c3fb27SDimitry Andric   }
100606c3fb27SDimitry Andric }
100706c3fb27SDimitry Andric 
100806c3fb27SDimitry Andric MemProfUsePass::MemProfUsePass(std::string MemoryProfileFile,
100906c3fb27SDimitry Andric                                IntrusiveRefCntPtr<vfs::FileSystem> FS)
101006c3fb27SDimitry Andric     : MemoryProfileFileName(MemoryProfileFile), FS(FS) {
101106c3fb27SDimitry Andric   if (!FS)
101206c3fb27SDimitry Andric     this->FS = vfs::getRealFileSystem();
101306c3fb27SDimitry Andric }
101406c3fb27SDimitry Andric 
101506c3fb27SDimitry Andric PreservedAnalyses MemProfUsePass::run(Module &M, ModuleAnalysisManager &AM) {
101606c3fb27SDimitry Andric   LLVM_DEBUG(dbgs() << "Read in memory profile:");
101706c3fb27SDimitry Andric   auto &Ctx = M.getContext();
101806c3fb27SDimitry Andric   auto ReaderOrErr = IndexedInstrProfReader::create(MemoryProfileFileName, *FS);
101906c3fb27SDimitry Andric   if (Error E = ReaderOrErr.takeError()) {
102006c3fb27SDimitry Andric     handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) {
102106c3fb27SDimitry Andric       Ctx.diagnose(
102206c3fb27SDimitry Andric           DiagnosticInfoPGOProfile(MemoryProfileFileName.data(), EI.message()));
102306c3fb27SDimitry Andric     });
102406c3fb27SDimitry Andric     return PreservedAnalyses::all();
102506c3fb27SDimitry Andric   }
102606c3fb27SDimitry Andric 
102706c3fb27SDimitry Andric   std::unique_ptr<IndexedInstrProfReader> MemProfReader =
102806c3fb27SDimitry Andric       std::move(ReaderOrErr.get());
102906c3fb27SDimitry Andric   if (!MemProfReader) {
103006c3fb27SDimitry Andric     Ctx.diagnose(DiagnosticInfoPGOProfile(
103106c3fb27SDimitry Andric         MemoryProfileFileName.data(), StringRef("Cannot get MemProfReader")));
103206c3fb27SDimitry Andric     return PreservedAnalyses::all();
103306c3fb27SDimitry Andric   }
103406c3fb27SDimitry Andric 
103506c3fb27SDimitry Andric   if (!MemProfReader->hasMemoryProfile()) {
103606c3fb27SDimitry Andric     Ctx.diagnose(DiagnosticInfoPGOProfile(MemoryProfileFileName.data(),
103706c3fb27SDimitry Andric                                           "Not a memory profile"));
103806c3fb27SDimitry Andric     return PreservedAnalyses::all();
103906c3fb27SDimitry Andric   }
104006c3fb27SDimitry Andric 
104106c3fb27SDimitry Andric   auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
104206c3fb27SDimitry Andric 
1043*0fca6ea1SDimitry Andric   // Map from the stack has of each allocation context in the function profiles
1044*0fca6ea1SDimitry Andric   // to the total profiled size (bytes), allocation type, and whether we matched
1045*0fca6ea1SDimitry Andric   // it to an allocation in the IR.
1046*0fca6ea1SDimitry Andric   std::map<uint64_t, AllocMatchInfo> FullStackIdToAllocMatchInfo;
1047*0fca6ea1SDimitry Andric 
104806c3fb27SDimitry Andric   for (auto &F : M) {
104906c3fb27SDimitry Andric     if (F.isDeclaration())
105006c3fb27SDimitry Andric       continue;
105106c3fb27SDimitry Andric 
105206c3fb27SDimitry Andric     const TargetLibraryInfo &TLI = FAM.getResult<TargetLibraryAnalysis>(F);
1053*0fca6ea1SDimitry Andric     readMemprof(M, F, MemProfReader.get(), TLI, FullStackIdToAllocMatchInfo);
1054*0fca6ea1SDimitry Andric   }
1055*0fca6ea1SDimitry Andric 
1056*0fca6ea1SDimitry Andric   if (ClPrintMemProfMatchInfo) {
1057*0fca6ea1SDimitry Andric     for (const auto &[Id, Info] : FullStackIdToAllocMatchInfo)
1058*0fca6ea1SDimitry Andric       errs() << "MemProf " << getAllocTypeAttributeString(Info.AllocType)
1059*0fca6ea1SDimitry Andric              << " context with id " << Id << " has total profiled size "
1060*0fca6ea1SDimitry Andric              << Info.TotalSize << (Info.Matched ? " is" : " not")
1061*0fca6ea1SDimitry Andric              << " matched\n";
106206c3fb27SDimitry Andric   }
106306c3fb27SDimitry Andric 
106406c3fb27SDimitry Andric   return PreservedAnalyses::none();
106506c3fb27SDimitry Andric }
1066