diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-04-14 21:41:27 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-06-22 18:20:56 +0000 |
commit | bdd1243df58e60e85101c09001d9812a789b6bc4 (patch) | |
tree | a1ce621c7301dd47ba2ddc3b8eaa63b441389481 /contrib/llvm-project/llvm/lib/Analysis/MemoryBuiltins.cpp | |
parent | 781624ca2d054430052c828ba8d2c2eaf2d733e7 (diff) | |
parent | e3b557809604d036af6e00c60f012c2025b59a5e (diff) |
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Analysis/MemoryBuiltins.cpp')
-rw-r--r-- | contrib/llvm-project/llvm/lib/Analysis/MemoryBuiltins.cpp | 159 |
1 files changed, 64 insertions, 95 deletions
diff --git a/contrib/llvm-project/llvm/lib/Analysis/MemoryBuiltins.cpp b/contrib/llvm-project/llvm/lib/Analysis/MemoryBuiltins.cpp index 413ec6dd4b42..0edad0557369 100644 --- a/contrib/llvm-project/llvm/lib/Analysis/MemoryBuiltins.cpp +++ b/contrib/llvm-project/llvm/lib/Analysis/MemoryBuiltins.cpp @@ -13,8 +13,6 @@ #include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/ADT/APInt.h" -#include "llvm/ADT/None.h" -#include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/AliasAnalysis.h" @@ -44,6 +42,7 @@ #include <cstdint> #include <iterator> #include <numeric> +#include <optional> #include <type_traits> #include <utility> @@ -54,14 +53,10 @@ using namespace llvm; enum AllocType : uint8_t { OpNewLike = 1<<0, // allocates; never returns null MallocLike = 1<<1, // allocates; may return null - AlignedAllocLike = 1<<2, // allocates with alignment; may return null - CallocLike = 1<<3, // allocates + bzero - ReallocLike = 1<<4, // reallocates - StrDupLike = 1<<5, + StrDupLike = 1<<2, MallocOrOpNewLike = MallocLike | OpNewLike, - MallocOrCallocLike = MallocLike | OpNewLike | CallocLike | AlignedAllocLike, - AllocLike = MallocOrCallocLike | StrDupLike, - AnyAlloc = AllocLike | ReallocLike + AllocLike = MallocOrOpNewLike | StrDupLike, + AnyAlloc = AllocLike }; enum class MallocFamily { @@ -115,7 +110,6 @@ struct AllocFnsTy { // FIXME: certain users need more information. E.g., SimplifyLibCalls needs to // know which functions are nounwind, noalias, nocapture parameters, etc. static const std::pair<LibFunc, AllocFnsTy> AllocationFnData[] = { - {LibFunc_vec_malloc, {MallocLike, 1, 0, -1, -1, MallocFamily::VecMalloc}}, {LibFunc_Znwj, {OpNewLike, 1, 0, -1, -1, MallocFamily::CPPNew}}, // new(unsigned int) {LibFunc_ZnwjRKSt9nothrow_t, {MallocLike, 2, 0, -1, -1, MallocFamily::CPPNew}}, // new(unsigned int, nothrow) {LibFunc_ZnwjSt11align_val_t, {OpNewLike, 2, 0, -1, 1, MallocFamily::CPPNewAligned}}, // new(unsigned int, align_val_t) @@ -140,9 +134,6 @@ static const std::pair<LibFunc, AllocFnsTy> AllocationFnData[] = { {LibFunc_msvc_new_array_int_nothrow, {MallocLike, 2, 0, -1, -1, MallocFamily::MSVCArrayNew}}, // new[](unsigned int, nothrow) {LibFunc_msvc_new_array_longlong, {OpNewLike, 1, 0, -1, -1, MallocFamily::MSVCArrayNew}}, // new[](unsigned long long) {LibFunc_msvc_new_array_longlong_nothrow, {MallocLike, 2, 0, -1, -1, MallocFamily::MSVCArrayNew}}, // new[](unsigned long long, nothrow) - {LibFunc_memalign, {AlignedAllocLike, 2, 1, -1, 0, MallocFamily::Malloc}}, - {LibFunc_vec_calloc, {CallocLike, 2, 0, 1, -1, MallocFamily::VecMalloc}}, - {LibFunc_vec_realloc, {ReallocLike, 2, 1, -1, -1, MallocFamily::VecMalloc}}, {LibFunc_strdup, {StrDupLike, 1, -1, -1, -1, MallocFamily::Malloc}}, {LibFunc_dunder_strdup, {StrDupLike, 1, -1, -1, -1, MallocFamily::Malloc}}, {LibFunc_strndup, {StrDupLike, 2, 1, -1, -1, MallocFamily::Malloc}}, @@ -170,18 +161,18 @@ static const Function *getCalledFunction(const Value *V, /// Returns the allocation data for the given value if it's a call to a known /// allocation function. -static Optional<AllocFnsTy> +static std::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; + return std::nullopt; // Make sure that the function is available. LibFunc TLIFn; if (!TLI || !TLI->getLibFunc(*Callee, TLIFn) || !TLI->has(TLIFn)) - return None; + return std::nullopt; const auto *Iter = find_if( AllocationFnData, [TLIFn](const std::pair<LibFunc, AllocFnsTy> &P) { @@ -189,18 +180,18 @@ getAllocationDataForFunction(const Function *Callee, AllocType AllocTy, }); if (Iter == std::end(AllocationFnData)) - return None; + return std::nullopt; const AllocFnsTy *FnData = &Iter->second; if ((FnData->AllocTy & AllocTy) != FnData->AllocTy) - return None; + return std::nullopt; // Check function prototype. int FstParam = FnData->FstParam; int SndParam = FnData->SndParam; FunctionType *FTy = Callee->getFunctionType(); - if (FTy->getReturnType() == Type::getInt8PtrTy(FTy->getContext()) && + if (FTy->getReturnType()->isPointerTy() && FTy->getNumParams() == FnData->NumParams && (FstParam < 0 || (FTy->getParamType(FstParam)->isIntegerTy(32) || @@ -209,19 +200,20 @@ getAllocationDataForFunction(const Function *Callee, AllocType AllocTy, FTy->getParamType(SndParam)->isIntegerTy(32) || FTy->getParamType(SndParam)->isIntegerTy(64))) return *FnData; - return None; + return std::nullopt; } -static Optional<AllocFnsTy> getAllocationData(const Value *V, AllocType AllocTy, - const TargetLibraryInfo *TLI) { +static std::optional<AllocFnsTy> +getAllocationData(const Value *V, AllocType AllocTy, + const TargetLibraryInfo *TLI) { bool IsNoBuiltinCall; if (const Function *Callee = getCalledFunction(V, IsNoBuiltinCall)) if (!IsNoBuiltinCall) return getAllocationDataForFunction(Callee, AllocTy, TLI); - return None; + return std::nullopt; } -static Optional<AllocFnsTy> +static std::optional<AllocFnsTy> getAllocationData(const Value *V, AllocType AllocTy, function_ref<const TargetLibraryInfo &(Function &)> GetTLI) { bool IsNoBuiltinCall; @@ -229,29 +221,29 @@ getAllocationData(const Value *V, AllocType AllocTy, if (!IsNoBuiltinCall) return getAllocationDataForFunction( Callee, AllocTy, &GetTLI(const_cast<Function &>(*Callee))); - return None; + return std::nullopt; } -static Optional<AllocFnsTy> getAllocationSize(const Value *V, - const TargetLibraryInfo *TLI) { +static std::optional<AllocFnsTy> +getAllocationSize(const Value *V, const TargetLibraryInfo *TLI) { bool IsNoBuiltinCall; const Function *Callee = getCalledFunction(V, IsNoBuiltinCall); if (!Callee) - return None; + return std::nullopt; // Prefer to use existing information over allocsize. This will give us an // accurate AllocTy. if (!IsNoBuiltinCall) - if (Optional<AllocFnsTy> Data = + if (std::optional<AllocFnsTy> Data = getAllocationDataForFunction(Callee, AnyAlloc, TLI)) return Data; Attribute Attr = Callee->getFnAttribute(Attribute::AllocSize); if (Attr == Attribute()) - return None; + return std::nullopt; - std::pair<unsigned, Optional<unsigned>> Args = Attr.getAllocSizeArgs(); + std::pair<unsigned, std::optional<unsigned>> Args = Attr.getAllocSizeArgs(); AllocFnsTy Result; // Because allocsize only tells us how many bytes are allocated, we're not @@ -304,27 +296,16 @@ bool llvm::isAllocationFn( } /// Tests if a value is a call or invoke to a library function that -/// allocates uninitialized memory (such as malloc). -static bool isMallocLikeFn(const Value *V, const TargetLibraryInfo *TLI) { - return getAllocationData(V, MallocOrOpNewLike, TLI).has_value(); -} - -/// Tests if a value is a call or invoke to a library function that -/// allocates uninitialized memory with alignment (such as aligned_alloc). -static bool isAlignedAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI) { - return getAllocationData(V, AlignedAllocLike, TLI).has_value(); -} - -/// Tests if a value is a call or invoke to a library function that -/// allocates zero-filled memory (such as calloc). -static bool isCallocLikeFn(const Value *V, const TargetLibraryInfo *TLI) { - return getAllocationData(V, CallocLike, TLI).has_value(); +/// allocates memory via new. +bool llvm::isNewLikeFn(const Value *V, const TargetLibraryInfo *TLI) { + return getAllocationData(V, OpNewLike, TLI).has_value(); } /// Tests if a value is a call or invoke to a library function that /// allocates memory similar to malloc or calloc. bool llvm::isMallocOrCallocLikeFn(const Value *V, const TargetLibraryInfo *TLI) { - return getAllocationData(V, MallocOrCallocLike, TLI).has_value(); + // TODO: Function behavior does not match name. + return getAllocationData(V, MallocOrOpNewLike, TLI).has_value(); } /// Tests if a value is a call or invoke to a library function that @@ -336,17 +317,11 @@ bool llvm::isAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI) { /// 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() || - checkFnAllocKind(F, AllocFnKind::Realloc); +bool llvm::isReallocLikeFn(const Function *F) { + return checkFnAllocKind(F, AllocFnKind::Realloc); } -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); - } +Value *llvm::getReallocatedOperand(const CallBase *CB) { if (checkFnAllocKind(CB, AllocFnKind::Realloc)) return CB->getArgOperandWithAttribute(Attribute::AllocatedPointer); return nullptr; @@ -365,7 +340,7 @@ bool llvm::isRemovableAlloc(const CallBase *CB, const TargetLibraryInfo *TLI) { Value *llvm::getAllocAlignment(const CallBase *V, const TargetLibraryInfo *TLI) { - const Optional<AllocFnsTy> FnData = getAllocationData(V, AnyAlloc, TLI); + const std::optional<AllocFnsTy> FnData = getAllocationData(V, AnyAlloc, TLI); if (FnData && FnData->AlignParam >= 0) { return V->getOperand(FnData->AlignParam); } @@ -388,14 +363,14 @@ static bool CheckedZextOrTrunc(APInt &I, unsigned IntTyBits) { return true; } -Optional<APInt> +std::optional<APInt> 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); + std::optional<AllocFnsTy> FnData = getAllocationSize(CB, TLI); if (!FnData) - return None; + return std::nullopt; // Get the index type for this address space, results and intermediate // computations are performed at that width. @@ -406,14 +381,14 @@ llvm::getAllocSize(const CallBase *CB, const TargetLibraryInfo *TLI, if (FnData->AllocTy == StrDupLike) { APInt Size(IntTyBits, GetStringLength(Mapper(CB->getArgOperand(0)))); if (!Size) - return None; + return std::nullopt; // Strndup limits strlen. if (FnData->FstParam > 0) { const ConstantInt *Arg = dyn_cast<ConstantInt>(Mapper(CB->getArgOperand(FnData->FstParam))); if (!Arg) - return None; + return std::nullopt; APInt MaxSize = Arg->getValue().zext(IntTyBits); if (Size.ugt(MaxSize)) @@ -425,11 +400,11 @@ llvm::getAllocSize(const CallBase *CB, const TargetLibraryInfo *TLI, const ConstantInt *Arg = dyn_cast<ConstantInt>(Mapper(CB->getArgOperand(FnData->FstParam))); if (!Arg) - return None; + return std::nullopt; APInt Size = Arg->getValue(); if (!CheckedZextOrTrunc(Size, IntTyBits)) - return None; + return std::nullopt; // Size is determined by just 1 parameter. if (FnData->SndParam < 0) @@ -437,16 +412,16 @@ llvm::getAllocSize(const CallBase *CB, const TargetLibraryInfo *TLI, Arg = dyn_cast<ConstantInt>(Mapper(CB->getArgOperand(FnData->SndParam))); if (!Arg) - return None; + return std::nullopt; APInt NumElems = Arg->getValue(); if (!CheckedZextOrTrunc(NumElems, IntTyBits)) - return None; + return std::nullopt; bool Overflow; Size = Size.umul_ov(NumElems, Overflow); if (Overflow) - return None; + return std::nullopt; return Size; } @@ -457,14 +432,10 @@ Constant *llvm::getInitialValueOfAllocation(const Value *V, if (!Alloc) return nullptr; - // malloc and aligned_alloc are uninitialized (undef) - if (isMallocLikeFn(Alloc, TLI) || isAlignedAllocLikeFn(Alloc, TLI)) + // malloc are uninitialized (undef) + if (getAllocationData(Alloc, MallocOrOpNewLike, TLI).has_value()) return UndefValue::get(Ty); - // calloc zero initializes - if (isCallocLikeFn(Alloc, TLI)) - return Constant::getNullValue(Ty); - AllocFnKind AK = getAllocFnKind(Alloc); if ((AK & AllocFnKind::Uninitialized) != AllocFnKind::Unknown) return UndefValue::get(Ty); @@ -482,7 +453,6 @@ struct FreeFnsTy { // clang-format off static const std::pair<LibFunc, FreeFnsTy> FreeFnData[] = { - {LibFunc_vec_free, {1, MallocFamily::VecMalloc}}, {LibFunc_ZdlPv, {1, MallocFamily::CPPNew}}, // operator delete(void*) {LibFunc_ZdaPv, {1, MallocFamily::CPPNewArray}}, // operator delete[](void*) {LibFunc_msvc_delete_ptr32, {1, MallocFamily::MSVCNew}}, // operator delete(void*) @@ -515,33 +485,33 @@ static const std::pair<LibFunc, FreeFnsTy> FreeFnData[] = { }; // clang-format on -Optional<FreeFnsTy> getFreeFunctionDataForFunction(const Function *Callee, - const LibFunc TLIFn) { +std::optional<FreeFnsTy> getFreeFunctionDataForFunction(const Function *Callee, + const LibFunc TLIFn) { const auto *Iter = find_if(FreeFnData, [TLIFn](const std::pair<LibFunc, FreeFnsTy> &P) { return P.first == TLIFn; }); if (Iter == std::end(FreeFnData)) - return None; + return std::nullopt; return Iter->second; } -Optional<StringRef> llvm::getAllocationFamily(const Value *I, - const TargetLibraryInfo *TLI) { +std::optional<StringRef> +llvm::getAllocationFamily(const Value *I, const TargetLibraryInfo *TLI) { bool IsNoBuiltin; const Function *Callee = getCalledFunction(I, IsNoBuiltin); if (Callee == nullptr || IsNoBuiltin) - return None; + return std::nullopt; LibFunc TLIFn; 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); + return mangledNameForMallocFamily(AllocData->Family); const auto FreeData = getFreeFunctionDataForFunction(Callee, TLIFn); if (FreeData) - return mangledNameForMallocFamily(FreeData.value().Family); + return mangledNameForMallocFamily(FreeData->Family); } // Callee isn't a known library function, still check attributes. if (checkFnAllocKind(I, AllocFnKind::Free | AllocFnKind::Alloc | @@ -550,12 +520,12 @@ Optional<StringRef> llvm::getAllocationFamily(const Value *I, if (Attr.isValid()) return Attr.getValueAsString(); } - return None; + return std::nullopt; } /// isLibFreeFunction - Returns true if the function is a builtin free() bool llvm::isLibFreeFunction(const Function *F, const LibFunc TLIFn) { - Optional<FreeFnsTy> FnData = getFreeFunctionDataForFunction(F, TLIFn); + std::optional<FreeFnsTy> FnData = getFreeFunctionDataForFunction(F, TLIFn); if (!FnData) return checkFnAllocKind(F, AllocFnKind::Free); @@ -567,7 +537,7 @@ bool llvm::isLibFreeFunction(const Function *F, const LibFunc TLIFn) { return false; if (FTy->getNumParams() != FnData->NumParams) return false; - if (FTy->getParamType(0) != Type::getInt8PtrTy(F->getContext())) + if (!FTy->getParamType(0)->isPointerTy()) return false; return true; @@ -641,7 +611,7 @@ Value *llvm::lowerObjectSizeCall(IntrinsicInst *ObjectSize, EvalOptions.EvalMode = MaxVal ? ObjectSizeOpts::Mode::Max : ObjectSizeOpts::Mode::Min; else - EvalOptions.EvalMode = ObjectSizeOpts::Mode::Exact; + EvalOptions.EvalMode = ObjectSizeOpts::Mode::ExactSizeFromOffset; EvalOptions.NullIsUnknownSize = cast<ConstantInt>(ObjectSize->getArgOperand(2))->isOne(); @@ -777,13 +747,10 @@ bool ObjectSizeOffsetVisitor::CheckedZextOrTrunc(APInt &I) { } SizeOffsetType ObjectSizeOffsetVisitor::visitAllocaInst(AllocaInst &I) { - if (!I.getAllocatedType()->isSized()) - return unknown(); - TypeSize ElemSize = DL.getTypeAllocSize(I.getAllocatedType()); if (ElemSize.isScalable() && Options.EvalMode != ObjectSizeOpts::Mode::Min) return unknown(); - APInt Size(IntTyBits, ElemSize.getKnownMinSize()); + APInt Size(IntTyBits, ElemSize.getKnownMinValue()); if (!I.isArrayAllocation()) return std::make_pair(align(Size, I.getAlign()), Zero); @@ -814,7 +781,7 @@ SizeOffsetType ObjectSizeOffsetVisitor::visitArgument(Argument &A) { } SizeOffsetType ObjectSizeOffsetVisitor::visitCallBase(CallBase &CB) { - if (Optional<APInt> Size = getAllocSize(&CB, TLI)) + if (std::optional<APInt> Size = getAllocSize(&CB, TLI)) return std::make_pair(*Size, Zero); return unknown(); } @@ -937,7 +904,7 @@ SizeOffsetType ObjectSizeOffsetVisitor::findLoadSizeOffset( // Is the error status of posix_memalign correctly checked? If not it // would be incorrect to assume it succeeds and load doesn't see the // previous value. - Optional<bool> Checked = isImpliedByDomCondition( + std::optional<bool> Checked = isImpliedByDomCondition( ICmpInst::ICMP_EQ, CB, ConstantInt::get(CB->getType(), 0), &Load, DL); if (!Checked || !*Checked) return Unknown(); @@ -999,9 +966,11 @@ SizeOffsetType ObjectSizeOffsetVisitor::combineSizeOffset(SizeOffsetType LHS, return (getSizeWithOverflow(LHS).slt(getSizeWithOverflow(RHS))) ? LHS : RHS; case ObjectSizeOpts::Mode::Max: return (getSizeWithOverflow(LHS).sgt(getSizeWithOverflow(RHS))) ? LHS : RHS; - case ObjectSizeOpts::Mode::Exact: + case ObjectSizeOpts::Mode::ExactSizeFromOffset: return (getSizeWithOverflow(LHS).eq(getSizeWithOverflow(RHS))) ? LHS : unknown(); + case ObjectSizeOpts::Mode::ExactUnderlyingSizeAndOffset: + return LHS == RHS && LHS.second.eq(RHS.second) ? LHS : unknown(); } llvm_unreachable("missing an eval mode"); } @@ -1144,7 +1113,7 @@ SizeOffsetEvalType ObjectSizeOffsetEvaluator::visitAllocaInst(AllocaInst &I) { } SizeOffsetEvalType ObjectSizeOffsetEvaluator::visitCallBase(CallBase &CB) { - Optional<AllocFnsTy> FnData = getAllocationSize(&CB, TLI); + std::optional<AllocFnsTy> FnData = getAllocationSize(&CB, TLI); if (!FnData) return unknown(); @@ -1181,7 +1150,7 @@ ObjectSizeOffsetEvaluator::visitGEPOperator(GEPOperator &GEP) { if (!bothKnown(PtrData)) return unknown(); - Value *Offset = EmitGEPOffset(&Builder, DL, &GEP, /*NoAssumptions=*/true); + Value *Offset = emitGEPOffset(&Builder, DL, &GEP, /*NoAssumptions=*/true); Offset = Builder.CreateAdd(PtrData.second, Offset); return std::make_pair(PtrData.first, Offset); } |