aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/llvm/lib/Analysis/MemoryBuiltins.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-04-14 21:41:27 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-06-22 18:20:56 +0000
commitbdd1243df58e60e85101c09001d9812a789b6bc4 (patch)
treea1ce621c7301dd47ba2ddc3b8eaa63b441389481 /contrib/llvm-project/llvm/lib/Analysis/MemoryBuiltins.cpp
parent781624ca2d054430052c828ba8d2c2eaf2d733e7 (diff)
parente3b557809604d036af6e00c60f012c2025b59a5e (diff)
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Analysis/MemoryBuiltins.cpp')
-rw-r--r--contrib/llvm-project/llvm/lib/Analysis/MemoryBuiltins.cpp159
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);
}