Skip to content

Commit

Permalink
MemoryBuiltins: start using properties of functions
Browse files Browse the repository at this point in the history
Prior to this change, we relied on the hard-coded list for all of the
information performed by MemoryBuiltins. With this change, we're able to
start relying on properites of functions described in attributes, which
opens the door to out-of-tree compilers being able to describe their
allocator functions to LLVM's optimizer logic without having to register
their implementation details with LLVM.

Differential Revision: https://reviews.llvm.org/D123090
  • Loading branch information
durin42 committed Jul 21, 2022
1 parent 78c09f0 commit 5a3e367
Showing 1 changed file with 52 additions and 6 deletions.
58 changes: 52 additions & 6 deletions llvm/lib/Analysis/MemoryBuiltins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,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
Expand Down Expand Up @@ -309,13 +336,15 @@ 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();
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);
}

Value *llvm::getReallocatedOperand(const CallBase *CB,
Expand All @@ -324,6 +353,8 @@ Value *llvm::getReallocatedOperand(const CallBase *CB,
// 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;
}

Expand Down Expand Up @@ -440,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;
}

Expand Down Expand Up @@ -511,14 +548,20 @@ Optional<StringRef> llvm::getAllocationFamily(const Value *I,
const auto FreeData = getFreeFunctionDataForFunction(Callee, TLIFn);
if (FreeData)
return mangledNameForMallocFamily(FreeData.value().Family);
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;
}

/// 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);
if (!FnData)
return false;
return checkFnAllocKind(F, AllocFnKind::Free);

// Check free prototype.
// FIXME: workaround for PR5130, this will be obsolete when a nobuiltin
Expand Down Expand Up @@ -547,6 +590,9 @@ Value *llvm::getFreedOperand(const CallBase *CB, const TargetLibraryInfo *TLI) {
return CB->getArgOperand(0);
}

if (checkFnAllocKind(CB, AllocFnKind::Free))
return CB->getArgOperandWithAttribute(Attribute::AllocatedPointer);

return nullptr;
}

Expand Down

0 comments on commit 5a3e367

Please sign in to comment.