forked from OSchip/llvm-project
Teach MemoryBuiltins and InstructionSimplify that operator new never returns NULL.
This is safe per C++11 18.6.1.1p3: [operator new returns] a non-null pointer to suitably aligned storage (3.7.4), or else throw a bad_alloc exception. This requirement is binding on a replacement version of this function. Brings us a tiny bit closer to eliminating more vector push_backs. llvm-svn: 191310
This commit is contained in:
parent
30d249a1b3
commit
fd4777c046
|
@ -64,6 +64,10 @@ bool isAllocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
|||
bool isReallocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
bool LookThroughBitCast = false);
|
||||
|
||||
/// \brief Tests if a value is a call or invoke to a library function that
|
||||
/// allocates memory and never returns null (such as operator new).
|
||||
bool isOperatorNewLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
bool LookThroughBitCast = false);
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// malloc Call Utility Functions.
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace llvm {
|
|||
class DataLayout;
|
||||
class StringRef;
|
||||
class MDNode;
|
||||
class TargetLibraryInfo;
|
||||
|
||||
/// ComputeMaskedBits - Determine which of the bits specified in Mask are
|
||||
/// known to be either zero or one and return them in the KnownZero/KnownOne
|
||||
|
@ -186,7 +187,7 @@ namespace llvm {
|
|||
/// isKnownNonNull - Return true if this pointer couldn't possibly be null by
|
||||
/// its definition. This returns true for allocas, non-extern-weak globals
|
||||
/// and byval arguments.
|
||||
bool isKnownNonNull(const Value *V);
|
||||
bool isKnownNonNull(const Value *V, const TargetLibraryInfo *TLI = 0);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
|
|
|
@ -1739,7 +1739,7 @@ static Constant *computePointerICmp(const DataLayout *TD,
|
|||
RHS = RHS->stripPointerCasts();
|
||||
|
||||
// A non-null pointer is not equal to a null pointer.
|
||||
if (llvm::isKnownNonNull(LHS) && isa<ConstantPointerNull>(RHS) &&
|
||||
if (llvm::isKnownNonNull(LHS, TLI) && isa<ConstantPointerNull>(RHS) &&
|
||||
(Pred == CmpInst::ICMP_EQ || Pred == CmpInst::ICMP_NE))
|
||||
return ConstantInt::get(GetCompareTy(LHS),
|
||||
!CmpInst::isTrueWhenEqual(Pred));
|
||||
|
|
|
@ -35,6 +35,7 @@ enum AllocType {
|
|||
CallocLike = 1<<1, // allocates + bzero
|
||||
ReallocLike = 1<<2, // reallocates
|
||||
StrDupLike = 1<<3,
|
||||
OpNewLike = MallocLike | (1<<4), // allocates; never returns null
|
||||
AllocLike = MallocLike | CallocLike | StrDupLike,
|
||||
AnyAlloc = MallocLike | CallocLike | ReallocLike | StrDupLike
|
||||
};
|
||||
|
@ -52,13 +53,13 @@ struct AllocFnsTy {
|
|||
static const AllocFnsTy AllocationFnData[] = {
|
||||
{LibFunc::malloc, MallocLike, 1, 0, -1},
|
||||
{LibFunc::valloc, MallocLike, 1, 0, -1},
|
||||
{LibFunc::Znwj, MallocLike, 1, 0, -1}, // new(unsigned int)
|
||||
{LibFunc::Znwj, OpNewLike, 1, 0, -1}, // new(unsigned int)
|
||||
{LibFunc::ZnwjRKSt9nothrow_t, MallocLike, 2, 0, -1}, // new(unsigned int, nothrow)
|
||||
{LibFunc::Znwm, MallocLike, 1, 0, -1}, // new(unsigned long)
|
||||
{LibFunc::Znwm, OpNewLike, 1, 0, -1}, // new(unsigned long)
|
||||
{LibFunc::ZnwmRKSt9nothrow_t, MallocLike, 2, 0, -1}, // new(unsigned long, nothrow)
|
||||
{LibFunc::Znaj, MallocLike, 1, 0, -1}, // new[](unsigned int)
|
||||
{LibFunc::Znaj, OpNewLike, 1, 0, -1}, // new[](unsigned int)
|
||||
{LibFunc::ZnajRKSt9nothrow_t, MallocLike, 2, 0, -1}, // new[](unsigned int, nothrow)
|
||||
{LibFunc::Znam, MallocLike, 1, 0, -1}, // new[](unsigned long)
|
||||
{LibFunc::Znam, OpNewLike, 1, 0, -1}, // new[](unsigned long)
|
||||
{LibFunc::ZnamRKSt9nothrow_t, MallocLike, 2, 0, -1}, // new[](unsigned long, nothrow)
|
||||
{LibFunc::posix_memalign, MallocLike, 3, 2, -1},
|
||||
{LibFunc::calloc, CallocLike, 2, 0, 1},
|
||||
|
@ -189,6 +190,13 @@ bool llvm::isReallocLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
|||
return getAllocationData(V, ReallocLike, TLI, LookThroughBitCast);
|
||||
}
|
||||
|
||||
/// \brief Tests if a value is a call or invoke to a library function that
|
||||
/// allocates memory and never returns null (such as operator new).
|
||||
bool llvm::isOperatorNewLikeFn(const Value *V, const TargetLibraryInfo *TLI,
|
||||
bool LookThroughBitCast) {
|
||||
return getAllocationData(V, OpNewLike, TLI, LookThroughBitCast);
|
||||
}
|
||||
|
||||
/// extractMallocCall - Returns the corresponding CallInst if the instruction
|
||||
/// is a malloc call. Since CallInst::CreateMalloc() only creates calls, we
|
||||
/// ignore InvokeInst here.
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/Analysis/InstructionSimplify.h"
|
||||
#include "llvm/Analysis/MemoryBuiltins.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/GlobalAlias.h"
|
||||
|
@ -2064,7 +2065,7 @@ bool llvm::isSafeToSpeculativelyExecute(const Value *V,
|
|||
|
||||
/// isKnownNonNull - Return true if we know that the specified value is never
|
||||
/// null.
|
||||
bool llvm::isKnownNonNull(const Value *V) {
|
||||
bool llvm::isKnownNonNull(const Value *V, const TargetLibraryInfo *TLI) {
|
||||
// Alloca never returns null, malloc might.
|
||||
if (isa<AllocaInst>(V)) return true;
|
||||
|
||||
|
@ -2075,5 +2076,10 @@ bool llvm::isKnownNonNull(const Value *V) {
|
|||
// Global values are not null unless extern weak.
|
||||
if (const GlobalValue *GV = dyn_cast<GlobalValue>(V))
|
||||
return !GV->hasExternalWeakLinkage();
|
||||
|
||||
// operator new never returns null.
|
||||
if (isOperatorNewLikeFn(V, TLI, /*LookThroughBitCast=*/true))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -101,3 +101,23 @@ define float @test_idempotence(float %a) {
|
|||
|
||||
ret float %r4
|
||||
}
|
||||
|
||||
define i8* @operator_new() {
|
||||
entry:
|
||||
%call = tail call noalias i8* @_Znwm(i64 8)
|
||||
%cmp = icmp eq i8* %call, null
|
||||
br i1 %cmp, label %cast.end, label %cast.notnull
|
||||
|
||||
cast.notnull: ; preds = %entry
|
||||
%add.ptr = getelementptr inbounds i8* %call, i64 4
|
||||
br label %cast.end
|
||||
|
||||
cast.end: ; preds = %cast.notnull, %entry
|
||||
%cast.result = phi i8* [ %add.ptr, %cast.notnull ], [ null, %entry ]
|
||||
ret i8* %cast.result
|
||||
|
||||
; CHECK-LABEL: @operator_new
|
||||
; CHECK: br i1 false, label %cast.end, label %cast.notnull
|
||||
}
|
||||
|
||||
declare noalias i8* @_Znwm(i64)
|
||||
|
|
Loading…
Reference in New Issue