diff options
Diffstat (limited to 'llvm/lib/Analysis/MemoryBuiltins.cpp')
| -rw-r--r-- | llvm/lib/Analysis/MemoryBuiltins.cpp | 125 |
1 files changed, 90 insertions, 35 deletions
diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp index f5b121c98ec4..31e4380e4379 100644 --- a/llvm/lib/Analysis/MemoryBuiltins.cpp +++ b/llvm/lib/Analysis/MemoryBuiltins.cpp @@ -179,6 +179,11 @@ static const Function *getCalledFunction(const Value *V, static Optional<AllocFnsTy> getAllocationDataForFunction(const Function *Callee, AllocType AllocTy, const TargetLibraryInfo *TLI) { + // Don't perform a slow TLI lookup, if this function doesn't return a pointer + // and thus can't be an allocation function. + if (!Callee->getReturnType()->isPointerTy()) + return None; + // Make sure that the function is available. LibFunc TLIFn; if (!TLI || !TLI->getLibFunc(*Callee, TLIFn) || !TLI->has(TLIFn)) @@ -266,15 +271,42 @@ static Optional<AllocFnsTy> getAllocationSize(const Value *V, return Result; } +static AllocFnKind getAllocFnKind(const Value *V) { + if (const auto *CB = dyn_cast<CallBase>(V)) { + Attribute Attr = CB->getFnAttr(Attribute::AllocKind); + if (Attr.isValid()) + return AllocFnKind(Attr.getValueAsInt()); + } + return AllocFnKind::Unknown; +} + +static AllocFnKind getAllocFnKind(const Function *F) { + Attribute Attr = F->getFnAttribute(Attribute::AllocKind); + if (Attr.isValid()) + return AllocFnKind(Attr.getValueAsInt()); + return AllocFnKind::Unknown; +} + +static bool checkFnAllocKind(const Value *V, AllocFnKind Wanted) { + return (getAllocFnKind(V) & Wanted) != AllocFnKind::Unknown; +} + +static bool checkFnAllocKind(const Function *F, AllocFnKind Wanted) { + return (getAllocFnKind(F) & Wanted) != AllocFnKind::Unknown; +} + /// Tests if a value is a call or invoke to a library function that /// allocates or reallocates memory (either malloc, calloc, realloc, or strdup /// like). bool llvm::isAllocationFn(const Value *V, const TargetLibraryInfo *TLI) { - return getAllocationData(V, AnyAlloc, TLI).has_value(); + return getAllocationData(V, AnyAlloc, TLI).has_value() || + checkFnAllocKind(V, AllocFnKind::Alloc | AllocFnKind::Realloc); } bool llvm::isAllocationFn( - const Value *V, function_ref<const TargetLibraryInfo &(Function &)> GetTLI) { - return getAllocationData(V, AnyAlloc, GetTLI).has_value(); + const Value *V, + function_ref<const TargetLibraryInfo &(Function &)> GetTLI) { + return getAllocationData(V, AnyAlloc, GetTLI).has_value() || + checkFnAllocKind(V, AllocFnKind::Alloc | AllocFnKind::Realloc); } /// Tests if a value is a call or invoke to a library function that @@ -304,30 +336,36 @@ bool llvm::isMallocOrCallocLikeFn(const Value *V, const TargetLibraryInfo *TLI) /// Tests if a value is a call or invoke to a library function that /// allocates memory (either malloc, calloc, or strdup like). bool llvm::isAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI) { - return getAllocationData(V, AllocLike, TLI).has_value(); -} - -/// Tests if a value is a call or invoke to a library function that -/// reallocates memory (e.g., realloc). -bool llvm::isReallocLikeFn(const Value *V, const TargetLibraryInfo *TLI) { - return getAllocationData(V, ReallocLike, TLI).has_value(); + return getAllocationData(V, AllocLike, TLI).has_value() || + checkFnAllocKind(V, AllocFnKind::Alloc); } /// Tests if a functions is a call or invoke to a library function that /// reallocates memory (e.g., realloc). bool llvm::isReallocLikeFn(const Function *F, const TargetLibraryInfo *TLI) { - return getAllocationDataForFunction(F, ReallocLike, TLI).has_value(); + return getAllocationDataForFunction(F, ReallocLike, TLI).has_value() || + checkFnAllocKind(F, AllocFnKind::Realloc); } -bool llvm::isAllocRemovable(const CallBase *CB, const TargetLibraryInfo *TLI) { - assert(isAllocationFn(CB, TLI)); +Value *llvm::getReallocatedOperand(const CallBase *CB, + const TargetLibraryInfo *TLI) { + if (getAllocationData(CB, ReallocLike, TLI).has_value()) { + // All currently supported realloc functions reallocate the first argument. + return CB->getArgOperand(0); + } + if (checkFnAllocKind(CB, AllocFnKind::Realloc)) + return CB->getArgOperandWithAttribute(Attribute::AllocatedPointer); + return nullptr; +} +bool llvm::isRemovableAlloc(const CallBase *CB, const TargetLibraryInfo *TLI) { // Note: Removability is highly dependent on the source language. For // example, recent C++ requires direct calls to the global allocation // [basic.stc.dynamic.allocation] to be observable unless part of a new // expression [expr.new paragraph 13]. - // Historically we've treated the C family allocation routines as removable + // Historically we've treated the C family allocation routines and operator + // new as removable return isAllocLikeFn(CB, TLI); } @@ -357,9 +395,8 @@ static bool CheckedZextOrTrunc(APInt &I, unsigned IntTyBits) { } Optional<APInt> -llvm::getAllocSize(const CallBase *CB, - const TargetLibraryInfo *TLI, - std::function<const Value*(const Value*)> Mapper) { +llvm::getAllocSize(const CallBase *CB, const TargetLibraryInfo *TLI, + function_ref<const Value *(const Value *)> Mapper) { // Note: This handles both explicitly listed allocation functions and // allocsize. The code structure could stand to be cleaned up a bit. Optional<AllocFnsTy> FnData = getAllocationSize(CB, TLI); @@ -434,6 +471,12 @@ Constant *llvm::getInitialValueOfAllocation(const Value *V, if (isCallocLikeFn(Alloc, TLI)) return Constant::getNullValue(Ty); + AllocFnKind AK = getAllocFnKind(Alloc); + if ((AK & AllocFnKind::Uninitialized) != AllocFnKind::Unknown) + return UndefValue::get(Ty); + if ((AK & AllocFnKind::Zeroed) != AllocFnKind::Unknown) + return Constant::getNullValue(Ty); + return nullptr; } @@ -497,14 +540,23 @@ Optional<StringRef> llvm::getAllocationFamily(const Value *I, if (Callee == nullptr || IsNoBuiltin) return None; LibFunc TLIFn; - if (!TLI || !TLI->getLibFunc(*Callee, TLIFn) || !TLI->has(TLIFn)) - return None; - const auto AllocData = getAllocationDataForFunction(Callee, AnyAlloc, TLI); - if (AllocData) - return mangledNameForMallocFamily(AllocData.value().Family); - const auto FreeData = getFreeFunctionDataForFunction(Callee, TLIFn); - if (FreeData) - return mangledNameForMallocFamily(FreeData.value().Family); + + if (TLI && TLI->getLibFunc(*Callee, TLIFn) && TLI->has(TLIFn)) { + // Callee is some known library function. + const auto AllocData = getAllocationDataForFunction(Callee, AnyAlloc, TLI); + if (AllocData) + return mangledNameForMallocFamily(AllocData.value().Family); + const auto FreeData = getFreeFunctionDataForFunction(Callee, TLIFn); + if (FreeData) + return mangledNameForMallocFamily(FreeData.value().Family); + } + // Callee isn't a known library function, still check attributes. + if (checkFnAllocKind(I, AllocFnKind::Free | AllocFnKind::Alloc | + AllocFnKind::Realloc)) { + Attribute Attr = cast<CallBase>(I)->getFnAttr("alloc-family"); + if (Attr.isValid()) + return Attr.getValueAsString(); + } return None; } @@ -512,7 +564,7 @@ Optional<StringRef> llvm::getAllocationFamily(const Value *I, bool llvm::isLibFreeFunction(const Function *F, const LibFunc TLIFn) { Optional<FreeFnsTy> FnData = getFreeFunctionDataForFunction(F, TLIFn); if (!FnData) - return false; + return checkFnAllocKind(F, AllocFnKind::Free); // Check free prototype. // FIXME: workaround for PR5130, this will be obsolete when a nobuiltin @@ -528,20 +580,24 @@ bool llvm::isLibFreeFunction(const Function *F, const LibFunc TLIFn) { return true; } -/// isFreeCall - Returns non-null if the value is a call to the builtin free() -const CallInst *llvm::isFreeCall(const Value *I, const TargetLibraryInfo *TLI) { +Value *llvm::getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI) { bool IsNoBuiltinCall; - const Function *Callee = getCalledFunction(I, IsNoBuiltinCall); + const Function *Callee = getCalledFunction(CB, IsNoBuiltinCall); if (Callee == nullptr || IsNoBuiltinCall) return nullptr; LibFunc TLIFn; - if (!TLI || !TLI->getLibFunc(*Callee, TLIFn) || !TLI->has(TLIFn)) - return nullptr; + if (TLI && TLI->getLibFunc(*Callee, TLIFn) && TLI->has(TLIFn) && + isLibFreeFunction(Callee, TLIFn)) { + // All currently supported free functions free the first argument. + return CB->getArgOperand(0); + } - return isLibFreeFunction(Callee, TLIFn) ? dyn_cast<CallInst>(I) : nullptr; -} + if (checkFnAllocKind(CB, AllocFnKind::Free)) + return CB->getArgOperandWithAttribute(Attribute::AllocatedPointer); + return nullptr; +} //===----------------------------------------------------------------------===// // Utility functions to compute size of objects. @@ -765,8 +821,7 @@ SizeOffsetType ObjectSizeOffsetVisitor::visitArgument(Argument &A) { } SizeOffsetType ObjectSizeOffsetVisitor::visitCallBase(CallBase &CB) { - auto Mapper = [](const Value *V) { return V; }; - if (Optional<APInt> Size = getAllocSize(&CB, TLI, Mapper)) + if (Optional<APInt> Size = getAllocSize(&CB, TLI)) return std::make_pair(*Size, Zero); return unknown(); } |
