// 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.
+/// Return true if this is a call to an allocation function that does not have
+/// side effects that 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);
+bool isRemovableAlloc(const CallBase *V, const TargetLibraryInfo *TLI);
/// Gets the alignment argument for an aligned_alloc-like function, using either
/// built-in knowledge based on fuction names/signatures or allocalign
return getAllocationDataForFunction(F, ReallocLike, TLI).has_value();
}
-bool llvm::isAllocRemovable(const CallBase *CB, const TargetLibraryInfo *TLI) {
- assert(isAllocationFn(CB, TLI));
-
+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);
}
// To do heap to stack, we need to know that the allocation itself is
// removable once uses are rewritten, and that we can initialize the
// alloca to the same pattern as the original allocation result.
- if (isAllocationFn(CB, TLI) && isAllocRemovable(CB, TLI)) {
+ if (isRemovableAlloc(CB, TLI)) {
auto *I8Ty = Type::getInt8Ty(CB->getParent()->getContext());
if (nullptr != getInitialValueOfAllocation(CB, TLI, I8Ty)) {
AllocationInfo *AI = new (A.Allocator) AllocationInfo{CB};
CallInst *CI,
const DataLayout &DL,
TargetLibraryInfo *TLI) {
- if (!isAllocRemovable(CI, TLI))
+ if (!isRemovableAlloc(CI, TLI))
// Must be able to remove the call when we get done..
return false;
Call, Builder.CreateBitOrPointerCast(ReturnedArg, CallTy));
}
- if (isAllocationFn(&Call, &TLI) &&
- isAllocRemovable(&cast<CallBase>(Call), &TLI))
+ if (isRemovableAlloc(&Call, &TLI))
return visitAllocSite(Call);
// Handle intrinsics which can be used in both call and invoke context.
}
Instruction *InstCombinerImpl::visitAllocSite(Instruction &MI) {
- assert(isa<AllocaInst>(MI) || isAllocRemovable(&cast<CallBase>(MI), &TLI));
+ assert(isa<AllocaInst>(MI) || isRemovableAlloc(&cast<CallBase>(MI), &TLI));
// 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
return true;
}
- if (isAllocationFn(I, TLI) && isAllocRemovable(cast<CallBase>(I), TLI))
- return true;
+ if (auto *CB = dyn_cast<CallBase>(I))
+ if (isRemovableAlloc(CB, TLI))
+ return true;
if (!I->willReturn())
return false;