xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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"
21e8d8bef9SDimitry Andric #include "llvm/ADT/Triple.h"
22349cc55cSDimitry Andric #include "llvm/Analysis/ValueTracking.h"
23e8d8bef9SDimitry Andric #include "llvm/IR/Constant.h"
24e8d8bef9SDimitry Andric #include "llvm/IR/DataLayout.h"
25e8d8bef9SDimitry Andric #include "llvm/IR/Function.h"
26e8d8bef9SDimitry Andric #include "llvm/IR/GlobalValue.h"
27e8d8bef9SDimitry Andric #include "llvm/IR/IRBuilder.h"
28e8d8bef9SDimitry Andric #include "llvm/IR/Instruction.h"
291fd87a68SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
30e8d8bef9SDimitry Andric #include "llvm/IR/Module.h"
31e8d8bef9SDimitry Andric #include "llvm/IR/Type.h"
32e8d8bef9SDimitry Andric #include "llvm/IR/Value.h"
33e8d8bef9SDimitry Andric #include "llvm/InitializePasses.h"
34e8d8bef9SDimitry Andric #include "llvm/Pass.h"
3581ad6265SDimitry Andric #include "llvm/ProfileData/InstrProf.h"
36e8d8bef9SDimitry Andric #include "llvm/Support/CommandLine.h"
37e8d8bef9SDimitry Andric #include "llvm/Support/Debug.h"
38e8d8bef9SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h"
39e8d8bef9SDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h"
40e8d8bef9SDimitry Andric 
41e8d8bef9SDimitry Andric using namespace llvm;
42e8d8bef9SDimitry Andric 
43e8d8bef9SDimitry Andric #define DEBUG_TYPE "memprof"
44e8d8bef9SDimitry Andric 
45e8d8bef9SDimitry Andric constexpr int LLVM_MEM_PROFILER_VERSION = 1;
46e8d8bef9SDimitry Andric 
47e8d8bef9SDimitry Andric // Size of memory mapped to a single shadow location.
48e8d8bef9SDimitry Andric constexpr uint64_t DefaultShadowGranularity = 64;
49e8d8bef9SDimitry Andric 
50e8d8bef9SDimitry Andric // Scale from granularity down to shadow size.
51e8d8bef9SDimitry Andric constexpr uint64_t DefaultShadowScale = 3;
52e8d8bef9SDimitry Andric 
53e8d8bef9SDimitry Andric constexpr char MemProfModuleCtorName[] = "memprof.module_ctor";
54e8d8bef9SDimitry Andric constexpr uint64_t MemProfCtorAndDtorPriority = 1;
55e8d8bef9SDimitry Andric // On Emscripten, the system needs more than one priorities for constructors.
56e8d8bef9SDimitry Andric constexpr uint64_t MemProfEmscriptenCtorAndDtorPriority = 50;
57e8d8bef9SDimitry Andric constexpr char MemProfInitName[] = "__memprof_init";
58e8d8bef9SDimitry Andric constexpr char MemProfVersionCheckNamePrefix[] =
59e8d8bef9SDimitry Andric     "__memprof_version_mismatch_check_v";
60e8d8bef9SDimitry Andric 
61e8d8bef9SDimitry Andric constexpr char MemProfShadowMemoryDynamicAddress[] =
62e8d8bef9SDimitry Andric     "__memprof_shadow_memory_dynamic_address";
63e8d8bef9SDimitry Andric 
64e8d8bef9SDimitry Andric constexpr char MemProfFilenameVar[] = "__memprof_profile_filename";
65e8d8bef9SDimitry Andric 
66e8d8bef9SDimitry Andric // Command-line flags.
67e8d8bef9SDimitry Andric 
68e8d8bef9SDimitry Andric static cl::opt<bool> ClInsertVersionCheck(
69e8d8bef9SDimitry Andric     "memprof-guard-against-version-mismatch",
70e8d8bef9SDimitry Andric     cl::desc("Guard against compiler/runtime version mismatch."), cl::Hidden,
71e8d8bef9SDimitry Andric     cl::init(true));
72e8d8bef9SDimitry Andric 
73e8d8bef9SDimitry Andric // This flag may need to be replaced with -f[no-]memprof-reads.
74e8d8bef9SDimitry Andric static cl::opt<bool> ClInstrumentReads("memprof-instrument-reads",
75e8d8bef9SDimitry Andric                                        cl::desc("instrument read instructions"),
76e8d8bef9SDimitry Andric                                        cl::Hidden, cl::init(true));
77e8d8bef9SDimitry Andric 
78e8d8bef9SDimitry Andric static cl::opt<bool>
79e8d8bef9SDimitry Andric     ClInstrumentWrites("memprof-instrument-writes",
80e8d8bef9SDimitry Andric                        cl::desc("instrument write instructions"), cl::Hidden,
81e8d8bef9SDimitry Andric                        cl::init(true));
82e8d8bef9SDimitry Andric 
83e8d8bef9SDimitry Andric static cl::opt<bool> ClInstrumentAtomics(
84e8d8bef9SDimitry Andric     "memprof-instrument-atomics",
85e8d8bef9SDimitry Andric     cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden,
86e8d8bef9SDimitry Andric     cl::init(true));
87e8d8bef9SDimitry Andric 
88e8d8bef9SDimitry Andric static cl::opt<bool> ClUseCalls(
89e8d8bef9SDimitry Andric     "memprof-use-callbacks",
90e8d8bef9SDimitry Andric     cl::desc("Use callbacks instead of inline instrumentation sequences."),
91e8d8bef9SDimitry Andric     cl::Hidden, cl::init(false));
92e8d8bef9SDimitry Andric 
93e8d8bef9SDimitry Andric static cl::opt<std::string>
94e8d8bef9SDimitry Andric     ClMemoryAccessCallbackPrefix("memprof-memory-access-callback-prefix",
95e8d8bef9SDimitry Andric                                  cl::desc("Prefix for memory access callbacks"),
96e8d8bef9SDimitry Andric                                  cl::Hidden, cl::init("__memprof_"));
97e8d8bef9SDimitry Andric 
98e8d8bef9SDimitry Andric // These flags allow to change the shadow mapping.
99e8d8bef9SDimitry Andric // The shadow mapping looks like
100e8d8bef9SDimitry Andric //    Shadow = ((Mem & mask) >> scale) + offset
101e8d8bef9SDimitry Andric 
102e8d8bef9SDimitry Andric static cl::opt<int> ClMappingScale("memprof-mapping-scale",
103e8d8bef9SDimitry Andric                                    cl::desc("scale of memprof shadow mapping"),
104e8d8bef9SDimitry Andric                                    cl::Hidden, cl::init(DefaultShadowScale));
105e8d8bef9SDimitry Andric 
106e8d8bef9SDimitry Andric static cl::opt<int>
107e8d8bef9SDimitry Andric     ClMappingGranularity("memprof-mapping-granularity",
108e8d8bef9SDimitry Andric                          cl::desc("granularity of memprof shadow mapping"),
109e8d8bef9SDimitry Andric                          cl::Hidden, cl::init(DefaultShadowGranularity));
110e8d8bef9SDimitry Andric 
111349cc55cSDimitry Andric static cl::opt<bool> ClStack("memprof-instrument-stack",
112349cc55cSDimitry Andric                              cl::desc("Instrument scalar stack variables"),
113349cc55cSDimitry Andric                              cl::Hidden, cl::init(false));
114349cc55cSDimitry Andric 
115e8d8bef9SDimitry Andric // Debug flags.
116e8d8bef9SDimitry Andric 
117e8d8bef9SDimitry Andric static cl::opt<int> ClDebug("memprof-debug", cl::desc("debug"), cl::Hidden,
118e8d8bef9SDimitry Andric                             cl::init(0));
119e8d8bef9SDimitry Andric 
120e8d8bef9SDimitry Andric static cl::opt<std::string> ClDebugFunc("memprof-debug-func", cl::Hidden,
121e8d8bef9SDimitry Andric                                         cl::desc("Debug func"));
122e8d8bef9SDimitry Andric 
123e8d8bef9SDimitry Andric static cl::opt<int> ClDebugMin("memprof-debug-min", cl::desc("Debug min inst"),
124e8d8bef9SDimitry Andric                                cl::Hidden, cl::init(-1));
125e8d8bef9SDimitry Andric 
126e8d8bef9SDimitry Andric static cl::opt<int> ClDebugMax("memprof-debug-max", cl::desc("Debug max inst"),
127e8d8bef9SDimitry Andric                                cl::Hidden, cl::init(-1));
128e8d8bef9SDimitry Andric 
129e8d8bef9SDimitry Andric STATISTIC(NumInstrumentedReads, "Number of instrumented reads");
130e8d8bef9SDimitry Andric STATISTIC(NumInstrumentedWrites, "Number of instrumented writes");
131349cc55cSDimitry Andric STATISTIC(NumSkippedStackReads, "Number of non-instrumented stack reads");
132349cc55cSDimitry Andric STATISTIC(NumSkippedStackWrites, "Number of non-instrumented stack writes");
133e8d8bef9SDimitry Andric 
134e8d8bef9SDimitry Andric namespace {
135e8d8bef9SDimitry Andric 
136e8d8bef9SDimitry Andric /// This struct defines the shadow mapping using the rule:
137e8d8bef9SDimitry Andric ///   shadow = ((mem & mask) >> Scale) ADD DynamicShadowOffset.
138e8d8bef9SDimitry Andric struct ShadowMapping {
139e8d8bef9SDimitry Andric   ShadowMapping() {
140e8d8bef9SDimitry Andric     Scale = ClMappingScale;
141e8d8bef9SDimitry Andric     Granularity = ClMappingGranularity;
142e8d8bef9SDimitry Andric     Mask = ~(Granularity - 1);
143e8d8bef9SDimitry Andric   }
144e8d8bef9SDimitry Andric 
145e8d8bef9SDimitry Andric   int Scale;
146e8d8bef9SDimitry Andric   int Granularity;
147e8d8bef9SDimitry Andric   uint64_t Mask; // Computed as ~(Granularity-1)
148e8d8bef9SDimitry Andric };
149e8d8bef9SDimitry Andric 
150e8d8bef9SDimitry Andric static uint64_t getCtorAndDtorPriority(Triple &TargetTriple) {
151e8d8bef9SDimitry Andric   return TargetTriple.isOSEmscripten() ? MemProfEmscriptenCtorAndDtorPriority
152e8d8bef9SDimitry Andric                                        : MemProfCtorAndDtorPriority;
153e8d8bef9SDimitry Andric }
154e8d8bef9SDimitry Andric 
155e8d8bef9SDimitry Andric struct InterestingMemoryAccess {
156e8d8bef9SDimitry Andric   Value *Addr = nullptr;
157e8d8bef9SDimitry Andric   bool IsWrite;
15804eeddc0SDimitry Andric   Type *AccessTy;
159e8d8bef9SDimitry Andric   uint64_t TypeSize;
160e8d8bef9SDimitry Andric   Value *MaybeMask = nullptr;
161e8d8bef9SDimitry Andric };
162e8d8bef9SDimitry Andric 
163e8d8bef9SDimitry Andric /// Instrument the code in module to profile memory accesses.
164e8d8bef9SDimitry Andric class MemProfiler {
165e8d8bef9SDimitry Andric public:
166e8d8bef9SDimitry Andric   MemProfiler(Module &M) {
167e8d8bef9SDimitry Andric     C = &(M.getContext());
168e8d8bef9SDimitry Andric     LongSize = M.getDataLayout().getPointerSizeInBits();
169e8d8bef9SDimitry Andric     IntptrTy = Type::getIntNTy(*C, LongSize);
170e8d8bef9SDimitry Andric   }
171e8d8bef9SDimitry Andric 
172e8d8bef9SDimitry Andric   /// If it is an interesting memory access, populate information
173e8d8bef9SDimitry Andric   /// about the access and return a InterestingMemoryAccess struct.
174*bdd1243dSDimitry Andric   /// Otherwise return std::nullopt.
175*bdd1243dSDimitry Andric   std::optional<InterestingMemoryAccess>
176e8d8bef9SDimitry Andric   isInterestingMemoryAccess(Instruction *I) const;
177e8d8bef9SDimitry Andric 
178e8d8bef9SDimitry Andric   void instrumentMop(Instruction *I, const DataLayout &DL,
179e8d8bef9SDimitry Andric                      InterestingMemoryAccess &Access);
180e8d8bef9SDimitry Andric   void instrumentAddress(Instruction *OrigIns, Instruction *InsertBefore,
181e8d8bef9SDimitry Andric                          Value *Addr, uint32_t TypeSize, bool IsWrite);
182e8d8bef9SDimitry Andric   void instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask,
18381ad6265SDimitry Andric                                    Instruction *I, Value *Addr, Type *AccessTy,
184e8d8bef9SDimitry Andric                                    bool IsWrite);
185e8d8bef9SDimitry Andric   void instrumentMemIntrinsic(MemIntrinsic *MI);
186e8d8bef9SDimitry Andric   Value *memToShadow(Value *Shadow, IRBuilder<> &IRB);
187e8d8bef9SDimitry Andric   bool instrumentFunction(Function &F);
188e8d8bef9SDimitry Andric   bool maybeInsertMemProfInitAtFunctionEntry(Function &F);
189e8d8bef9SDimitry Andric   bool insertDynamicShadowAtFunctionEntry(Function &F);
190e8d8bef9SDimitry Andric 
191e8d8bef9SDimitry Andric private:
192e8d8bef9SDimitry Andric   void initializeCallbacks(Module &M);
193e8d8bef9SDimitry Andric 
194e8d8bef9SDimitry Andric   LLVMContext *C;
195e8d8bef9SDimitry Andric   int LongSize;
196e8d8bef9SDimitry Andric   Type *IntptrTy;
197e8d8bef9SDimitry Andric   ShadowMapping Mapping;
198e8d8bef9SDimitry Andric 
199e8d8bef9SDimitry Andric   // These arrays is indexed by AccessIsWrite
200e8d8bef9SDimitry Andric   FunctionCallee MemProfMemoryAccessCallback[2];
201e8d8bef9SDimitry Andric   FunctionCallee MemProfMemoryAccessCallbackSized[2];
202e8d8bef9SDimitry Andric 
203e8d8bef9SDimitry Andric   FunctionCallee MemProfMemmove, MemProfMemcpy, MemProfMemset;
204e8d8bef9SDimitry Andric   Value *DynamicShadowOffset = nullptr;
205e8d8bef9SDimitry Andric };
206e8d8bef9SDimitry Andric 
207e8d8bef9SDimitry Andric class ModuleMemProfiler {
208e8d8bef9SDimitry Andric public:
209e8d8bef9SDimitry Andric   ModuleMemProfiler(Module &M) { TargetTriple = Triple(M.getTargetTriple()); }
210e8d8bef9SDimitry Andric 
211e8d8bef9SDimitry Andric   bool instrumentModule(Module &);
212e8d8bef9SDimitry Andric 
213e8d8bef9SDimitry Andric private:
214e8d8bef9SDimitry Andric   Triple TargetTriple;
215e8d8bef9SDimitry Andric   ShadowMapping Mapping;
216e8d8bef9SDimitry Andric   Function *MemProfCtorFunction = nullptr;
217e8d8bef9SDimitry Andric };
218e8d8bef9SDimitry Andric 
219e8d8bef9SDimitry Andric } // end anonymous namespace
220e8d8bef9SDimitry Andric 
22181ad6265SDimitry Andric MemProfilerPass::MemProfilerPass() = default;
222e8d8bef9SDimitry Andric 
223e8d8bef9SDimitry Andric PreservedAnalyses MemProfilerPass::run(Function &F,
224e8d8bef9SDimitry Andric                                        AnalysisManager<Function> &AM) {
225e8d8bef9SDimitry Andric   Module &M = *F.getParent();
226e8d8bef9SDimitry Andric   MemProfiler Profiler(M);
227e8d8bef9SDimitry Andric   if (Profiler.instrumentFunction(F))
228e8d8bef9SDimitry Andric     return PreservedAnalyses::none();
229e8d8bef9SDimitry Andric   return PreservedAnalyses::all();
230e8d8bef9SDimitry Andric }
231e8d8bef9SDimitry Andric 
23281ad6265SDimitry Andric ModuleMemProfilerPass::ModuleMemProfilerPass() = default;
233e8d8bef9SDimitry Andric 
234e8d8bef9SDimitry Andric PreservedAnalyses ModuleMemProfilerPass::run(Module &M,
235e8d8bef9SDimitry Andric                                              AnalysisManager<Module> &AM) {
236e8d8bef9SDimitry Andric   ModuleMemProfiler Profiler(M);
237e8d8bef9SDimitry Andric   if (Profiler.instrumentModule(M))
238e8d8bef9SDimitry Andric     return PreservedAnalyses::none();
239e8d8bef9SDimitry Andric   return PreservedAnalyses::all();
240e8d8bef9SDimitry Andric }
241e8d8bef9SDimitry Andric 
242e8d8bef9SDimitry Andric Value *MemProfiler::memToShadow(Value *Shadow, IRBuilder<> &IRB) {
243e8d8bef9SDimitry Andric   // (Shadow & mask) >> scale
244e8d8bef9SDimitry Andric   Shadow = IRB.CreateAnd(Shadow, Mapping.Mask);
245e8d8bef9SDimitry Andric   Shadow = IRB.CreateLShr(Shadow, Mapping.Scale);
246e8d8bef9SDimitry Andric   // (Shadow >> scale) | offset
247e8d8bef9SDimitry Andric   assert(DynamicShadowOffset);
248e8d8bef9SDimitry Andric   return IRB.CreateAdd(Shadow, DynamicShadowOffset);
249e8d8bef9SDimitry Andric }
250e8d8bef9SDimitry Andric 
251e8d8bef9SDimitry Andric // Instrument memset/memmove/memcpy
252e8d8bef9SDimitry Andric void MemProfiler::instrumentMemIntrinsic(MemIntrinsic *MI) {
253e8d8bef9SDimitry Andric   IRBuilder<> IRB(MI);
254e8d8bef9SDimitry Andric   if (isa<MemTransferInst>(MI)) {
255e8d8bef9SDimitry Andric     IRB.CreateCall(
256e8d8bef9SDimitry Andric         isa<MemMoveInst>(MI) ? MemProfMemmove : MemProfMemcpy,
257e8d8bef9SDimitry Andric         {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()),
258e8d8bef9SDimitry Andric          IRB.CreatePointerCast(MI->getOperand(1), IRB.getInt8PtrTy()),
259e8d8bef9SDimitry Andric          IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)});
260e8d8bef9SDimitry Andric   } else if (isa<MemSetInst>(MI)) {
261e8d8bef9SDimitry Andric     IRB.CreateCall(
262e8d8bef9SDimitry Andric         MemProfMemset,
263e8d8bef9SDimitry Andric         {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()),
264e8d8bef9SDimitry Andric          IRB.CreateIntCast(MI->getOperand(1), IRB.getInt32Ty(), false),
265e8d8bef9SDimitry Andric          IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)});
266e8d8bef9SDimitry Andric   }
267e8d8bef9SDimitry Andric   MI->eraseFromParent();
268e8d8bef9SDimitry Andric }
269e8d8bef9SDimitry Andric 
270*bdd1243dSDimitry Andric std::optional<InterestingMemoryAccess>
271e8d8bef9SDimitry Andric MemProfiler::isInterestingMemoryAccess(Instruction *I) const {
272e8d8bef9SDimitry Andric   // Do not instrument the load fetching the dynamic shadow address.
273e8d8bef9SDimitry Andric   if (DynamicShadowOffset == I)
274*bdd1243dSDimitry Andric     return std::nullopt;
275e8d8bef9SDimitry Andric 
276e8d8bef9SDimitry Andric   InterestingMemoryAccess Access;
277e8d8bef9SDimitry Andric 
278e8d8bef9SDimitry Andric   if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
279e8d8bef9SDimitry Andric     if (!ClInstrumentReads)
280*bdd1243dSDimitry Andric       return std::nullopt;
281e8d8bef9SDimitry Andric     Access.IsWrite = false;
28204eeddc0SDimitry Andric     Access.AccessTy = LI->getType();
283e8d8bef9SDimitry Andric     Access.Addr = LI->getPointerOperand();
284e8d8bef9SDimitry Andric   } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
285e8d8bef9SDimitry Andric     if (!ClInstrumentWrites)
286*bdd1243dSDimitry Andric       return std::nullopt;
287e8d8bef9SDimitry Andric     Access.IsWrite = true;
28804eeddc0SDimitry Andric     Access.AccessTy = SI->getValueOperand()->getType();
289e8d8bef9SDimitry Andric     Access.Addr = SI->getPointerOperand();
290e8d8bef9SDimitry Andric   } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
291e8d8bef9SDimitry Andric     if (!ClInstrumentAtomics)
292*bdd1243dSDimitry Andric       return std::nullopt;
293e8d8bef9SDimitry Andric     Access.IsWrite = true;
29404eeddc0SDimitry Andric     Access.AccessTy = RMW->getValOperand()->getType();
295e8d8bef9SDimitry Andric     Access.Addr = RMW->getPointerOperand();
296e8d8bef9SDimitry Andric   } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
297e8d8bef9SDimitry Andric     if (!ClInstrumentAtomics)
298*bdd1243dSDimitry Andric       return std::nullopt;
299e8d8bef9SDimitry Andric     Access.IsWrite = true;
30004eeddc0SDimitry Andric     Access.AccessTy = XCHG->getCompareOperand()->getType();
301e8d8bef9SDimitry Andric     Access.Addr = XCHG->getPointerOperand();
302e8d8bef9SDimitry Andric   } else if (auto *CI = dyn_cast<CallInst>(I)) {
303e8d8bef9SDimitry Andric     auto *F = CI->getCalledFunction();
304e8d8bef9SDimitry Andric     if (F && (F->getIntrinsicID() == Intrinsic::masked_load ||
305e8d8bef9SDimitry Andric               F->getIntrinsicID() == Intrinsic::masked_store)) {
306e8d8bef9SDimitry Andric       unsigned OpOffset = 0;
307e8d8bef9SDimitry Andric       if (F->getIntrinsicID() == Intrinsic::masked_store) {
308e8d8bef9SDimitry Andric         if (!ClInstrumentWrites)
309*bdd1243dSDimitry Andric           return std::nullopt;
310e8d8bef9SDimitry Andric         // Masked store has an initial operand for the value.
311e8d8bef9SDimitry Andric         OpOffset = 1;
31204eeddc0SDimitry Andric         Access.AccessTy = CI->getArgOperand(0)->getType();
313e8d8bef9SDimitry Andric         Access.IsWrite = true;
314e8d8bef9SDimitry Andric       } else {
315e8d8bef9SDimitry Andric         if (!ClInstrumentReads)
316*bdd1243dSDimitry Andric           return std::nullopt;
31704eeddc0SDimitry Andric         Access.AccessTy = CI->getType();
318e8d8bef9SDimitry Andric         Access.IsWrite = false;
319e8d8bef9SDimitry Andric       }
320e8d8bef9SDimitry Andric 
321e8d8bef9SDimitry Andric       auto *BasePtr = CI->getOperand(0 + OpOffset);
322e8d8bef9SDimitry Andric       Access.MaybeMask = CI->getOperand(2 + OpOffset);
323e8d8bef9SDimitry Andric       Access.Addr = BasePtr;
324e8d8bef9SDimitry Andric     }
325e8d8bef9SDimitry Andric   }
326e8d8bef9SDimitry Andric 
327e8d8bef9SDimitry Andric   if (!Access.Addr)
328*bdd1243dSDimitry Andric     return std::nullopt;
329e8d8bef9SDimitry Andric 
330*bdd1243dSDimitry Andric   // Do not instrument accesses from different address spaces; we cannot deal
331e8d8bef9SDimitry Andric   // with them.
332e8d8bef9SDimitry Andric   Type *PtrTy = cast<PointerType>(Access.Addr->getType()->getScalarType());
333e8d8bef9SDimitry Andric   if (PtrTy->getPointerAddressSpace() != 0)
334*bdd1243dSDimitry Andric     return std::nullopt;
335e8d8bef9SDimitry Andric 
336e8d8bef9SDimitry Andric   // Ignore swifterror addresses.
337e8d8bef9SDimitry Andric   // swifterror memory addresses are mem2reg promoted by instruction
338e8d8bef9SDimitry Andric   // selection. As such they cannot have regular uses like an instrumentation
339e8d8bef9SDimitry Andric   // function and it makes no sense to track them as memory.
340e8d8bef9SDimitry Andric   if (Access.Addr->isSwiftError())
341*bdd1243dSDimitry Andric     return std::nullopt;
342e8d8bef9SDimitry Andric 
34381ad6265SDimitry Andric   // Peel off GEPs and BitCasts.
34481ad6265SDimitry Andric   auto *Addr = Access.Addr->stripInBoundsOffsets();
34581ad6265SDimitry Andric 
34681ad6265SDimitry Andric   if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Addr)) {
34781ad6265SDimitry Andric     // Do not instrument PGO counter updates.
34881ad6265SDimitry Andric     if (GV->hasSection()) {
34981ad6265SDimitry Andric       StringRef SectionName = GV->getSection();
35081ad6265SDimitry Andric       // Check if the global is in the PGO counters section.
35181ad6265SDimitry Andric       auto OF = Triple(I->getModule()->getTargetTriple()).getObjectFormat();
35281ad6265SDimitry Andric       if (SectionName.endswith(
35381ad6265SDimitry Andric               getInstrProfSectionName(IPSK_cnts, OF, /*AddSegmentInfo=*/false)))
354*bdd1243dSDimitry Andric         return std::nullopt;
35581ad6265SDimitry Andric     }
35681ad6265SDimitry Andric 
35781ad6265SDimitry Andric     // Do not instrument accesses to LLVM internal variables.
35881ad6265SDimitry Andric     if (GV->getName().startswith("__llvm"))
359*bdd1243dSDimitry Andric       return std::nullopt;
36081ad6265SDimitry Andric   }
36181ad6265SDimitry Andric 
36204eeddc0SDimitry Andric   const DataLayout &DL = I->getModule()->getDataLayout();
36304eeddc0SDimitry Andric   Access.TypeSize = DL.getTypeStoreSizeInBits(Access.AccessTy);
364e8d8bef9SDimitry Andric   return Access;
365e8d8bef9SDimitry Andric }
366e8d8bef9SDimitry Andric 
367e8d8bef9SDimitry Andric void MemProfiler::instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask,
368e8d8bef9SDimitry Andric                                               Instruction *I, Value *Addr,
36904eeddc0SDimitry Andric                                               Type *AccessTy, bool IsWrite) {
37004eeddc0SDimitry Andric   auto *VTy = cast<FixedVectorType>(AccessTy);
371e8d8bef9SDimitry Andric   uint64_t ElemTypeSize = DL.getTypeStoreSizeInBits(VTy->getScalarType());
372e8d8bef9SDimitry Andric   unsigned Num = VTy->getNumElements();
373e8d8bef9SDimitry Andric   auto *Zero = ConstantInt::get(IntptrTy, 0);
374e8d8bef9SDimitry Andric   for (unsigned Idx = 0; Idx < Num; ++Idx) {
375e8d8bef9SDimitry Andric     Value *InstrumentedAddress = nullptr;
376e8d8bef9SDimitry Andric     Instruction *InsertBefore = I;
377e8d8bef9SDimitry Andric     if (auto *Vector = dyn_cast<ConstantVector>(Mask)) {
378e8d8bef9SDimitry Andric       // dyn_cast as we might get UndefValue
379e8d8bef9SDimitry Andric       if (auto *Masked = dyn_cast<ConstantInt>(Vector->getOperand(Idx))) {
380e8d8bef9SDimitry Andric         if (Masked->isZero())
381e8d8bef9SDimitry Andric           // Mask is constant false, so no instrumentation needed.
382e8d8bef9SDimitry Andric           continue;
383e8d8bef9SDimitry Andric         // If we have a true or undef value, fall through to instrumentAddress.
384e8d8bef9SDimitry Andric         // with InsertBefore == I
385e8d8bef9SDimitry Andric       }
386e8d8bef9SDimitry Andric     } else {
387e8d8bef9SDimitry Andric       IRBuilder<> IRB(I);
388e8d8bef9SDimitry Andric       Value *MaskElem = IRB.CreateExtractElement(Mask, Idx);
389e8d8bef9SDimitry Andric       Instruction *ThenTerm = SplitBlockAndInsertIfThen(MaskElem, I, false);
390e8d8bef9SDimitry Andric       InsertBefore = ThenTerm;
391e8d8bef9SDimitry Andric     }
392e8d8bef9SDimitry Andric 
393e8d8bef9SDimitry Andric     IRBuilder<> IRB(InsertBefore);
394e8d8bef9SDimitry Andric     InstrumentedAddress =
395e8d8bef9SDimitry Andric         IRB.CreateGEP(VTy, Addr, {Zero, ConstantInt::get(IntptrTy, Idx)});
396e8d8bef9SDimitry Andric     instrumentAddress(I, InsertBefore, InstrumentedAddress, ElemTypeSize,
397e8d8bef9SDimitry Andric                       IsWrite);
398e8d8bef9SDimitry Andric   }
399e8d8bef9SDimitry Andric }
400e8d8bef9SDimitry Andric 
401e8d8bef9SDimitry Andric void MemProfiler::instrumentMop(Instruction *I, const DataLayout &DL,
402e8d8bef9SDimitry Andric                                 InterestingMemoryAccess &Access) {
403349cc55cSDimitry Andric   // Skip instrumentation of stack accesses unless requested.
404349cc55cSDimitry Andric   if (!ClStack && isa<AllocaInst>(getUnderlyingObject(Access.Addr))) {
405349cc55cSDimitry Andric     if (Access.IsWrite)
406349cc55cSDimitry Andric       ++NumSkippedStackWrites;
407349cc55cSDimitry Andric     else
408349cc55cSDimitry Andric       ++NumSkippedStackReads;
409349cc55cSDimitry Andric     return;
410349cc55cSDimitry Andric   }
411349cc55cSDimitry Andric 
412e8d8bef9SDimitry Andric   if (Access.IsWrite)
413e8d8bef9SDimitry Andric     NumInstrumentedWrites++;
414e8d8bef9SDimitry Andric   else
415e8d8bef9SDimitry Andric     NumInstrumentedReads++;
416e8d8bef9SDimitry Andric 
417e8d8bef9SDimitry Andric   if (Access.MaybeMask) {
418e8d8bef9SDimitry Andric     instrumentMaskedLoadOrStore(DL, Access.MaybeMask, I, Access.Addr,
41981ad6265SDimitry Andric                                 Access.AccessTy, Access.IsWrite);
420e8d8bef9SDimitry Andric   } else {
421e8d8bef9SDimitry Andric     // Since the access counts will be accumulated across the entire allocation,
422e8d8bef9SDimitry Andric     // we only update the shadow access count for the first location and thus
423e8d8bef9SDimitry Andric     // don't need to worry about alignment and type size.
424e8d8bef9SDimitry Andric     instrumentAddress(I, I, Access.Addr, Access.TypeSize, Access.IsWrite);
425e8d8bef9SDimitry Andric   }
426e8d8bef9SDimitry Andric }
427e8d8bef9SDimitry Andric 
428e8d8bef9SDimitry Andric void MemProfiler::instrumentAddress(Instruction *OrigIns,
429e8d8bef9SDimitry Andric                                     Instruction *InsertBefore, Value *Addr,
430e8d8bef9SDimitry Andric                                     uint32_t TypeSize, bool IsWrite) {
431e8d8bef9SDimitry Andric   IRBuilder<> IRB(InsertBefore);
432e8d8bef9SDimitry Andric   Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);
433e8d8bef9SDimitry Andric 
434e8d8bef9SDimitry Andric   if (ClUseCalls) {
435e8d8bef9SDimitry Andric     IRB.CreateCall(MemProfMemoryAccessCallback[IsWrite], AddrLong);
436e8d8bef9SDimitry Andric     return;
437e8d8bef9SDimitry Andric   }
438e8d8bef9SDimitry Andric 
439e8d8bef9SDimitry Andric   // Create an inline sequence to compute shadow location, and increment the
440e8d8bef9SDimitry Andric   // value by one.
441e8d8bef9SDimitry Andric   Type *ShadowTy = Type::getInt64Ty(*C);
442e8d8bef9SDimitry Andric   Type *ShadowPtrTy = PointerType::get(ShadowTy, 0);
443e8d8bef9SDimitry Andric   Value *ShadowPtr = memToShadow(AddrLong, IRB);
444e8d8bef9SDimitry Andric   Value *ShadowAddr = IRB.CreateIntToPtr(ShadowPtr, ShadowPtrTy);
445e8d8bef9SDimitry Andric   Value *ShadowValue = IRB.CreateLoad(ShadowTy, ShadowAddr);
446e8d8bef9SDimitry Andric   Value *Inc = ConstantInt::get(Type::getInt64Ty(*C), 1);
447e8d8bef9SDimitry Andric   ShadowValue = IRB.CreateAdd(ShadowValue, Inc);
448e8d8bef9SDimitry Andric   IRB.CreateStore(ShadowValue, ShadowAddr);
449e8d8bef9SDimitry Andric }
450e8d8bef9SDimitry Andric 
451e8d8bef9SDimitry Andric // Create the variable for the profile file name.
452e8d8bef9SDimitry Andric void createProfileFileNameVar(Module &M) {
453e8d8bef9SDimitry Andric   const MDString *MemProfFilename =
454e8d8bef9SDimitry Andric       dyn_cast_or_null<MDString>(M.getModuleFlag("MemProfProfileFilename"));
455e8d8bef9SDimitry Andric   if (!MemProfFilename)
456e8d8bef9SDimitry Andric     return;
457e8d8bef9SDimitry Andric   assert(!MemProfFilename->getString().empty() &&
458e8d8bef9SDimitry Andric          "Unexpected MemProfProfileFilename metadata with empty string");
459e8d8bef9SDimitry Andric   Constant *ProfileNameConst = ConstantDataArray::getString(
460e8d8bef9SDimitry Andric       M.getContext(), MemProfFilename->getString(), true);
461e8d8bef9SDimitry Andric   GlobalVariable *ProfileNameVar = new GlobalVariable(
462e8d8bef9SDimitry Andric       M, ProfileNameConst->getType(), /*isConstant=*/true,
463e8d8bef9SDimitry Andric       GlobalValue::WeakAnyLinkage, ProfileNameConst, MemProfFilenameVar);
464e8d8bef9SDimitry Andric   Triple TT(M.getTargetTriple());
465e8d8bef9SDimitry Andric   if (TT.supportsCOMDAT()) {
466e8d8bef9SDimitry Andric     ProfileNameVar->setLinkage(GlobalValue::ExternalLinkage);
467e8d8bef9SDimitry Andric     ProfileNameVar->setComdat(M.getOrInsertComdat(MemProfFilenameVar));
468e8d8bef9SDimitry Andric   }
469e8d8bef9SDimitry Andric }
470e8d8bef9SDimitry Andric 
471e8d8bef9SDimitry Andric bool ModuleMemProfiler::instrumentModule(Module &M) {
472e8d8bef9SDimitry Andric   // Create a module constructor.
473e8d8bef9SDimitry Andric   std::string MemProfVersion = std::to_string(LLVM_MEM_PROFILER_VERSION);
474e8d8bef9SDimitry Andric   std::string VersionCheckName =
475e8d8bef9SDimitry Andric       ClInsertVersionCheck ? (MemProfVersionCheckNamePrefix + MemProfVersion)
476e8d8bef9SDimitry Andric                            : "";
477e8d8bef9SDimitry Andric   std::tie(MemProfCtorFunction, std::ignore) =
478e8d8bef9SDimitry Andric       createSanitizerCtorAndInitFunctions(M, MemProfModuleCtorName,
479e8d8bef9SDimitry Andric                                           MemProfInitName, /*InitArgTypes=*/{},
480e8d8bef9SDimitry Andric                                           /*InitArgs=*/{}, VersionCheckName);
481e8d8bef9SDimitry Andric 
482e8d8bef9SDimitry Andric   const uint64_t Priority = getCtorAndDtorPriority(TargetTriple);
483e8d8bef9SDimitry Andric   appendToGlobalCtors(M, MemProfCtorFunction, Priority);
484e8d8bef9SDimitry Andric 
485e8d8bef9SDimitry Andric   createProfileFileNameVar(M);
486e8d8bef9SDimitry Andric 
487e8d8bef9SDimitry Andric   return true;
488e8d8bef9SDimitry Andric }
489e8d8bef9SDimitry Andric 
490e8d8bef9SDimitry Andric void MemProfiler::initializeCallbacks(Module &M) {
491e8d8bef9SDimitry Andric   IRBuilder<> IRB(*C);
492e8d8bef9SDimitry Andric 
493e8d8bef9SDimitry Andric   for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {
494e8d8bef9SDimitry Andric     const std::string TypeStr = AccessIsWrite ? "store" : "load";
495e8d8bef9SDimitry Andric 
496e8d8bef9SDimitry Andric     SmallVector<Type *, 3> Args2 = {IntptrTy, IntptrTy};
497e8d8bef9SDimitry Andric     SmallVector<Type *, 2> Args1{1, IntptrTy};
498e8d8bef9SDimitry Andric     MemProfMemoryAccessCallbackSized[AccessIsWrite] =
499e8d8bef9SDimitry Andric         M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + TypeStr + "N",
500e8d8bef9SDimitry Andric                               FunctionType::get(IRB.getVoidTy(), Args2, false));
501e8d8bef9SDimitry Andric 
502e8d8bef9SDimitry Andric     MemProfMemoryAccessCallback[AccessIsWrite] =
503e8d8bef9SDimitry Andric         M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + TypeStr,
504e8d8bef9SDimitry Andric                               FunctionType::get(IRB.getVoidTy(), Args1, false));
505e8d8bef9SDimitry Andric   }
506e8d8bef9SDimitry Andric   MemProfMemmove = M.getOrInsertFunction(
507e8d8bef9SDimitry Andric       ClMemoryAccessCallbackPrefix + "memmove", IRB.getInt8PtrTy(),
508e8d8bef9SDimitry Andric       IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy);
509e8d8bef9SDimitry Andric   MemProfMemcpy = M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + "memcpy",
510e8d8bef9SDimitry Andric                                         IRB.getInt8PtrTy(), IRB.getInt8PtrTy(),
511e8d8bef9SDimitry Andric                                         IRB.getInt8PtrTy(), IntptrTy);
512e8d8bef9SDimitry Andric   MemProfMemset = M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + "memset",
513e8d8bef9SDimitry Andric                                         IRB.getInt8PtrTy(), IRB.getInt8PtrTy(),
514e8d8bef9SDimitry Andric                                         IRB.getInt32Ty(), IntptrTy);
515e8d8bef9SDimitry Andric }
516e8d8bef9SDimitry Andric 
517e8d8bef9SDimitry Andric bool MemProfiler::maybeInsertMemProfInitAtFunctionEntry(Function &F) {
518e8d8bef9SDimitry Andric   // For each NSObject descendant having a +load method, this method is invoked
519e8d8bef9SDimitry Andric   // by the ObjC runtime before any of the static constructors is called.
520e8d8bef9SDimitry Andric   // Therefore we need to instrument such methods with a call to __memprof_init
521e8d8bef9SDimitry Andric   // at the beginning in order to initialize our runtime before any access to
522e8d8bef9SDimitry Andric   // the shadow memory.
523e8d8bef9SDimitry Andric   // We cannot just ignore these methods, because they may call other
524e8d8bef9SDimitry Andric   // instrumented functions.
525e8d8bef9SDimitry Andric   if (F.getName().find(" load]") != std::string::npos) {
526e8d8bef9SDimitry Andric     FunctionCallee MemProfInitFunction =
527e8d8bef9SDimitry Andric         declareSanitizerInitFunction(*F.getParent(), MemProfInitName, {});
528e8d8bef9SDimitry Andric     IRBuilder<> IRB(&F.front(), F.front().begin());
529e8d8bef9SDimitry Andric     IRB.CreateCall(MemProfInitFunction, {});
530e8d8bef9SDimitry Andric     return true;
531e8d8bef9SDimitry Andric   }
532e8d8bef9SDimitry Andric   return false;
533e8d8bef9SDimitry Andric }
534e8d8bef9SDimitry Andric 
535e8d8bef9SDimitry Andric bool MemProfiler::insertDynamicShadowAtFunctionEntry(Function &F) {
536e8d8bef9SDimitry Andric   IRBuilder<> IRB(&F.front().front());
537e8d8bef9SDimitry Andric   Value *GlobalDynamicAddress = F.getParent()->getOrInsertGlobal(
538e8d8bef9SDimitry Andric       MemProfShadowMemoryDynamicAddress, IntptrTy);
539e8d8bef9SDimitry Andric   if (F.getParent()->getPICLevel() == PICLevel::NotPIC)
540e8d8bef9SDimitry Andric     cast<GlobalVariable>(GlobalDynamicAddress)->setDSOLocal(true);
541e8d8bef9SDimitry Andric   DynamicShadowOffset = IRB.CreateLoad(IntptrTy, GlobalDynamicAddress);
542e8d8bef9SDimitry Andric   return true;
543e8d8bef9SDimitry Andric }
544e8d8bef9SDimitry Andric 
545e8d8bef9SDimitry Andric bool MemProfiler::instrumentFunction(Function &F) {
546e8d8bef9SDimitry Andric   if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage)
547e8d8bef9SDimitry Andric     return false;
548e8d8bef9SDimitry Andric   if (ClDebugFunc == F.getName())
549e8d8bef9SDimitry Andric     return false;
550e8d8bef9SDimitry Andric   if (F.getName().startswith("__memprof_"))
551e8d8bef9SDimitry Andric     return false;
552e8d8bef9SDimitry Andric 
553e8d8bef9SDimitry Andric   bool FunctionModified = false;
554e8d8bef9SDimitry Andric 
555e8d8bef9SDimitry Andric   // If needed, insert __memprof_init.
556e8d8bef9SDimitry Andric   // This function needs to be called even if the function body is not
557e8d8bef9SDimitry Andric   // instrumented.
558e8d8bef9SDimitry Andric   if (maybeInsertMemProfInitAtFunctionEntry(F))
559e8d8bef9SDimitry Andric     FunctionModified = true;
560e8d8bef9SDimitry Andric 
561e8d8bef9SDimitry Andric   LLVM_DEBUG(dbgs() << "MEMPROF instrumenting:\n" << F << "\n");
562e8d8bef9SDimitry Andric 
563e8d8bef9SDimitry Andric   initializeCallbacks(*F.getParent());
564e8d8bef9SDimitry Andric 
565e8d8bef9SDimitry Andric   SmallVector<Instruction *, 16> ToInstrument;
566e8d8bef9SDimitry Andric 
567e8d8bef9SDimitry Andric   // Fill the set of memory operations to instrument.
568e8d8bef9SDimitry Andric   for (auto &BB : F) {
569e8d8bef9SDimitry Andric     for (auto &Inst : BB) {
570e8d8bef9SDimitry Andric       if (isInterestingMemoryAccess(&Inst) || isa<MemIntrinsic>(Inst))
571e8d8bef9SDimitry Andric         ToInstrument.push_back(&Inst);
572e8d8bef9SDimitry Andric     }
573e8d8bef9SDimitry Andric   }
574e8d8bef9SDimitry Andric 
57581ad6265SDimitry Andric   if (ToInstrument.empty()) {
57681ad6265SDimitry Andric     LLVM_DEBUG(dbgs() << "MEMPROF done instrumenting: " << FunctionModified
57781ad6265SDimitry Andric                       << " " << F << "\n");
57881ad6265SDimitry Andric 
57981ad6265SDimitry Andric     return FunctionModified;
58081ad6265SDimitry Andric   }
58181ad6265SDimitry Andric 
58281ad6265SDimitry Andric   FunctionModified |= insertDynamicShadowAtFunctionEntry(F);
58381ad6265SDimitry Andric 
584e8d8bef9SDimitry Andric   int NumInstrumented = 0;
585e8d8bef9SDimitry Andric   for (auto *Inst : ToInstrument) {
586e8d8bef9SDimitry Andric     if (ClDebugMin < 0 || ClDebugMax < 0 ||
587e8d8bef9SDimitry Andric         (NumInstrumented >= ClDebugMin && NumInstrumented <= ClDebugMax)) {
588*bdd1243dSDimitry Andric       std::optional<InterestingMemoryAccess> Access =
589e8d8bef9SDimitry Andric           isInterestingMemoryAccess(Inst);
590e8d8bef9SDimitry Andric       if (Access)
591e8d8bef9SDimitry Andric         instrumentMop(Inst, F.getParent()->getDataLayout(), *Access);
592e8d8bef9SDimitry Andric       else
593e8d8bef9SDimitry Andric         instrumentMemIntrinsic(cast<MemIntrinsic>(Inst));
594e8d8bef9SDimitry Andric     }
595e8d8bef9SDimitry Andric     NumInstrumented++;
596e8d8bef9SDimitry Andric   }
597e8d8bef9SDimitry Andric 
598e8d8bef9SDimitry Andric   if (NumInstrumented > 0)
599e8d8bef9SDimitry Andric     FunctionModified = true;
600e8d8bef9SDimitry Andric 
601e8d8bef9SDimitry Andric   LLVM_DEBUG(dbgs() << "MEMPROF done instrumenting: " << FunctionModified << " "
602e8d8bef9SDimitry Andric                     << F << "\n");
603e8d8bef9SDimitry Andric 
604e8d8bef9SDimitry Andric   return FunctionModified;
605e8d8bef9SDimitry Andric }
606