Skip to content

Commit 5265ac7

Browse files
committed
[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.
1 parent 38b30eb commit 5265ac7

File tree

5 files changed

+26
-2
lines changed

5 files changed

+26
-2
lines changed

llvm/include/llvm/Analysis/MemoryBuiltins.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,16 @@ inline CallInst *isFreeCall(Value *I, const TargetLibraryInfo *TLI) {
114114
// Properties of allocation functions
115115
//
116116

117+
/// Return false if the allocation can have side effects on the program state
118+
/// we are required to preserve beyond the effect of allocating a new object.
119+
/// Ex: If our allocation routine has a counter for the number of objects
120+
/// allocated, and the program prints it on exit, can the value change due
121+
/// to optimization? Answer is highly language dependent.
122+
/// Note: *Removable* really does mean removable; it does not mean observable.
123+
/// A language (e.g. C++) can allow removing allocations without allowing
124+
/// insertion or speculative execution of allocation routines.
125+
bool isAllocRemovable(const CallBase *V, const TargetLibraryInfo *TLI);
126+
117127
/// Gets the alignment argument for an aligned_alloc-like function
118128
Value *getAllocAlignment(const CallBase *V, const TargetLibraryInfo *TLI);
119129

llvm/lib/Analysis/MemoryBuiltins.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,17 @@ bool llvm::isStrdupLikeFn(const Value *V, const TargetLibraryInfo *TLI) {
298298
return getAllocationData(V, StrDupLike, TLI).hasValue();
299299
}
300300

301+
bool llvm::isAllocRemovable(const CallBase *CB, const TargetLibraryInfo *TLI) {
302+
assert(isAllocationFn(CB, TLI));
303+
304+
// Note: Removability is highly dependent on the source language. For
305+
// example, recent C++ requires direct calls to the global allocation
306+
// [basic.stc.dynamic.allocation] to be observable unless part of a new
307+
// expression [expr.new paragraph 13].
308+
309+
// Historically we've treated the C family allocation routines as removable
310+
return isAllocLikeFn(CB, TLI);
311+
}
301312

302313
Value *llvm::getAllocAlignment(const CallBase *V,
303314
const TargetLibraryInfo *TLI) {

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2761,7 +2761,8 @@ Instruction *InstCombinerImpl::visitCallBase(CallBase &Call) {
27612761
Call, Builder.CreateBitOrPointerCast(ReturnedArg, CallTy));
27622762
}
27632763

2764-
if (isAllocLikeFn(&Call, &TLI))
2764+
if (isAllocationFn(&Call, &TLI) &&
2765+
isAllocRemovable(&cast<CallBase>(Call), &TLI))
27652766
return visitAllocSite(Call);
27662767

27672768
// Handle intrinsics which can be used in both call and invoke context.

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2696,6 +2696,8 @@ static bool isAllocSiteRemovable(Instruction *AI,
26962696
}
26972697

26982698
Instruction *InstCombinerImpl::visitAllocSite(Instruction &MI) {
2699+
assert(isa<AllocaInst>(MI) || isAllocRemovable(&cast<CallBase>(MI), &TLI));
2700+
26992701
// If we have a malloc call which is only used in any amount of comparisons to
27002702
// null and free calls, delete the calls and replace the comparisons with true
27012703
// or false as appropriate.

llvm/lib/Transforms/Utils/Local.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ bool llvm::wouldInstructionBeTriviallyDead(Instruction *I,
492492
}
493493
}
494494

495-
if (isAllocLikeFn(I, TLI))
495+
if (isAllocationFn(I, TLI) && isAllocRemovable(cast<CallBase>(I), TLI))
496496
return true;
497497

498498
if (CallInst *CI = isFreeCall(I, TLI))

0 commit comments

Comments
 (0)