[MemoryBuiltin] Add an API for checking if an unused allocation can be removed [NFC]
Not all allocation functions are removable if unused. An example of a non-removable allocation would be a direct call to the replaceable global allocation function in C++. An example of a removable one - at least according to historical practice - would be malloc.
This commit is contained in:
parent
38b30eb2b2
commit
5265ac72c6
|
@ -114,6 +114,16 @@ inline CallInst *isFreeCall(Value *I, const TargetLibraryInfo *TLI) {
|
||||||
// Properties of allocation functions
|
// Properties of allocation functions
|
||||||
//
|
//
|
||||||
|
|
||||||
|
/// Return false if the allocation can have side effects on the program state
|
||||||
|
/// we are required to preserve beyond the effect of allocating a new object.
|
||||||
|
/// Ex: If our allocation routine has a counter for the number of objects
|
||||||
|
/// allocated, and the program prints it on exit, can the value change due
|
||||||
|
/// to optimization? Answer is highly language dependent.
|
||||||
|
/// Note: *Removable* really does mean removable; it does not mean observable.
|
||||||
|
/// A language (e.g. C++) can allow removing allocations without allowing
|
||||||
|
/// insertion or speculative execution of allocation routines.
|
||||||
|
bool isAllocRemovable(const CallBase *V, const TargetLibraryInfo *TLI);
|
||||||
|
|
||||||
/// Gets the alignment argument for an aligned_alloc-like function
|
/// Gets the alignment argument for an aligned_alloc-like function
|
||||||
Value *getAllocAlignment(const CallBase *V, const TargetLibraryInfo *TLI);
|
Value *getAllocAlignment(const CallBase *V, const TargetLibraryInfo *TLI);
|
||||||
|
|
||||||
|
|
|
@ -298,6 +298,17 @@ bool llvm::isStrdupLikeFn(const Value *V, const TargetLibraryInfo *TLI) {
|
||||||
return getAllocationData(V, StrDupLike, TLI).hasValue();
|
return getAllocationData(V, StrDupLike, TLI).hasValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool llvm::isAllocRemovable(const CallBase *CB, const TargetLibraryInfo *TLI) {
|
||||||
|
assert(isAllocationFn(CB, 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
|
||||||
|
return isAllocLikeFn(CB, TLI);
|
||||||
|
}
|
||||||
|
|
||||||
Value *llvm::getAllocAlignment(const CallBase *V,
|
Value *llvm::getAllocAlignment(const CallBase *V,
|
||||||
const TargetLibraryInfo *TLI) {
|
const TargetLibraryInfo *TLI) {
|
||||||
|
|
|
@ -2761,7 +2761,8 @@ Instruction *InstCombinerImpl::visitCallBase(CallBase &Call) {
|
||||||
Call, Builder.CreateBitOrPointerCast(ReturnedArg, CallTy));
|
Call, Builder.CreateBitOrPointerCast(ReturnedArg, CallTy));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAllocLikeFn(&Call, &TLI))
|
if (isAllocationFn(&Call, &TLI) &&
|
||||||
|
isAllocRemovable(&cast<CallBase>(Call), &TLI))
|
||||||
return visitAllocSite(Call);
|
return visitAllocSite(Call);
|
||||||
|
|
||||||
// Handle intrinsics which can be used in both call and invoke context.
|
// Handle intrinsics which can be used in both call and invoke context.
|
||||||
|
|
|
@ -2696,6 +2696,8 @@ static bool isAllocSiteRemovable(Instruction *AI,
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction *InstCombinerImpl::visitAllocSite(Instruction &MI) {
|
Instruction *InstCombinerImpl::visitAllocSite(Instruction &MI) {
|
||||||
|
assert(isa<AllocaInst>(MI) || isAllocRemovable(&cast<CallBase>(MI), &TLI));
|
||||||
|
|
||||||
// If we have a malloc call which is only used in any amount of comparisons to
|
// If we have a malloc call which is only used in any amount of comparisons to
|
||||||
// null and free calls, delete the calls and replace the comparisons with true
|
// null and free calls, delete the calls and replace the comparisons with true
|
||||||
// or false as appropriate.
|
// or false as appropriate.
|
||||||
|
|
|
@ -492,7 +492,7 @@ bool llvm::wouldInstructionBeTriviallyDead(Instruction *I,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAllocLikeFn(I, TLI))
|
if (isAllocationFn(I, TLI) && isAllocRemovable(cast<CallBase>(I), TLI))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (CallInst *CI = isFreeCall(I, TLI))
|
if (CallInst *CI = isFreeCall(I, TLI))
|
||||||
|
|
Loading…
Reference in New Issue