Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/Instrumentation/MemProfInstrumentation.cpp
213799 views
//===- MemProfInstrumentation.cpp - memory alloc and access instrumentation ==//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file is a part of MemProf. Memory accesses are instrumented9// to increment the access count held in a shadow memory location, or10// alternatively to call into the runtime. Memory intrinsic calls (memmove,11// memcpy, memset) are changed to call the memory profiling runtime version12// instead.13//14//===----------------------------------------------------------------------===//1516#include "llvm/Transforms/Instrumentation/MemProfInstrumentation.h"17#include "llvm/ADT/SmallVector.h"18#include "llvm/ADT/Statistic.h"19#include "llvm/ADT/StringRef.h"20#include "llvm/Analysis/MemoryBuiltins.h"21#include "llvm/Analysis/TargetLibraryInfo.h"22#include "llvm/Analysis/ValueTracking.h"23#include "llvm/IR/Constant.h"24#include "llvm/IR/DataLayout.h"25#include "llvm/IR/DiagnosticInfo.h"26#include "llvm/IR/Function.h"27#include "llvm/IR/GlobalValue.h"28#include "llvm/IR/IRBuilder.h"29#include "llvm/IR/Instruction.h"30#include "llvm/IR/IntrinsicInst.h"31#include "llvm/IR/Module.h"32#include "llvm/IR/Type.h"33#include "llvm/IR/Value.h"34#include "llvm/ProfileData/InstrProf.h"35#include "llvm/ProfileData/MemProf.h"36#include "llvm/Support/CommandLine.h"37#include "llvm/Support/Debug.h"38#include "llvm/TargetParser/Triple.h"39#include "llvm/Transforms/Utils/BasicBlockUtils.h"40#include "llvm/Transforms/Utils/ModuleUtils.h"4142using namespace llvm;43using namespace llvm::memprof;4445#define DEBUG_TYPE "memprof"4647constexpr int LLVM_MEM_PROFILER_VERSION = 1;4849// Size of memory mapped to a single shadow location.50constexpr uint64_t DefaultMemGranularity = 64;5152// Size of memory mapped to a single histogram bucket.53constexpr uint64_t HistogramGranularity = 8;5455// Scale from granularity down to shadow size.56constexpr uint64_t DefaultShadowScale = 3;5758constexpr char MemProfModuleCtorName[] = "memprof.module_ctor";59constexpr uint64_t MemProfCtorAndDtorPriority = 1;60// On Emscripten, the system needs more than one priorities for constructors.61constexpr uint64_t MemProfEmscriptenCtorAndDtorPriority = 50;62constexpr char MemProfInitName[] = "__memprof_init";63constexpr char MemProfVersionCheckNamePrefix[] =64"__memprof_version_mismatch_check_v";6566constexpr char MemProfShadowMemoryDynamicAddress[] =67"__memprof_shadow_memory_dynamic_address";6869constexpr char MemProfFilenameVar[] = "__memprof_profile_filename";7071constexpr char MemProfHistogramFlagVar[] = "__memprof_histogram";7273// Command-line flags.7475static cl::opt<bool> ClInsertVersionCheck(76"memprof-guard-against-version-mismatch",77cl::desc("Guard against compiler/runtime version mismatch."), cl::Hidden,78cl::init(true));7980// This flag may need to be replaced with -f[no-]memprof-reads.81static cl::opt<bool> ClInstrumentReads("memprof-instrument-reads",82cl::desc("instrument read instructions"),83cl::Hidden, cl::init(true));8485static cl::opt<bool>86ClInstrumentWrites("memprof-instrument-writes",87cl::desc("instrument write instructions"), cl::Hidden,88cl::init(true));8990static cl::opt<bool> ClInstrumentAtomics(91"memprof-instrument-atomics",92cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden,93cl::init(true));9495static cl::opt<bool> ClUseCalls(96"memprof-use-callbacks",97cl::desc("Use callbacks instead of inline instrumentation sequences."),98cl::Hidden, cl::init(false));99100static cl::opt<std::string>101ClMemoryAccessCallbackPrefix("memprof-memory-access-callback-prefix",102cl::desc("Prefix for memory access callbacks"),103cl::Hidden, cl::init("__memprof_"));104105// These flags allow to change the shadow mapping.106// The shadow mapping looks like107// Shadow = ((Mem & mask) >> scale) + offset108109static cl::opt<int> ClMappingScale("memprof-mapping-scale",110cl::desc("scale of memprof shadow mapping"),111cl::Hidden, cl::init(DefaultShadowScale));112113static cl::opt<int>114ClMappingGranularity("memprof-mapping-granularity",115cl::desc("granularity of memprof shadow mapping"),116cl::Hidden, cl::init(DefaultMemGranularity));117118static cl::opt<bool> ClStack("memprof-instrument-stack",119cl::desc("Instrument scalar stack variables"),120cl::Hidden, cl::init(false));121122// Debug flags.123124static cl::opt<int> ClDebug("memprof-debug", cl::desc("debug"), cl::Hidden,125cl::init(0));126127static cl::opt<std::string> ClDebugFunc("memprof-debug-func", cl::Hidden,128cl::desc("Debug func"));129130static cl::opt<int> ClDebugMin("memprof-debug-min", cl::desc("Debug min inst"),131cl::Hidden, cl::init(-1));132133static cl::opt<int> ClDebugMax("memprof-debug-max", cl::desc("Debug max inst"),134cl::Hidden, cl::init(-1));135136static cl::opt<bool> ClHistogram("memprof-histogram",137cl::desc("Collect access count histograms"),138cl::Hidden, cl::init(false));139140static cl::opt<std::string>141MemprofRuntimeDefaultOptions("memprof-runtime-default-options",142cl::desc("The default memprof options"),143cl::Hidden, cl::init(""));144145// Instrumentation statistics146STATISTIC(NumInstrumentedReads, "Number of instrumented reads");147STATISTIC(NumInstrumentedWrites, "Number of instrumented writes");148STATISTIC(NumSkippedStackReads, "Number of non-instrumented stack reads");149STATISTIC(NumSkippedStackWrites, "Number of non-instrumented stack writes");150151namespace {152153/// This struct defines the shadow mapping using the rule:154/// shadow = ((mem & mask) >> Scale) ADD DynamicShadowOffset.155struct ShadowMapping {156ShadowMapping() {157Scale = ClMappingScale;158Granularity = ClHistogram ? HistogramGranularity : ClMappingGranularity;159Mask = ~(Granularity - 1);160}161162int Scale;163int Granularity;164uint64_t Mask; // Computed as ~(Granularity-1)165};166167static uint64_t getCtorAndDtorPriority(Triple &TargetTriple) {168return TargetTriple.isOSEmscripten() ? MemProfEmscriptenCtorAndDtorPriority169: MemProfCtorAndDtorPriority;170}171172struct InterestingMemoryAccess {173Value *Addr = nullptr;174bool IsWrite;175Type *AccessTy;176Value *MaybeMask = nullptr;177};178179/// Instrument the code in module to profile memory accesses.180class MemProfiler {181public:182MemProfiler(Module &M) {183C = &(M.getContext());184LongSize = M.getDataLayout().getPointerSizeInBits();185IntptrTy = Type::getIntNTy(*C, LongSize);186PtrTy = PointerType::getUnqual(*C);187}188189/// If it is an interesting memory access, populate information190/// about the access and return a InterestingMemoryAccess struct.191/// Otherwise return std::nullopt.192std::optional<InterestingMemoryAccess>193isInterestingMemoryAccess(Instruction *I) const;194195void instrumentMop(Instruction *I, const DataLayout &DL,196InterestingMemoryAccess &Access);197void instrumentAddress(Instruction *OrigIns, Instruction *InsertBefore,198Value *Addr, bool IsWrite);199void instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask,200Instruction *I, Value *Addr, Type *AccessTy,201bool IsWrite);202void instrumentMemIntrinsic(MemIntrinsic *MI);203Value *memToShadow(Value *Shadow, IRBuilder<> &IRB);204bool instrumentFunction(Function &F);205bool maybeInsertMemProfInitAtFunctionEntry(Function &F);206bool insertDynamicShadowAtFunctionEntry(Function &F);207208private:209void initializeCallbacks(Module &M);210211LLVMContext *C;212int LongSize;213Type *IntptrTy;214PointerType *PtrTy;215ShadowMapping Mapping;216217// These arrays is indexed by AccessIsWrite218FunctionCallee MemProfMemoryAccessCallback[2];219220FunctionCallee MemProfMemmove, MemProfMemcpy, MemProfMemset;221Value *DynamicShadowOffset = nullptr;222};223224class ModuleMemProfiler {225public:226ModuleMemProfiler(Module &M) { TargetTriple = M.getTargetTriple(); }227228bool instrumentModule(Module &);229230private:231Triple TargetTriple;232ShadowMapping Mapping;233Function *MemProfCtorFunction = nullptr;234};235236} // end anonymous namespace237238MemProfilerPass::MemProfilerPass() = default;239240PreservedAnalyses MemProfilerPass::run(Function &F,241AnalysisManager<Function> &AM) {242assert((!ClHistogram || ClMappingGranularity == DefaultMemGranularity) &&243"Memprof with histogram only supports default mapping granularity");244Module &M = *F.getParent();245MemProfiler Profiler(M);246if (Profiler.instrumentFunction(F))247return PreservedAnalyses::none();248return PreservedAnalyses::all();249}250251ModuleMemProfilerPass::ModuleMemProfilerPass() = default;252253PreservedAnalyses ModuleMemProfilerPass::run(Module &M,254AnalysisManager<Module> &AM) {255256ModuleMemProfiler Profiler(M);257if (Profiler.instrumentModule(M))258return PreservedAnalyses::none();259return PreservedAnalyses::all();260}261262Value *MemProfiler::memToShadow(Value *Shadow, IRBuilder<> &IRB) {263// (Shadow & mask) >> scale264Shadow = IRB.CreateAnd(Shadow, Mapping.Mask);265Shadow = IRB.CreateLShr(Shadow, Mapping.Scale);266// (Shadow >> scale) | offset267assert(DynamicShadowOffset);268return IRB.CreateAdd(Shadow, DynamicShadowOffset);269}270271// Instrument memset/memmove/memcpy272void MemProfiler::instrumentMemIntrinsic(MemIntrinsic *MI) {273IRBuilder<> IRB(MI);274if (isa<MemTransferInst>(MI)) {275IRB.CreateCall(isa<MemMoveInst>(MI) ? MemProfMemmove : MemProfMemcpy,276{MI->getOperand(0), MI->getOperand(1),277IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)});278} else if (isa<MemSetInst>(MI)) {279IRB.CreateCall(280MemProfMemset,281{MI->getOperand(0),282IRB.CreateIntCast(MI->getOperand(1), IRB.getInt32Ty(), false),283IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)});284}285MI->eraseFromParent();286}287288std::optional<InterestingMemoryAccess>289MemProfiler::isInterestingMemoryAccess(Instruction *I) const {290// Do not instrument the load fetching the dynamic shadow address.291if (DynamicShadowOffset == I)292return std::nullopt;293294InterestingMemoryAccess Access;295296if (LoadInst *LI = dyn_cast<LoadInst>(I)) {297if (!ClInstrumentReads)298return std::nullopt;299Access.IsWrite = false;300Access.AccessTy = LI->getType();301Access.Addr = LI->getPointerOperand();302} else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {303if (!ClInstrumentWrites)304return std::nullopt;305Access.IsWrite = true;306Access.AccessTy = SI->getValueOperand()->getType();307Access.Addr = SI->getPointerOperand();308} else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {309if (!ClInstrumentAtomics)310return std::nullopt;311Access.IsWrite = true;312Access.AccessTy = RMW->getValOperand()->getType();313Access.Addr = RMW->getPointerOperand();314} else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {315if (!ClInstrumentAtomics)316return std::nullopt;317Access.IsWrite = true;318Access.AccessTy = XCHG->getCompareOperand()->getType();319Access.Addr = XCHG->getPointerOperand();320} else if (auto *CI = dyn_cast<CallInst>(I)) {321auto *F = CI->getCalledFunction();322if (F && (F->getIntrinsicID() == Intrinsic::masked_load ||323F->getIntrinsicID() == Intrinsic::masked_store)) {324unsigned OpOffset = 0;325if (F->getIntrinsicID() == Intrinsic::masked_store) {326if (!ClInstrumentWrites)327return std::nullopt;328// Masked store has an initial operand for the value.329OpOffset = 1;330Access.AccessTy = CI->getArgOperand(0)->getType();331Access.IsWrite = true;332} else {333if (!ClInstrumentReads)334return std::nullopt;335Access.AccessTy = CI->getType();336Access.IsWrite = false;337}338339auto *BasePtr = CI->getOperand(0 + OpOffset);340Access.MaybeMask = CI->getOperand(2 + OpOffset);341Access.Addr = BasePtr;342}343}344345if (!Access.Addr)346return std::nullopt;347348// Do not instrument accesses from different address spaces; we cannot deal349// with them.350Type *PtrTy = cast<PointerType>(Access.Addr->getType()->getScalarType());351if (PtrTy->getPointerAddressSpace() != 0)352return std::nullopt;353354// Ignore swifterror addresses.355// swifterror memory addresses are mem2reg promoted by instruction356// selection. As such they cannot have regular uses like an instrumentation357// function and it makes no sense to track them as memory.358if (Access.Addr->isSwiftError())359return std::nullopt;360361// Peel off GEPs and BitCasts.362auto *Addr = Access.Addr->stripInBoundsOffsets();363364if (GlobalVariable *GV = dyn_cast<GlobalVariable>(Addr)) {365// Do not instrument PGO counter updates.366if (GV->hasSection()) {367StringRef SectionName = GV->getSection();368// Check if the global is in the PGO counters section.369auto OF = I->getModule()->getTargetTriple().getObjectFormat();370if (SectionName.ends_with(371getInstrProfSectionName(IPSK_cnts, OF, /*AddSegmentInfo=*/false)))372return std::nullopt;373}374375// Do not instrument accesses to LLVM internal variables.376if (GV->getName().starts_with("__llvm"))377return std::nullopt;378}379380return Access;381}382383void MemProfiler::instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask,384Instruction *I, Value *Addr,385Type *AccessTy, bool IsWrite) {386auto *VTy = cast<FixedVectorType>(AccessTy);387unsigned Num = VTy->getNumElements();388auto *Zero = ConstantInt::get(IntptrTy, 0);389for (unsigned Idx = 0; Idx < Num; ++Idx) {390Value *InstrumentedAddress = nullptr;391Instruction *InsertBefore = I;392if (auto *Vector = dyn_cast<ConstantVector>(Mask)) {393// dyn_cast as we might get UndefValue394if (auto *Masked = dyn_cast<ConstantInt>(Vector->getOperand(Idx))) {395if (Masked->isZero())396// Mask is constant false, so no instrumentation needed.397continue;398// If we have a true or undef value, fall through to instrumentAddress.399// with InsertBefore == I400}401} else {402IRBuilder<> IRB(I);403Value *MaskElem = IRB.CreateExtractElement(Mask, Idx);404Instruction *ThenTerm = SplitBlockAndInsertIfThen(MaskElem, I, false);405InsertBefore = ThenTerm;406}407408IRBuilder<> IRB(InsertBefore);409InstrumentedAddress =410IRB.CreateGEP(VTy, Addr, {Zero, ConstantInt::get(IntptrTy, Idx)});411instrumentAddress(I, InsertBefore, InstrumentedAddress, IsWrite);412}413}414415void MemProfiler::instrumentMop(Instruction *I, const DataLayout &DL,416InterestingMemoryAccess &Access) {417// Skip instrumentation of stack accesses unless requested.418if (!ClStack && isa<AllocaInst>(getUnderlyingObject(Access.Addr))) {419if (Access.IsWrite)420++NumSkippedStackWrites;421else422++NumSkippedStackReads;423return;424}425426if (Access.IsWrite)427NumInstrumentedWrites++;428else429NumInstrumentedReads++;430431if (Access.MaybeMask) {432instrumentMaskedLoadOrStore(DL, Access.MaybeMask, I, Access.Addr,433Access.AccessTy, Access.IsWrite);434} else {435// Since the access counts will be accumulated across the entire allocation,436// we only update the shadow access count for the first location and thus437// don't need to worry about alignment and type size.438instrumentAddress(I, I, Access.Addr, Access.IsWrite);439}440}441442void MemProfiler::instrumentAddress(Instruction *OrigIns,443Instruction *InsertBefore, Value *Addr,444bool IsWrite) {445IRBuilder<> IRB(InsertBefore);446Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy);447448if (ClUseCalls) {449IRB.CreateCall(MemProfMemoryAccessCallback[IsWrite], AddrLong);450return;451}452453Type *ShadowTy = ClHistogram ? Type::getInt8Ty(*C) : Type::getInt64Ty(*C);454Type *ShadowPtrTy = PointerType::get(*C, 0);455456Value *ShadowPtr = memToShadow(AddrLong, IRB);457Value *ShadowAddr = IRB.CreateIntToPtr(ShadowPtr, ShadowPtrTy);458Value *ShadowValue = IRB.CreateLoad(ShadowTy, ShadowAddr);459// If we are profiling with histograms, add overflow protection at 255.460if (ClHistogram) {461Value *MaxCount = ConstantInt::get(Type::getInt8Ty(*C), 255);462Value *Cmp = IRB.CreateICmpULT(ShadowValue, MaxCount);463Instruction *IncBlock =464SplitBlockAndInsertIfThen(Cmp, InsertBefore, /*Unreachable=*/false);465IRB.SetInsertPoint(IncBlock);466}467Value *Inc = ConstantInt::get(ShadowTy, 1);468ShadowValue = IRB.CreateAdd(ShadowValue, Inc);469IRB.CreateStore(ShadowValue, ShadowAddr);470}471472// Create the variable for the profile file name.473void createProfileFileNameVar(Module &M) {474const MDString *MemProfFilename =475dyn_cast_or_null<MDString>(M.getModuleFlag("MemProfProfileFilename"));476if (!MemProfFilename)477return;478assert(!MemProfFilename->getString().empty() &&479"Unexpected MemProfProfileFilename metadata with empty string");480Constant *ProfileNameConst = ConstantDataArray::getString(481M.getContext(), MemProfFilename->getString(), true);482GlobalVariable *ProfileNameVar = new GlobalVariable(483M, ProfileNameConst->getType(), /*isConstant=*/true,484GlobalValue::WeakAnyLinkage, ProfileNameConst, MemProfFilenameVar);485const Triple &TT = M.getTargetTriple();486if (TT.supportsCOMDAT()) {487ProfileNameVar->setLinkage(GlobalValue::ExternalLinkage);488ProfileNameVar->setComdat(M.getOrInsertComdat(MemProfFilenameVar));489}490}491492// Set MemprofHistogramFlag as a Global veriable in IR. This makes it accessible493// to the runtime, changing shadow count behavior.494void createMemprofHistogramFlagVar(Module &M) {495const StringRef VarName(MemProfHistogramFlagVar);496Type *IntTy1 = Type::getInt1Ty(M.getContext());497auto MemprofHistogramFlag = new GlobalVariable(498M, IntTy1, true, GlobalValue::WeakAnyLinkage,499Constant::getIntegerValue(IntTy1, APInt(1, ClHistogram)), VarName);500const Triple &TT = M.getTargetTriple();501if (TT.supportsCOMDAT()) {502MemprofHistogramFlag->setLinkage(GlobalValue::ExternalLinkage);503MemprofHistogramFlag->setComdat(M.getOrInsertComdat(VarName));504}505appendToCompilerUsed(M, MemprofHistogramFlag);506}507508void createMemprofDefaultOptionsVar(Module &M) {509Constant *OptionsConst = ConstantDataArray::getString(510M.getContext(), MemprofRuntimeDefaultOptions, /*AddNull=*/true);511GlobalVariable *OptionsVar =512new GlobalVariable(M, OptionsConst->getType(), /*isConstant=*/true,513GlobalValue::WeakAnyLinkage, OptionsConst,514memprof::getMemprofOptionsSymbolName());515const Triple &TT = M.getTargetTriple();516if (TT.supportsCOMDAT()) {517OptionsVar->setLinkage(GlobalValue::ExternalLinkage);518OptionsVar->setComdat(M.getOrInsertComdat(OptionsVar->getName()));519}520}521522bool ModuleMemProfiler::instrumentModule(Module &M) {523524// Create a module constructor.525std::string MemProfVersion = std::to_string(LLVM_MEM_PROFILER_VERSION);526std::string VersionCheckName =527ClInsertVersionCheck ? (MemProfVersionCheckNamePrefix + MemProfVersion)528: "";529std::tie(MemProfCtorFunction, std::ignore) =530createSanitizerCtorAndInitFunctions(M, MemProfModuleCtorName,531MemProfInitName, /*InitArgTypes=*/{},532/*InitArgs=*/{}, VersionCheckName);533534const uint64_t Priority = getCtorAndDtorPriority(TargetTriple);535appendToGlobalCtors(M, MemProfCtorFunction, Priority);536537createProfileFileNameVar(M);538539createMemprofHistogramFlagVar(M);540541createMemprofDefaultOptionsVar(M);542543return true;544}545546void MemProfiler::initializeCallbacks(Module &M) {547IRBuilder<> IRB(*C);548549for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) {550const std::string TypeStr = AccessIsWrite ? "store" : "load";551const std::string HistPrefix = ClHistogram ? "hist_" : "";552553SmallVector<Type *, 2> Args1{1, IntptrTy};554MemProfMemoryAccessCallback[AccessIsWrite] = M.getOrInsertFunction(555ClMemoryAccessCallbackPrefix + HistPrefix + TypeStr,556FunctionType::get(IRB.getVoidTy(), Args1, false));557}558MemProfMemmove = M.getOrInsertFunction(559ClMemoryAccessCallbackPrefix + "memmove", PtrTy, PtrTy, PtrTy, IntptrTy);560MemProfMemcpy = M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + "memcpy",561PtrTy, PtrTy, PtrTy, IntptrTy);562MemProfMemset =563M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + "memset", PtrTy,564PtrTy, IRB.getInt32Ty(), IntptrTy);565}566567bool MemProfiler::maybeInsertMemProfInitAtFunctionEntry(Function &F) {568// For each NSObject descendant having a +load method, this method is invoked569// by the ObjC runtime before any of the static constructors is called.570// Therefore we need to instrument such methods with a call to __memprof_init571// at the beginning in order to initialize our runtime before any access to572// the shadow memory.573// We cannot just ignore these methods, because they may call other574// instrumented functions.575if (F.getName().contains(" load]")) {576FunctionCallee MemProfInitFunction =577declareSanitizerInitFunction(*F.getParent(), MemProfInitName, {});578IRBuilder<> IRB(&F.front(), F.front().begin());579IRB.CreateCall(MemProfInitFunction, {});580return true;581}582return false;583}584585bool MemProfiler::insertDynamicShadowAtFunctionEntry(Function &F) {586IRBuilder<> IRB(&F.front().front());587Value *GlobalDynamicAddress = F.getParent()->getOrInsertGlobal(588MemProfShadowMemoryDynamicAddress, IntptrTy);589if (F.getParent()->getPICLevel() == PICLevel::NotPIC)590cast<GlobalVariable>(GlobalDynamicAddress)->setDSOLocal(true);591DynamicShadowOffset = IRB.CreateLoad(IntptrTy, GlobalDynamicAddress);592return true;593}594595bool MemProfiler::instrumentFunction(Function &F) {596if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage)597return false;598if (ClDebugFunc == F.getName())599return false;600if (F.getName().starts_with("__memprof_"))601return false;602603bool FunctionModified = false;604605// If needed, insert __memprof_init.606// This function needs to be called even if the function body is not607// instrumented.608if (maybeInsertMemProfInitAtFunctionEntry(F))609FunctionModified = true;610611LLVM_DEBUG(dbgs() << "MEMPROF instrumenting:\n" << F << "\n");612613initializeCallbacks(*F.getParent());614615SmallVector<Instruction *, 16> ToInstrument;616617// Fill the set of memory operations to instrument.618for (auto &BB : F) {619for (auto &Inst : BB) {620if (isInterestingMemoryAccess(&Inst) || isa<MemIntrinsic>(Inst))621ToInstrument.push_back(&Inst);622}623}624625if (ToInstrument.empty()) {626LLVM_DEBUG(dbgs() << "MEMPROF done instrumenting: " << FunctionModified627<< " " << F << "\n");628629return FunctionModified;630}631632FunctionModified |= insertDynamicShadowAtFunctionEntry(F);633634int NumInstrumented = 0;635for (auto *Inst : ToInstrument) {636if (ClDebugMin < 0 || ClDebugMax < 0 ||637(NumInstrumented >= ClDebugMin && NumInstrumented <= ClDebugMax)) {638std::optional<InterestingMemoryAccess> Access =639isInterestingMemoryAccess(Inst);640if (Access)641instrumentMop(Inst, F.getDataLayout(), *Access);642else643instrumentMemIntrinsic(cast<MemIntrinsic>(Inst));644}645NumInstrumented++;646}647648if (NumInstrumented > 0)649FunctionModified = true;650651LLVM_DEBUG(dbgs() << "MEMPROF done instrumenting: " << FunctionModified << " "652<< F << "\n");653654return FunctionModified;655}656657658