diff options
author | shadchin <shadchin@yandex-team.ru> | 2022-02-10 16:44:30 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:30 +0300 |
commit | 2598ef1d0aee359b4b6d5fdd1758916d5907d04f (patch) | |
tree | 012bb94d777798f1f56ac1cec429509766d05181 /contrib/libs/llvm12/lib/Transforms/Instrumentation/MemProfiler.cpp | |
parent | 6751af0b0c1b952fede40b19b71da8025b5d8bcf (diff) | |
download | ydb-2598ef1d0aee359b4b6d5fdd1758916d5907d04f.tar.gz |
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/libs/llvm12/lib/Transforms/Instrumentation/MemProfiler.cpp')
-rw-r--r-- | contrib/libs/llvm12/lib/Transforms/Instrumentation/MemProfiler.cpp | 1276 |
1 files changed, 638 insertions, 638 deletions
diff --git a/contrib/libs/llvm12/lib/Transforms/Instrumentation/MemProfiler.cpp b/contrib/libs/llvm12/lib/Transforms/Instrumentation/MemProfiler.cpp index 0e6a404a9e..fa2edf52a2 100644 --- a/contrib/libs/llvm12/lib/Transforms/Instrumentation/MemProfiler.cpp +++ b/contrib/libs/llvm12/lib/Transforms/Instrumentation/MemProfiler.cpp @@ -1,638 +1,638 @@ -//===- MemProfiler.cpp - memory allocation and access profiler ------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file is a part of MemProfiler. Memory accesses are instrumented -// to increment the access count held in a shadow memory location, or -// alternatively to call into the runtime. Memory intrinsic calls (memmove, -// memcpy, memset) are changed to call the memory profiling runtime version -// instead. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Transforms/Instrumentation/MemProfiler.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Triple.h" -#include "llvm/IR/Constant.h" -#include "llvm/IR/DataLayout.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/GlobalValue.h" -#include "llvm/IR/IRBuilder.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Type.h" -#include "llvm/IR/Value.h" -#include "llvm/InitializePasses.h" -#include "llvm/Pass.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Debug.h" -#include "llvm/Transforms/Instrumentation.h" -#include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "llvm/Transforms/Utils/ModuleUtils.h" - -using namespace llvm; - -#define DEBUG_TYPE "memprof" - -constexpr int LLVM_MEM_PROFILER_VERSION = 1; - -// Size of memory mapped to a single shadow location. -constexpr uint64_t DefaultShadowGranularity = 64; - -// Scale from granularity down to shadow size. -constexpr uint64_t DefaultShadowScale = 3; - -constexpr char MemProfModuleCtorName[] = "memprof.module_ctor"; -constexpr uint64_t MemProfCtorAndDtorPriority = 1; -// On Emscripten, the system needs more than one priorities for constructors. -constexpr uint64_t MemProfEmscriptenCtorAndDtorPriority = 50; -constexpr char MemProfInitName[] = "__memprof_init"; -constexpr char MemProfVersionCheckNamePrefix[] = - "__memprof_version_mismatch_check_v"; - -constexpr char MemProfShadowMemoryDynamicAddress[] = - "__memprof_shadow_memory_dynamic_address"; - -constexpr char MemProfFilenameVar[] = "__memprof_profile_filename"; - -// Command-line flags. - -static cl::opt<bool> ClInsertVersionCheck( - "memprof-guard-against-version-mismatch", - cl::desc("Guard against compiler/runtime version mismatch."), cl::Hidden, - cl::init(true)); - -// This flag may need to be replaced with -f[no-]memprof-reads. -static cl::opt<bool> ClInstrumentReads("memprof-instrument-reads", - cl::desc("instrument read instructions"), - cl::Hidden, cl::init(true)); - -static cl::opt<bool> - ClInstrumentWrites("memprof-instrument-writes", - cl::desc("instrument write instructions"), cl::Hidden, - cl::init(true)); - -static cl::opt<bool> ClInstrumentAtomics( - "memprof-instrument-atomics", - cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden, - cl::init(true)); - -static cl::opt<bool> ClUseCalls( - "memprof-use-callbacks", - cl::desc("Use callbacks instead of inline instrumentation sequences."), - cl::Hidden, cl::init(false)); - -static cl::opt<std::string> - ClMemoryAccessCallbackPrefix("memprof-memory-access-callback-prefix", - cl::desc("Prefix for memory access callbacks"), - cl::Hidden, cl::init("__memprof_")); - -// These flags allow to change the shadow mapping. -// The shadow mapping looks like -// Shadow = ((Mem & mask) >> scale) + offset - -static cl::opt<int> ClMappingScale("memprof-mapping-scale", - cl::desc("scale of memprof shadow mapping"), - cl::Hidden, cl::init(DefaultShadowScale)); - -static cl::opt<int> - ClMappingGranularity("memprof-mapping-granularity", - cl::desc("granularity of memprof shadow mapping"), - cl::Hidden, cl::init(DefaultShadowGranularity)); - -// Debug flags. - -static cl::opt<int> ClDebug("memprof-debug", cl::desc("debug"), cl::Hidden, - cl::init(0)); - -static cl::opt<std::string> ClDebugFunc("memprof-debug-func", cl::Hidden, - cl::desc("Debug func")); - -static cl::opt<int> ClDebugMin("memprof-debug-min", cl::desc("Debug min inst"), - cl::Hidden, cl::init(-1)); - -static cl::opt<int> ClDebugMax("memprof-debug-max", cl::desc("Debug max inst"), - cl::Hidden, cl::init(-1)); - -STATISTIC(NumInstrumentedReads, "Number of instrumented reads"); -STATISTIC(NumInstrumentedWrites, "Number of instrumented writes"); - -namespace { - -/// This struct defines the shadow mapping using the rule: -/// shadow = ((mem & mask) >> Scale) ADD DynamicShadowOffset. -struct ShadowMapping { - ShadowMapping() { - Scale = ClMappingScale; - Granularity = ClMappingGranularity; - Mask = ~(Granularity - 1); - } - - int Scale; - int Granularity; - uint64_t Mask; // Computed as ~(Granularity-1) -}; - -static uint64_t getCtorAndDtorPriority(Triple &TargetTriple) { - return TargetTriple.isOSEmscripten() ? MemProfEmscriptenCtorAndDtorPriority - : MemProfCtorAndDtorPriority; -} - -struct InterestingMemoryAccess { - Value *Addr = nullptr; - bool IsWrite; - unsigned Alignment; - uint64_t TypeSize; - Value *MaybeMask = nullptr; -}; - -/// Instrument the code in module to profile memory accesses. -class MemProfiler { -public: - MemProfiler(Module &M) { - C = &(M.getContext()); - LongSize = M.getDataLayout().getPointerSizeInBits(); - IntptrTy = Type::getIntNTy(*C, LongSize); - } - - /// If it is an interesting memory access, populate information - /// about the access and return a InterestingMemoryAccess struct. - /// Otherwise return None. - Optional<InterestingMemoryAccess> - isInterestingMemoryAccess(Instruction *I) const; - - void instrumentMop(Instruction *I, const DataLayout &DL, - InterestingMemoryAccess &Access); - void instrumentAddress(Instruction *OrigIns, Instruction *InsertBefore, - Value *Addr, uint32_t TypeSize, bool IsWrite); - void instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask, - Instruction *I, Value *Addr, - unsigned Alignment, uint32_t TypeSize, - bool IsWrite); - void instrumentMemIntrinsic(MemIntrinsic *MI); - Value *memToShadow(Value *Shadow, IRBuilder<> &IRB); - bool instrumentFunction(Function &F); - bool maybeInsertMemProfInitAtFunctionEntry(Function &F); - bool insertDynamicShadowAtFunctionEntry(Function &F); - -private: - void initializeCallbacks(Module &M); - - LLVMContext *C; - int LongSize; - Type *IntptrTy; - ShadowMapping Mapping; - - // These arrays is indexed by AccessIsWrite - FunctionCallee MemProfMemoryAccessCallback[2]; - FunctionCallee MemProfMemoryAccessCallbackSized[2]; - - FunctionCallee MemProfMemmove, MemProfMemcpy, MemProfMemset; - Value *DynamicShadowOffset = nullptr; -}; - -class MemProfilerLegacyPass : public FunctionPass { -public: - static char ID; - - explicit MemProfilerLegacyPass() : FunctionPass(ID) { - initializeMemProfilerLegacyPassPass(*PassRegistry::getPassRegistry()); - } - - StringRef getPassName() const override { return "MemProfilerFunctionPass"; } - - bool runOnFunction(Function &F) override { - MemProfiler Profiler(*F.getParent()); - return Profiler.instrumentFunction(F); - } -}; - -class ModuleMemProfiler { -public: - ModuleMemProfiler(Module &M) { TargetTriple = Triple(M.getTargetTriple()); } - - bool instrumentModule(Module &); - -private: - Triple TargetTriple; - ShadowMapping Mapping; - Function *MemProfCtorFunction = nullptr; -}; - -class ModuleMemProfilerLegacyPass : public ModulePass { -public: - static char ID; - - explicit ModuleMemProfilerLegacyPass() : ModulePass(ID) { - initializeModuleMemProfilerLegacyPassPass(*PassRegistry::getPassRegistry()); - } - - StringRef getPassName() const override { return "ModuleMemProfiler"; } - - void getAnalysisUsage(AnalysisUsage &AU) const override {} - - bool runOnModule(Module &M) override { - ModuleMemProfiler MemProfiler(M); - return MemProfiler.instrumentModule(M); - } -}; - -} // end anonymous namespace - -MemProfilerPass::MemProfilerPass() {} - -PreservedAnalyses MemProfilerPass::run(Function &F, - AnalysisManager<Function> &AM) { - Module &M = *F.getParent(); - MemProfiler Profiler(M); - if (Profiler.instrumentFunction(F)) - return PreservedAnalyses::none(); - return PreservedAnalyses::all(); - - return PreservedAnalyses::all(); -} - -ModuleMemProfilerPass::ModuleMemProfilerPass() {} - -PreservedAnalyses ModuleMemProfilerPass::run(Module &M, - AnalysisManager<Module> &AM) { - ModuleMemProfiler Profiler(M); - if (Profiler.instrumentModule(M)) - return PreservedAnalyses::none(); - return PreservedAnalyses::all(); -} - -char MemProfilerLegacyPass::ID = 0; - -INITIALIZE_PASS_BEGIN(MemProfilerLegacyPass, "memprof", - "MemProfiler: profile memory allocations and accesses.", - false, false) -INITIALIZE_PASS_END(MemProfilerLegacyPass, "memprof", - "MemProfiler: profile memory allocations and accesses.", - false, false) - -FunctionPass *llvm::createMemProfilerFunctionPass() { - return new MemProfilerLegacyPass(); -} - -char ModuleMemProfilerLegacyPass::ID = 0; - -INITIALIZE_PASS(ModuleMemProfilerLegacyPass, "memprof-module", - "MemProfiler: profile memory allocations and accesses." - "ModulePass", - false, false) - -ModulePass *llvm::createModuleMemProfilerLegacyPassPass() { - return new ModuleMemProfilerLegacyPass(); -} - -Value *MemProfiler::memToShadow(Value *Shadow, IRBuilder<> &IRB) { - // (Shadow & mask) >> scale - Shadow = IRB.CreateAnd(Shadow, Mapping.Mask); - Shadow = IRB.CreateLShr(Shadow, Mapping.Scale); - // (Shadow >> scale) | offset - assert(DynamicShadowOffset); - return IRB.CreateAdd(Shadow, DynamicShadowOffset); -} - -// Instrument memset/memmove/memcpy -void MemProfiler::instrumentMemIntrinsic(MemIntrinsic *MI) { - IRBuilder<> IRB(MI); - if (isa<MemTransferInst>(MI)) { - IRB.CreateCall( - isa<MemMoveInst>(MI) ? MemProfMemmove : MemProfMemcpy, - {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()), - IRB.CreatePointerCast(MI->getOperand(1), IRB.getInt8PtrTy()), - IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)}); - } else if (isa<MemSetInst>(MI)) { - IRB.CreateCall( - MemProfMemset, - {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()), - IRB.CreateIntCast(MI->getOperand(1), IRB.getInt32Ty(), false), - IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)}); - } - MI->eraseFromParent(); -} - -Optional<InterestingMemoryAccess> -MemProfiler::isInterestingMemoryAccess(Instruction *I) const { - // Do not instrument the load fetching the dynamic shadow address. - if (DynamicShadowOffset == I) - return None; - - InterestingMemoryAccess Access; - - const DataLayout &DL = I->getModule()->getDataLayout(); - if (LoadInst *LI = dyn_cast<LoadInst>(I)) { - if (!ClInstrumentReads) - return None; - Access.IsWrite = false; - Access.TypeSize = DL.getTypeStoreSizeInBits(LI->getType()); - Access.Alignment = LI->getAlignment(); - Access.Addr = LI->getPointerOperand(); - } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) { - if (!ClInstrumentWrites) - return None; - Access.IsWrite = true; - Access.TypeSize = - DL.getTypeStoreSizeInBits(SI->getValueOperand()->getType()); - Access.Alignment = SI->getAlignment(); - Access.Addr = SI->getPointerOperand(); - } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) { - if (!ClInstrumentAtomics) - return None; - Access.IsWrite = true; - Access.TypeSize = - DL.getTypeStoreSizeInBits(RMW->getValOperand()->getType()); - Access.Alignment = 0; - Access.Addr = RMW->getPointerOperand(); - } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) { - if (!ClInstrumentAtomics) - return None; - Access.IsWrite = true; - Access.TypeSize = - DL.getTypeStoreSizeInBits(XCHG->getCompareOperand()->getType()); - Access.Alignment = 0; - Access.Addr = XCHG->getPointerOperand(); - } else if (auto *CI = dyn_cast<CallInst>(I)) { - auto *F = CI->getCalledFunction(); - if (F && (F->getIntrinsicID() == Intrinsic::masked_load || - F->getIntrinsicID() == Intrinsic::masked_store)) { - unsigned OpOffset = 0; - if (F->getIntrinsicID() == Intrinsic::masked_store) { - if (!ClInstrumentWrites) - return None; - // Masked store has an initial operand for the value. - OpOffset = 1; - Access.IsWrite = true; - } else { - if (!ClInstrumentReads) - return None; - Access.IsWrite = false; - } - - auto *BasePtr = CI->getOperand(0 + OpOffset); - auto *Ty = cast<PointerType>(BasePtr->getType())->getElementType(); - Access.TypeSize = DL.getTypeStoreSizeInBits(Ty); - if (auto *AlignmentConstant = - dyn_cast<ConstantInt>(CI->getOperand(1 + OpOffset))) - Access.Alignment = (unsigned)AlignmentConstant->getZExtValue(); - else - Access.Alignment = 1; // No alignment guarantees. We probably got Undef - Access.MaybeMask = CI->getOperand(2 + OpOffset); - Access.Addr = BasePtr; - } - } - - if (!Access.Addr) - return None; - - // Do not instrument acesses from different address spaces; we cannot deal - // with them. - Type *PtrTy = cast<PointerType>(Access.Addr->getType()->getScalarType()); - if (PtrTy->getPointerAddressSpace() != 0) - return None; - - // Ignore swifterror addresses. - // swifterror memory addresses are mem2reg promoted by instruction - // selection. As such they cannot have regular uses like an instrumentation - // function and it makes no sense to track them as memory. - if (Access.Addr->isSwiftError()) - return None; - - return Access; -} - -void MemProfiler::instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask, - Instruction *I, Value *Addr, - unsigned Alignment, - uint32_t TypeSize, bool IsWrite) { - auto *VTy = cast<FixedVectorType>( - cast<PointerType>(Addr->getType())->getElementType()); - uint64_t ElemTypeSize = DL.getTypeStoreSizeInBits(VTy->getScalarType()); - unsigned Num = VTy->getNumElements(); - auto *Zero = ConstantInt::get(IntptrTy, 0); - for (unsigned Idx = 0; Idx < Num; ++Idx) { - Value *InstrumentedAddress = nullptr; - Instruction *InsertBefore = I; - if (auto *Vector = dyn_cast<ConstantVector>(Mask)) { - // dyn_cast as we might get UndefValue - if (auto *Masked = dyn_cast<ConstantInt>(Vector->getOperand(Idx))) { - if (Masked->isZero()) - // Mask is constant false, so no instrumentation needed. - continue; - // If we have a true or undef value, fall through to instrumentAddress. - // with InsertBefore == I - } - } else { - IRBuilder<> IRB(I); - Value *MaskElem = IRB.CreateExtractElement(Mask, Idx); - Instruction *ThenTerm = SplitBlockAndInsertIfThen(MaskElem, I, false); - InsertBefore = ThenTerm; - } - - IRBuilder<> IRB(InsertBefore); - InstrumentedAddress = - IRB.CreateGEP(VTy, Addr, {Zero, ConstantInt::get(IntptrTy, Idx)}); - instrumentAddress(I, InsertBefore, InstrumentedAddress, ElemTypeSize, - IsWrite); - } -} - -void MemProfiler::instrumentMop(Instruction *I, const DataLayout &DL, - InterestingMemoryAccess &Access) { - if (Access.IsWrite) - NumInstrumentedWrites++; - else - NumInstrumentedReads++; - - if (Access.MaybeMask) { - instrumentMaskedLoadOrStore(DL, Access.MaybeMask, I, Access.Addr, - Access.Alignment, Access.TypeSize, - Access.IsWrite); - } else { - // Since the access counts will be accumulated across the entire allocation, - // we only update the shadow access count for the first location and thus - // don't need to worry about alignment and type size. - instrumentAddress(I, I, Access.Addr, Access.TypeSize, Access.IsWrite); - } -} - -void MemProfiler::instrumentAddress(Instruction *OrigIns, - Instruction *InsertBefore, Value *Addr, - uint32_t TypeSize, bool IsWrite) { - IRBuilder<> IRB(InsertBefore); - Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy); - - if (ClUseCalls) { - IRB.CreateCall(MemProfMemoryAccessCallback[IsWrite], AddrLong); - return; - } - - // Create an inline sequence to compute shadow location, and increment the - // value by one. - Type *ShadowTy = Type::getInt64Ty(*C); - Type *ShadowPtrTy = PointerType::get(ShadowTy, 0); - Value *ShadowPtr = memToShadow(AddrLong, IRB); - Value *ShadowAddr = IRB.CreateIntToPtr(ShadowPtr, ShadowPtrTy); - Value *ShadowValue = IRB.CreateLoad(ShadowTy, ShadowAddr); - Value *Inc = ConstantInt::get(Type::getInt64Ty(*C), 1); - ShadowValue = IRB.CreateAdd(ShadowValue, Inc); - IRB.CreateStore(ShadowValue, ShadowAddr); -} - -// Create the variable for the profile file name. -void createProfileFileNameVar(Module &M) { - const MDString *MemProfFilename = - dyn_cast_or_null<MDString>(M.getModuleFlag("MemProfProfileFilename")); - if (!MemProfFilename) - return; - assert(!MemProfFilename->getString().empty() && - "Unexpected MemProfProfileFilename metadata with empty string"); - Constant *ProfileNameConst = ConstantDataArray::getString( - M.getContext(), MemProfFilename->getString(), true); - GlobalVariable *ProfileNameVar = new GlobalVariable( - M, ProfileNameConst->getType(), /*isConstant=*/true, - GlobalValue::WeakAnyLinkage, ProfileNameConst, MemProfFilenameVar); - Triple TT(M.getTargetTriple()); - if (TT.supportsCOMDAT()) { - ProfileNameVar->setLinkage(GlobalValue::ExternalLinkage); - ProfileNameVar->setComdat(M.getOrInsertComdat(MemProfFilenameVar)); - } -} - -bool ModuleMemProfiler::instrumentModule(Module &M) { - // Create a module constructor. - std::string MemProfVersion = std::to_string(LLVM_MEM_PROFILER_VERSION); - std::string VersionCheckName = - ClInsertVersionCheck ? (MemProfVersionCheckNamePrefix + MemProfVersion) - : ""; - std::tie(MemProfCtorFunction, std::ignore) = - createSanitizerCtorAndInitFunctions(M, MemProfModuleCtorName, - MemProfInitName, /*InitArgTypes=*/{}, - /*InitArgs=*/{}, VersionCheckName); - - const uint64_t Priority = getCtorAndDtorPriority(TargetTriple); - appendToGlobalCtors(M, MemProfCtorFunction, Priority); - - createProfileFileNameVar(M); - - return true; -} - -void MemProfiler::initializeCallbacks(Module &M) { - IRBuilder<> IRB(*C); - - for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) { - const std::string TypeStr = AccessIsWrite ? "store" : "load"; - - SmallVector<Type *, 3> Args2 = {IntptrTy, IntptrTy}; - SmallVector<Type *, 2> Args1{1, IntptrTy}; - MemProfMemoryAccessCallbackSized[AccessIsWrite] = - M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + TypeStr + "N", - FunctionType::get(IRB.getVoidTy(), Args2, false)); - - MemProfMemoryAccessCallback[AccessIsWrite] = - M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + TypeStr, - FunctionType::get(IRB.getVoidTy(), Args1, false)); - } - MemProfMemmove = M.getOrInsertFunction( - ClMemoryAccessCallbackPrefix + "memmove", IRB.getInt8PtrTy(), - IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy); - MemProfMemcpy = M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + "memcpy", - IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), - IRB.getInt8PtrTy(), IntptrTy); - MemProfMemset = M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + "memset", - IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), - IRB.getInt32Ty(), IntptrTy); -} - -bool MemProfiler::maybeInsertMemProfInitAtFunctionEntry(Function &F) { - // For each NSObject descendant having a +load method, this method is invoked - // by the ObjC runtime before any of the static constructors is called. - // Therefore we need to instrument such methods with a call to __memprof_init - // at the beginning in order to initialize our runtime before any access to - // the shadow memory. - // We cannot just ignore these methods, because they may call other - // instrumented functions. - if (F.getName().find(" load]") != std::string::npos) { - FunctionCallee MemProfInitFunction = - declareSanitizerInitFunction(*F.getParent(), MemProfInitName, {}); - IRBuilder<> IRB(&F.front(), F.front().begin()); - IRB.CreateCall(MemProfInitFunction, {}); - return true; - } - return false; -} - -bool MemProfiler::insertDynamicShadowAtFunctionEntry(Function &F) { - IRBuilder<> IRB(&F.front().front()); - Value *GlobalDynamicAddress = F.getParent()->getOrInsertGlobal( - MemProfShadowMemoryDynamicAddress, IntptrTy); - if (F.getParent()->getPICLevel() == PICLevel::NotPIC) - cast<GlobalVariable>(GlobalDynamicAddress)->setDSOLocal(true); - DynamicShadowOffset = IRB.CreateLoad(IntptrTy, GlobalDynamicAddress); - return true; -} - -bool MemProfiler::instrumentFunction(Function &F) { - if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) - return false; - if (ClDebugFunc == F.getName()) - return false; - if (F.getName().startswith("__memprof_")) - return false; - - bool FunctionModified = false; - - // If needed, insert __memprof_init. - // This function needs to be called even if the function body is not - // instrumented. - if (maybeInsertMemProfInitAtFunctionEntry(F)) - FunctionModified = true; - - LLVM_DEBUG(dbgs() << "MEMPROF instrumenting:\n" << F << "\n"); - - initializeCallbacks(*F.getParent()); - - FunctionModified |= insertDynamicShadowAtFunctionEntry(F); - - SmallVector<Instruction *, 16> ToInstrument; - - // Fill the set of memory operations to instrument. - for (auto &BB : F) { - for (auto &Inst : BB) { - if (isInterestingMemoryAccess(&Inst) || isa<MemIntrinsic>(Inst)) - ToInstrument.push_back(&Inst); - } - } - - int NumInstrumented = 0; - for (auto *Inst : ToInstrument) { - if (ClDebugMin < 0 || ClDebugMax < 0 || - (NumInstrumented >= ClDebugMin && NumInstrumented <= ClDebugMax)) { - Optional<InterestingMemoryAccess> Access = - isInterestingMemoryAccess(Inst); - if (Access) - instrumentMop(Inst, F.getParent()->getDataLayout(), *Access); - else - instrumentMemIntrinsic(cast<MemIntrinsic>(Inst)); - } - NumInstrumented++; - } - - if (NumInstrumented > 0) - FunctionModified = true; - - LLVM_DEBUG(dbgs() << "MEMPROF done instrumenting: " << FunctionModified << " " - << F << "\n"); - - return FunctionModified; -} +//===- MemProfiler.cpp - memory allocation and access profiler ------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemProfiler. Memory accesses are instrumented +// to increment the access count held in a shadow memory location, or +// alternatively to call into the runtime. Memory intrinsic calls (memmove, +// memcpy, memset) are changed to call the memory profiling runtime version +// instead. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Instrumentation/MemProfiler.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Value.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Transforms/Instrumentation.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" + +using namespace llvm; + +#define DEBUG_TYPE "memprof" + +constexpr int LLVM_MEM_PROFILER_VERSION = 1; + +// Size of memory mapped to a single shadow location. +constexpr uint64_t DefaultShadowGranularity = 64; + +// Scale from granularity down to shadow size. +constexpr uint64_t DefaultShadowScale = 3; + +constexpr char MemProfModuleCtorName[] = "memprof.module_ctor"; +constexpr uint64_t MemProfCtorAndDtorPriority = 1; +// On Emscripten, the system needs more than one priorities for constructors. +constexpr uint64_t MemProfEmscriptenCtorAndDtorPriority = 50; +constexpr char MemProfInitName[] = "__memprof_init"; +constexpr char MemProfVersionCheckNamePrefix[] = + "__memprof_version_mismatch_check_v"; + +constexpr char MemProfShadowMemoryDynamicAddress[] = + "__memprof_shadow_memory_dynamic_address"; + +constexpr char MemProfFilenameVar[] = "__memprof_profile_filename"; + +// Command-line flags. + +static cl::opt<bool> ClInsertVersionCheck( + "memprof-guard-against-version-mismatch", + cl::desc("Guard against compiler/runtime version mismatch."), cl::Hidden, + cl::init(true)); + +// This flag may need to be replaced with -f[no-]memprof-reads. +static cl::opt<bool> ClInstrumentReads("memprof-instrument-reads", + cl::desc("instrument read instructions"), + cl::Hidden, cl::init(true)); + +static cl::opt<bool> + ClInstrumentWrites("memprof-instrument-writes", + cl::desc("instrument write instructions"), cl::Hidden, + cl::init(true)); + +static cl::opt<bool> ClInstrumentAtomics( + "memprof-instrument-atomics", + cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden, + cl::init(true)); + +static cl::opt<bool> ClUseCalls( + "memprof-use-callbacks", + cl::desc("Use callbacks instead of inline instrumentation sequences."), + cl::Hidden, cl::init(false)); + +static cl::opt<std::string> + ClMemoryAccessCallbackPrefix("memprof-memory-access-callback-prefix", + cl::desc("Prefix for memory access callbacks"), + cl::Hidden, cl::init("__memprof_")); + +// These flags allow to change the shadow mapping. +// The shadow mapping looks like +// Shadow = ((Mem & mask) >> scale) + offset + +static cl::opt<int> ClMappingScale("memprof-mapping-scale", + cl::desc("scale of memprof shadow mapping"), + cl::Hidden, cl::init(DefaultShadowScale)); + +static cl::opt<int> + ClMappingGranularity("memprof-mapping-granularity", + cl::desc("granularity of memprof shadow mapping"), + cl::Hidden, cl::init(DefaultShadowGranularity)); + +// Debug flags. + +static cl::opt<int> ClDebug("memprof-debug", cl::desc("debug"), cl::Hidden, + cl::init(0)); + +static cl::opt<std::string> ClDebugFunc("memprof-debug-func", cl::Hidden, + cl::desc("Debug func")); + +static cl::opt<int> ClDebugMin("memprof-debug-min", cl::desc("Debug min inst"), + cl::Hidden, cl::init(-1)); + +static cl::opt<int> ClDebugMax("memprof-debug-max", cl::desc("Debug max inst"), + cl::Hidden, cl::init(-1)); + +STATISTIC(NumInstrumentedReads, "Number of instrumented reads"); +STATISTIC(NumInstrumentedWrites, "Number of instrumented writes"); + +namespace { + +/// This struct defines the shadow mapping using the rule: +/// shadow = ((mem & mask) >> Scale) ADD DynamicShadowOffset. +struct ShadowMapping { + ShadowMapping() { + Scale = ClMappingScale; + Granularity = ClMappingGranularity; + Mask = ~(Granularity - 1); + } + + int Scale; + int Granularity; + uint64_t Mask; // Computed as ~(Granularity-1) +}; + +static uint64_t getCtorAndDtorPriority(Triple &TargetTriple) { + return TargetTriple.isOSEmscripten() ? MemProfEmscriptenCtorAndDtorPriority + : MemProfCtorAndDtorPriority; +} + +struct InterestingMemoryAccess { + Value *Addr = nullptr; + bool IsWrite; + unsigned Alignment; + uint64_t TypeSize; + Value *MaybeMask = nullptr; +}; + +/// Instrument the code in module to profile memory accesses. +class MemProfiler { +public: + MemProfiler(Module &M) { + C = &(M.getContext()); + LongSize = M.getDataLayout().getPointerSizeInBits(); + IntptrTy = Type::getIntNTy(*C, LongSize); + } + + /// If it is an interesting memory access, populate information + /// about the access and return a InterestingMemoryAccess struct. + /// Otherwise return None. + Optional<InterestingMemoryAccess> + isInterestingMemoryAccess(Instruction *I) const; + + void instrumentMop(Instruction *I, const DataLayout &DL, + InterestingMemoryAccess &Access); + void instrumentAddress(Instruction *OrigIns, Instruction *InsertBefore, + Value *Addr, uint32_t TypeSize, bool IsWrite); + void instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask, + Instruction *I, Value *Addr, + unsigned Alignment, uint32_t TypeSize, + bool IsWrite); + void instrumentMemIntrinsic(MemIntrinsic *MI); + Value *memToShadow(Value *Shadow, IRBuilder<> &IRB); + bool instrumentFunction(Function &F); + bool maybeInsertMemProfInitAtFunctionEntry(Function &F); + bool insertDynamicShadowAtFunctionEntry(Function &F); + +private: + void initializeCallbacks(Module &M); + + LLVMContext *C; + int LongSize; + Type *IntptrTy; + ShadowMapping Mapping; + + // These arrays is indexed by AccessIsWrite + FunctionCallee MemProfMemoryAccessCallback[2]; + FunctionCallee MemProfMemoryAccessCallbackSized[2]; + + FunctionCallee MemProfMemmove, MemProfMemcpy, MemProfMemset; + Value *DynamicShadowOffset = nullptr; +}; + +class MemProfilerLegacyPass : public FunctionPass { +public: + static char ID; + + explicit MemProfilerLegacyPass() : FunctionPass(ID) { + initializeMemProfilerLegacyPassPass(*PassRegistry::getPassRegistry()); + } + + StringRef getPassName() const override { return "MemProfilerFunctionPass"; } + + bool runOnFunction(Function &F) override { + MemProfiler Profiler(*F.getParent()); + return Profiler.instrumentFunction(F); + } +}; + +class ModuleMemProfiler { +public: + ModuleMemProfiler(Module &M) { TargetTriple = Triple(M.getTargetTriple()); } + + bool instrumentModule(Module &); + +private: + Triple TargetTriple; + ShadowMapping Mapping; + Function *MemProfCtorFunction = nullptr; +}; + +class ModuleMemProfilerLegacyPass : public ModulePass { +public: + static char ID; + + explicit ModuleMemProfilerLegacyPass() : ModulePass(ID) { + initializeModuleMemProfilerLegacyPassPass(*PassRegistry::getPassRegistry()); + } + + StringRef getPassName() const override { return "ModuleMemProfiler"; } + + void getAnalysisUsage(AnalysisUsage &AU) const override {} + + bool runOnModule(Module &M) override { + ModuleMemProfiler MemProfiler(M); + return MemProfiler.instrumentModule(M); + } +}; + +} // end anonymous namespace + +MemProfilerPass::MemProfilerPass() {} + +PreservedAnalyses MemProfilerPass::run(Function &F, + AnalysisManager<Function> &AM) { + Module &M = *F.getParent(); + MemProfiler Profiler(M); + if (Profiler.instrumentFunction(F)) + return PreservedAnalyses::none(); + return PreservedAnalyses::all(); + + return PreservedAnalyses::all(); +} + +ModuleMemProfilerPass::ModuleMemProfilerPass() {} + +PreservedAnalyses ModuleMemProfilerPass::run(Module &M, + AnalysisManager<Module> &AM) { + ModuleMemProfiler Profiler(M); + if (Profiler.instrumentModule(M)) + return PreservedAnalyses::none(); + return PreservedAnalyses::all(); +} + +char MemProfilerLegacyPass::ID = 0; + +INITIALIZE_PASS_BEGIN(MemProfilerLegacyPass, "memprof", + "MemProfiler: profile memory allocations and accesses.", + false, false) +INITIALIZE_PASS_END(MemProfilerLegacyPass, "memprof", + "MemProfiler: profile memory allocations and accesses.", + false, false) + +FunctionPass *llvm::createMemProfilerFunctionPass() { + return new MemProfilerLegacyPass(); +} + +char ModuleMemProfilerLegacyPass::ID = 0; + +INITIALIZE_PASS(ModuleMemProfilerLegacyPass, "memprof-module", + "MemProfiler: profile memory allocations and accesses." + "ModulePass", + false, false) + +ModulePass *llvm::createModuleMemProfilerLegacyPassPass() { + return new ModuleMemProfilerLegacyPass(); +} + +Value *MemProfiler::memToShadow(Value *Shadow, IRBuilder<> &IRB) { + // (Shadow & mask) >> scale + Shadow = IRB.CreateAnd(Shadow, Mapping.Mask); + Shadow = IRB.CreateLShr(Shadow, Mapping.Scale); + // (Shadow >> scale) | offset + assert(DynamicShadowOffset); + return IRB.CreateAdd(Shadow, DynamicShadowOffset); +} + +// Instrument memset/memmove/memcpy +void MemProfiler::instrumentMemIntrinsic(MemIntrinsic *MI) { + IRBuilder<> IRB(MI); + if (isa<MemTransferInst>(MI)) { + IRB.CreateCall( + isa<MemMoveInst>(MI) ? MemProfMemmove : MemProfMemcpy, + {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()), + IRB.CreatePointerCast(MI->getOperand(1), IRB.getInt8PtrTy()), + IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)}); + } else if (isa<MemSetInst>(MI)) { + IRB.CreateCall( + MemProfMemset, + {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()), + IRB.CreateIntCast(MI->getOperand(1), IRB.getInt32Ty(), false), + IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)}); + } + MI->eraseFromParent(); +} + +Optional<InterestingMemoryAccess> +MemProfiler::isInterestingMemoryAccess(Instruction *I) const { + // Do not instrument the load fetching the dynamic shadow address. + if (DynamicShadowOffset == I) + return None; + + InterestingMemoryAccess Access; + + const DataLayout &DL = I->getModule()->getDataLayout(); + if (LoadInst *LI = dyn_cast<LoadInst>(I)) { + if (!ClInstrumentReads) + return None; + Access.IsWrite = false; + Access.TypeSize = DL.getTypeStoreSizeInBits(LI->getType()); + Access.Alignment = LI->getAlignment(); + Access.Addr = LI->getPointerOperand(); + } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) { + if (!ClInstrumentWrites) + return None; + Access.IsWrite = true; + Access.TypeSize = + DL.getTypeStoreSizeInBits(SI->getValueOperand()->getType()); + Access.Alignment = SI->getAlignment(); + Access.Addr = SI->getPointerOperand(); + } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) { + if (!ClInstrumentAtomics) + return None; + Access.IsWrite = true; + Access.TypeSize = + DL.getTypeStoreSizeInBits(RMW->getValOperand()->getType()); + Access.Alignment = 0; + Access.Addr = RMW->getPointerOperand(); + } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) { + if (!ClInstrumentAtomics) + return None; + Access.IsWrite = true; + Access.TypeSize = + DL.getTypeStoreSizeInBits(XCHG->getCompareOperand()->getType()); + Access.Alignment = 0; + Access.Addr = XCHG->getPointerOperand(); + } else if (auto *CI = dyn_cast<CallInst>(I)) { + auto *F = CI->getCalledFunction(); + if (F && (F->getIntrinsicID() == Intrinsic::masked_load || + F->getIntrinsicID() == Intrinsic::masked_store)) { + unsigned OpOffset = 0; + if (F->getIntrinsicID() == Intrinsic::masked_store) { + if (!ClInstrumentWrites) + return None; + // Masked store has an initial operand for the value. + OpOffset = 1; + Access.IsWrite = true; + } else { + if (!ClInstrumentReads) + return None; + Access.IsWrite = false; + } + + auto *BasePtr = CI->getOperand(0 + OpOffset); + auto *Ty = cast<PointerType>(BasePtr->getType())->getElementType(); + Access.TypeSize = DL.getTypeStoreSizeInBits(Ty); + if (auto *AlignmentConstant = + dyn_cast<ConstantInt>(CI->getOperand(1 + OpOffset))) + Access.Alignment = (unsigned)AlignmentConstant->getZExtValue(); + else + Access.Alignment = 1; // No alignment guarantees. We probably got Undef + Access.MaybeMask = CI->getOperand(2 + OpOffset); + Access.Addr = BasePtr; + } + } + + if (!Access.Addr) + return None; + + // Do not instrument acesses from different address spaces; we cannot deal + // with them. + Type *PtrTy = cast<PointerType>(Access.Addr->getType()->getScalarType()); + if (PtrTy->getPointerAddressSpace() != 0) + return None; + + // Ignore swifterror addresses. + // swifterror memory addresses are mem2reg promoted by instruction + // selection. As such they cannot have regular uses like an instrumentation + // function and it makes no sense to track them as memory. + if (Access.Addr->isSwiftError()) + return None; + + return Access; +} + +void MemProfiler::instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask, + Instruction *I, Value *Addr, + unsigned Alignment, + uint32_t TypeSize, bool IsWrite) { + auto *VTy = cast<FixedVectorType>( + cast<PointerType>(Addr->getType())->getElementType()); + uint64_t ElemTypeSize = DL.getTypeStoreSizeInBits(VTy->getScalarType()); + unsigned Num = VTy->getNumElements(); + auto *Zero = ConstantInt::get(IntptrTy, 0); + for (unsigned Idx = 0; Idx < Num; ++Idx) { + Value *InstrumentedAddress = nullptr; + Instruction *InsertBefore = I; + if (auto *Vector = dyn_cast<ConstantVector>(Mask)) { + // dyn_cast as we might get UndefValue + if (auto *Masked = dyn_cast<ConstantInt>(Vector->getOperand(Idx))) { + if (Masked->isZero()) + // Mask is constant false, so no instrumentation needed. + continue; + // If we have a true or undef value, fall through to instrumentAddress. + // with InsertBefore == I + } + } else { + IRBuilder<> IRB(I); + Value *MaskElem = IRB.CreateExtractElement(Mask, Idx); + Instruction *ThenTerm = SplitBlockAndInsertIfThen(MaskElem, I, false); + InsertBefore = ThenTerm; + } + + IRBuilder<> IRB(InsertBefore); + InstrumentedAddress = + IRB.CreateGEP(VTy, Addr, {Zero, ConstantInt::get(IntptrTy, Idx)}); + instrumentAddress(I, InsertBefore, InstrumentedAddress, ElemTypeSize, + IsWrite); + } +} + +void MemProfiler::instrumentMop(Instruction *I, const DataLayout &DL, + InterestingMemoryAccess &Access) { + if (Access.IsWrite) + NumInstrumentedWrites++; + else + NumInstrumentedReads++; + + if (Access.MaybeMask) { + instrumentMaskedLoadOrStore(DL, Access.MaybeMask, I, Access.Addr, + Access.Alignment, Access.TypeSize, + Access.IsWrite); + } else { + // Since the access counts will be accumulated across the entire allocation, + // we only update the shadow access count for the first location and thus + // don't need to worry about alignment and type size. + instrumentAddress(I, I, Access.Addr, Access.TypeSize, Access.IsWrite); + } +} + +void MemProfiler::instrumentAddress(Instruction *OrigIns, + Instruction *InsertBefore, Value *Addr, + uint32_t TypeSize, bool IsWrite) { + IRBuilder<> IRB(InsertBefore); + Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy); + + if (ClUseCalls) { + IRB.CreateCall(MemProfMemoryAccessCallback[IsWrite], AddrLong); + return; + } + + // Create an inline sequence to compute shadow location, and increment the + // value by one. + Type *ShadowTy = Type::getInt64Ty(*C); + Type *ShadowPtrTy = PointerType::get(ShadowTy, 0); + Value *ShadowPtr = memToShadow(AddrLong, IRB); + Value *ShadowAddr = IRB.CreateIntToPtr(ShadowPtr, ShadowPtrTy); + Value *ShadowValue = IRB.CreateLoad(ShadowTy, ShadowAddr); + Value *Inc = ConstantInt::get(Type::getInt64Ty(*C), 1); + ShadowValue = IRB.CreateAdd(ShadowValue, Inc); + IRB.CreateStore(ShadowValue, ShadowAddr); +} + +// Create the variable for the profile file name. +void createProfileFileNameVar(Module &M) { + const MDString *MemProfFilename = + dyn_cast_or_null<MDString>(M.getModuleFlag("MemProfProfileFilename")); + if (!MemProfFilename) + return; + assert(!MemProfFilename->getString().empty() && + "Unexpected MemProfProfileFilename metadata with empty string"); + Constant *ProfileNameConst = ConstantDataArray::getString( + M.getContext(), MemProfFilename->getString(), true); + GlobalVariable *ProfileNameVar = new GlobalVariable( + M, ProfileNameConst->getType(), /*isConstant=*/true, + GlobalValue::WeakAnyLinkage, ProfileNameConst, MemProfFilenameVar); + Triple TT(M.getTargetTriple()); + if (TT.supportsCOMDAT()) { + ProfileNameVar->setLinkage(GlobalValue::ExternalLinkage); + ProfileNameVar->setComdat(M.getOrInsertComdat(MemProfFilenameVar)); + } +} + +bool ModuleMemProfiler::instrumentModule(Module &M) { + // Create a module constructor. + std::string MemProfVersion = std::to_string(LLVM_MEM_PROFILER_VERSION); + std::string VersionCheckName = + ClInsertVersionCheck ? (MemProfVersionCheckNamePrefix + MemProfVersion) + : ""; + std::tie(MemProfCtorFunction, std::ignore) = + createSanitizerCtorAndInitFunctions(M, MemProfModuleCtorName, + MemProfInitName, /*InitArgTypes=*/{}, + /*InitArgs=*/{}, VersionCheckName); + + const uint64_t Priority = getCtorAndDtorPriority(TargetTriple); + appendToGlobalCtors(M, MemProfCtorFunction, Priority); + + createProfileFileNameVar(M); + + return true; +} + +void MemProfiler::initializeCallbacks(Module &M) { + IRBuilder<> IRB(*C); + + for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) { + const std::string TypeStr = AccessIsWrite ? "store" : "load"; + + SmallVector<Type *, 3> Args2 = {IntptrTy, IntptrTy}; + SmallVector<Type *, 2> Args1{1, IntptrTy}; + MemProfMemoryAccessCallbackSized[AccessIsWrite] = + M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + TypeStr + "N", + FunctionType::get(IRB.getVoidTy(), Args2, false)); + + MemProfMemoryAccessCallback[AccessIsWrite] = + M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + TypeStr, + FunctionType::get(IRB.getVoidTy(), Args1, false)); + } + MemProfMemmove = M.getOrInsertFunction( + ClMemoryAccessCallbackPrefix + "memmove", IRB.getInt8PtrTy(), + IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy); + MemProfMemcpy = M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + "memcpy", + IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), + IRB.getInt8PtrTy(), IntptrTy); + MemProfMemset = M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + "memset", + IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), + IRB.getInt32Ty(), IntptrTy); +} + +bool MemProfiler::maybeInsertMemProfInitAtFunctionEntry(Function &F) { + // For each NSObject descendant having a +load method, this method is invoked + // by the ObjC runtime before any of the static constructors is called. + // Therefore we need to instrument such methods with a call to __memprof_init + // at the beginning in order to initialize our runtime before any access to + // the shadow memory. + // We cannot just ignore these methods, because they may call other + // instrumented functions. + if (F.getName().find(" load]") != std::string::npos) { + FunctionCallee MemProfInitFunction = + declareSanitizerInitFunction(*F.getParent(), MemProfInitName, {}); + IRBuilder<> IRB(&F.front(), F.front().begin()); + IRB.CreateCall(MemProfInitFunction, {}); + return true; + } + return false; +} + +bool MemProfiler::insertDynamicShadowAtFunctionEntry(Function &F) { + IRBuilder<> IRB(&F.front().front()); + Value *GlobalDynamicAddress = F.getParent()->getOrInsertGlobal( + MemProfShadowMemoryDynamicAddress, IntptrTy); + if (F.getParent()->getPICLevel() == PICLevel::NotPIC) + cast<GlobalVariable>(GlobalDynamicAddress)->setDSOLocal(true); + DynamicShadowOffset = IRB.CreateLoad(IntptrTy, GlobalDynamicAddress); + return true; +} + +bool MemProfiler::instrumentFunction(Function &F) { + if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) + return false; + if (ClDebugFunc == F.getName()) + return false; + if (F.getName().startswith("__memprof_")) + return false; + + bool FunctionModified = false; + + // If needed, insert __memprof_init. + // This function needs to be called even if the function body is not + // instrumented. + if (maybeInsertMemProfInitAtFunctionEntry(F)) + FunctionModified = true; + + LLVM_DEBUG(dbgs() << "MEMPROF instrumenting:\n" << F << "\n"); + + initializeCallbacks(*F.getParent()); + + FunctionModified |= insertDynamicShadowAtFunctionEntry(F); + + SmallVector<Instruction *, 16> ToInstrument; + + // Fill the set of memory operations to instrument. + for (auto &BB : F) { + for (auto &Inst : BB) { + if (isInterestingMemoryAccess(&Inst) || isa<MemIntrinsic>(Inst)) + ToInstrument.push_back(&Inst); + } + } + + int NumInstrumented = 0; + for (auto *Inst : ToInstrument) { + if (ClDebugMin < 0 || ClDebugMax < 0 || + (NumInstrumented >= ClDebugMin && NumInstrumented <= ClDebugMax)) { + Optional<InterestingMemoryAccess> Access = + isInterestingMemoryAccess(Inst); + if (Access) + instrumentMop(Inst, F.getParent()->getDataLayout(), *Access); + else + instrumentMemIntrinsic(cast<MemIntrinsic>(Inst)); + } + NumInstrumented++; + } + + if (NumInstrumented > 0) + FunctionModified = true; + + LLVM_DEBUG(dbgs() << "MEMPROF done instrumenting: " << FunctionModified << " " + << F << "\n"); + + return FunctionModified; +} |