forked from OSchip/llvm-project
Extract utility function for checking initial value of allocation [NFC, try 2]
This is a reoccuring pattern, we can consolidate three copies into one. The main motivation is to reduce usages of isMallocLike. The original commit (which was quickly reverted) didn't account for the allocation function could be an invoke, test coverage for that case added in this commit.
This commit is contained in:
parent
089b910abc
commit
6b0ff0969d
|
@ -115,6 +115,16 @@ inline CallInst *isFreeCall(Value *I, const TargetLibraryInfo *TLI) {
|
|||
return const_cast<CallInst*>(isFreeCall((const Value*)I, TLI));
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Properties of allocation functions
|
||||
//
|
||||
|
||||
/// If this allocation function initializes memory to a fixed value, return
|
||||
/// said value in the requested type. Otherwise, return nullptr.
|
||||
Constant *getInitialValueOfAllocation(const CallBase *Alloc,
|
||||
const TargetLibraryInfo *TLI,
|
||||
Type *Ty);
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Utility functions to compute size of objects.
|
||||
//
|
||||
|
|
|
@ -312,6 +312,22 @@ bool llvm::isStrdupLikeFn(const Value *V, const TargetLibraryInfo *TLI) {
|
|||
return getAllocationData(V, StrDupLike, TLI).hasValue();
|
||||
}
|
||||
|
||||
Constant *llvm::getInitialValueOfAllocation(const CallBase *Alloc,
|
||||
const TargetLibraryInfo *TLI,
|
||||
Type *Ty) {
|
||||
assert(isAllocationFn(Alloc, TLI));
|
||||
|
||||
// malloc and aligned_alloc are uninitialized (undef)
|
||||
if (isMallocLikeFn(Alloc, TLI) || isAlignedAllocLikeFn(Alloc, TLI))
|
||||
return UndefValue::get(Ty);
|
||||
|
||||
// calloc zero initializes
|
||||
if (isCallocLikeFn(Alloc, TLI))
|
||||
return Constant::getNullValue(Ty);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// isLibFreeFunction - Returns true if the function is a builtin free()
|
||||
bool llvm::isLibFreeFunction(const Function *F, const LibFunc TLIFn) {
|
||||
unsigned ExpectedNumParams;
|
||||
|
|
|
@ -207,13 +207,9 @@ Constant *AA::getInitialValueForObj(Value &Obj, Type &Ty,
|
|||
const TargetLibraryInfo *TLI) {
|
||||
if (isa<AllocaInst>(Obj))
|
||||
return UndefValue::get(&Ty);
|
||||
if (isNoAliasFn(&Obj, TLI)) {
|
||||
if (isMallocLikeFn(&Obj, TLI) || isAlignedAllocLikeFn(&Obj, TLI))
|
||||
return UndefValue::get(&Ty);
|
||||
if (isCallocLikeFn(&Obj, TLI))
|
||||
return Constant::getNullValue(&Ty);
|
||||
return nullptr;
|
||||
}
|
||||
if (isAllocationFn(&Obj, TLI))
|
||||
return getInitialValueOfAllocation(&cast<CallBase>(Obj), TLI, &Ty);
|
||||
|
||||
auto *GV = dyn_cast<GlobalVariable>(&Obj);
|
||||
if (!GV || !GV->hasLocalLinkage())
|
||||
return nullptr;
|
||||
|
|
|
@ -1104,20 +1104,19 @@ bool GVNPass::AnalyzeLoadAvailability(LoadInst *Load, MemDepResult DepInfo,
|
|||
}
|
||||
assert(DepInfo.isDef() && "follows from above");
|
||||
|
||||
// Loading the allocation -> undef.
|
||||
if (isa<AllocaInst>(DepInst) || isMallocLikeFn(DepInst, TLI) ||
|
||||
isAlignedAllocLikeFn(DepInst, TLI) ||
|
||||
// Loading immediately after lifetime begin -> undef.
|
||||
isLifetimeStart(DepInst)) {
|
||||
// Loading the alloca -> undef.
|
||||
// Loading immediately after lifetime begin -> undef.
|
||||
if (isa<AllocaInst>(DepInst) || isLifetimeStart(DepInst)) {
|
||||
Res = AvailableValue::get(UndefValue::get(Load->getType()));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Loading from calloc (which zero initializes memory) -> zero
|
||||
if (isCallocLikeFn(DepInst, TLI)) {
|
||||
Res = AvailableValue::get(Constant::getNullValue(Load->getType()));
|
||||
return true;
|
||||
}
|
||||
if (isAllocationFn(DepInst, TLI))
|
||||
if (auto *InitVal = getInitialValueOfAllocation(cast<CallBase>(DepInst),
|
||||
TLI, Load->getType())) {
|
||||
Res = AvailableValue::get(InitVal);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (StoreInst *S = dyn_cast<StoreInst>(DepInst)) {
|
||||
// Reject loads and stores that are to the same address but are of
|
||||
|
|
|
@ -1493,8 +1493,7 @@ NewGVN::performSymbolicLoadCoercion(Type *LoadType, Value *LoadPtr,
|
|||
// undef value. This can happen when loading for a fresh allocation with no
|
||||
// intervening stores, for example. Note that this is only true in the case
|
||||
// that the result of the allocation is pointer equal to the load ptr.
|
||||
if (isa<AllocaInst>(DepInst) || isMallocLikeFn(DepInst, TLI) ||
|
||||
isAlignedAllocLikeFn(DepInst, TLI)) {
|
||||
if (isa<AllocaInst>(DepInst)) {
|
||||
return createConstantExpression(UndefValue::get(LoadType));
|
||||
}
|
||||
// If this load occurs either right after a lifetime begin,
|
||||
|
@ -1502,12 +1501,10 @@ NewGVN::performSymbolicLoadCoercion(Type *LoadType, Value *LoadPtr,
|
|||
else if (auto *II = dyn_cast<IntrinsicInst>(DepInst)) {
|
||||
if (II->getIntrinsicID() == Intrinsic::lifetime_start)
|
||||
return createConstantExpression(UndefValue::get(LoadType));
|
||||
}
|
||||
// If this load follows a calloc (which zero initializes memory),
|
||||
// then the loaded value is zero
|
||||
else if (isCallocLikeFn(DepInst, TLI)) {
|
||||
return createConstantExpression(Constant::getNullValue(LoadType));
|
||||
}
|
||||
} else if (isAllocationFn(DepInst, TLI))
|
||||
if (auto *InitVal = getInitialValueOfAllocation(cast<CallBase>(DepInst),
|
||||
TLI, LoadType))
|
||||
return createConstantExpression(InitVal);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -22,4 +22,28 @@ define i32 @test1() {
|
|||
|
||||
}
|
||||
|
||||
define i32 @as_invoke(i1 %c) personality i32 (...)* undef {
|
||||
bb3:
|
||||
%mem = invoke noalias i8* @calloc(i64 1, i64 4)
|
||||
to label %bb4 unwind label %bb1
|
||||
|
||||
bb1:
|
||||
%lp = landingpad { i8*, i32 } cleanup
|
||||
ret i32 0
|
||||
|
||||
bb4:
|
||||
%mem.i32 = bitcast i8* %mem to i32*
|
||||
; This load is trivially constant zero
|
||||
%res = load i32, i32* %mem.i32, align 4
|
||||
ret i32 %res
|
||||
|
||||
; CHECK-LABEL: @as_invoke(
|
||||
; CHECK-NOT: %3 = load i32, i32* %2, align 4
|
||||
; CHECK: ret i32 0
|
||||
|
||||
; CHECK_NO_LIBCALLS-LABEL: @as_invoke(
|
||||
; CHECK_NO_LIBCALLS: load
|
||||
; CHECK_NO_LIBCALLS: ret i32 %
|
||||
}
|
||||
|
||||
declare noalias i8* @calloc(i64, i64)
|
||||
|
|
Loading…
Reference in New Issue