forked from OSchip/llvm-project
Implement zero-initialization for array new when there is an
initializer of (). Make sure to use a simple memset() when we can, or fall back to generating a loop when a simple memset will not suffice. Fixes <rdar://problem/8212208>, a regression due to my work in r107857. llvm-svn: 108977
This commit is contained in:
parent
a0e7f0c1b1
commit
05fc5be32f
|
@ -873,19 +873,24 @@ void CodeGenFunction::EmitDtorEpilogue(const CXXDestructorDecl *DD,
|
|||
/// 'D' is the default constructor for elements of the array, 'ArrayTy' is the
|
||||
/// array type and 'ArrayPtr' points to the beginning fo the array.
|
||||
/// It is assumed that all relevant checks have been made by the caller.
|
||||
///
|
||||
/// \param ZeroInitialization True if each element should be zero-initialized
|
||||
/// before it is constructed.
|
||||
void
|
||||
CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
|
||||
const ConstantArrayType *ArrayTy,
|
||||
llvm::Value *ArrayPtr,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
CallExpr::const_arg_iterator ArgEnd) {
|
||||
const ConstantArrayType *ArrayTy,
|
||||
llvm::Value *ArrayPtr,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
CallExpr::const_arg_iterator ArgEnd,
|
||||
bool ZeroInitialization) {
|
||||
|
||||
const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
|
||||
llvm::Value * NumElements =
|
||||
llvm::ConstantInt::get(SizeTy,
|
||||
getContext().getConstantArrayElementCount(ArrayTy));
|
||||
|
||||
EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr, ArgBeg, ArgEnd);
|
||||
EmitCXXAggrConstructorCall(D, NumElements, ArrayPtr, ArgBeg, ArgEnd,
|
||||
ZeroInitialization);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -893,7 +898,8 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
|
|||
llvm::Value *NumElements,
|
||||
llvm::Value *ArrayPtr,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
CallExpr::const_arg_iterator ArgEnd) {
|
||||
CallExpr::const_arg_iterator ArgEnd,
|
||||
bool ZeroInitialization) {
|
||||
const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
|
||||
|
||||
// Create a temporary for the loop index and initialize it with 0.
|
||||
|
@ -924,6 +930,11 @@ CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
|
|||
llvm::Value *Address = Builder.CreateInBoundsGEP(ArrayPtr, Counter,
|
||||
"arrayidx");
|
||||
|
||||
// Zero initialize the storage, if requested.
|
||||
if (ZeroInitialization)
|
||||
EmitNullInitialization(Address,
|
||||
getContext().getTypeDeclType(D->getParent()));
|
||||
|
||||
// C++ [class.temporary]p4:
|
||||
// There are two contexts in which temporaries are destroyed at a different
|
||||
// point than the end of the full-expression. The first context is when a
|
||||
|
|
|
@ -423,13 +423,16 @@ static CharUnits CalculateCookiePadding(ASTContext &Ctx, const CXXNewExpr *E) {
|
|||
static llvm::Value *EmitCXXNewAllocSize(ASTContext &Context,
|
||||
CodeGenFunction &CGF,
|
||||
const CXXNewExpr *E,
|
||||
llvm::Value *&NumElements) {
|
||||
llvm::Value *&NumElements,
|
||||
llvm::Value *&SizeWithoutCookie) {
|
||||
QualType Type = E->getAllocatedType();
|
||||
CharUnits TypeSize = CGF.getContext().getTypeSizeInChars(Type);
|
||||
const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
|
||||
|
||||
if (!E->isArray())
|
||||
return llvm::ConstantInt::get(SizeTy, TypeSize.getQuantity());
|
||||
if (!E->isArray()) {
|
||||
SizeWithoutCookie = llvm::ConstantInt::get(SizeTy, TypeSize.getQuantity());
|
||||
return SizeWithoutCookie;
|
||||
}
|
||||
|
||||
// Emit the array size expression.
|
||||
NumElements = CGF.EmitScalarExpr(E->getArraySize());
|
||||
|
@ -488,6 +491,7 @@ static llvm::Value *EmitCXXNewAllocSize(ASTContext &Context,
|
|||
PN->addIncoming(llvm::Constant::getAllOnesValue(V->getType()), OverflowBB);
|
||||
Size = PN;
|
||||
}
|
||||
SizeWithoutCookie = Size;
|
||||
|
||||
// Add the cookie padding if necessary.
|
||||
CharUnits CookiePadding = CalculateCookiePadding(CGF.getContext(), E);
|
||||
|
@ -571,18 +575,60 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E,
|
|||
EmitBlock(AfterFor, true);
|
||||
}
|
||||
|
||||
static void EmitZeroMemSet(CodeGenFunction &CGF, QualType T,
|
||||
llvm::Value *NewPtr, llvm::Value *Size) {
|
||||
llvm::LLVMContext &VMContext = CGF.CGM.getLLVMContext();
|
||||
const llvm::Type *BP = llvm::Type::getInt8PtrTy(VMContext);
|
||||
if (NewPtr->getType() != BP)
|
||||
NewPtr = CGF.Builder.CreateBitCast(NewPtr, BP, "tmp");
|
||||
|
||||
CGF.Builder.CreateCall5(CGF.CGM.getMemSetFn(BP, CGF.IntPtrTy), NewPtr,
|
||||
llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext)),
|
||||
Size,
|
||||
llvm::ConstantInt::get(CGF.Int32Ty,
|
||||
CGF.getContext().getTypeAlign(T)/8),
|
||||
llvm::ConstantInt::get(llvm::Type::getInt1Ty(VMContext),
|
||||
0));
|
||||
}
|
||||
|
||||
static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
|
||||
llvm::Value *NewPtr,
|
||||
llvm::Value *NumElements) {
|
||||
llvm::Value *NumElements,
|
||||
llvm::Value *AllocSizeWithoutCookie) {
|
||||
if (E->isArray()) {
|
||||
if (CXXConstructorDecl *Ctor = E->getConstructor()) {
|
||||
if (!Ctor->getParent()->hasTrivialConstructor())
|
||||
CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr,
|
||||
E->constructor_arg_begin(),
|
||||
E->constructor_arg_end());
|
||||
bool RequiresZeroInitialization = false;
|
||||
if (Ctor->getParent()->hasTrivialConstructor()) {
|
||||
// If new expression did not specify value-initialization, then there
|
||||
// is no initialization.
|
||||
if (!E->hasInitializer() || Ctor->getParent()->isEmpty())
|
||||
return;
|
||||
|
||||
if (!CGF.CGM.getTypes().ContainsPointerToDataMember(
|
||||
E->getAllocatedType())) {
|
||||
// Optimization: since zero initialization will just set the memory
|
||||
// to all zeroes, generate a single memset to do it in one shot.
|
||||
EmitZeroMemSet(CGF, E->getAllocatedType(), NewPtr,
|
||||
AllocSizeWithoutCookie);
|
||||
return;
|
||||
}
|
||||
|
||||
RequiresZeroInitialization = true;
|
||||
}
|
||||
|
||||
CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr,
|
||||
E->constructor_arg_begin(),
|
||||
E->constructor_arg_end(),
|
||||
RequiresZeroInitialization);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
} else if (E->getNumConstructorArgs() == 1 &&
|
||||
isa<ImplicitValueInitExpr>(E->getConstructorArg(0))) {
|
||||
// Optimization: since zero initialization will just set the memory
|
||||
// to all zeroes, generate a single memset to do it in one shot.
|
||||
EmitZeroMemSet(CGF, E->getAllocatedType(), NewPtr,
|
||||
AllocSizeWithoutCookie);
|
||||
return;
|
||||
} else {
|
||||
CGF.EmitNewArrayInitializer(E, NewPtr, NumElements);
|
||||
return;
|
||||
}
|
||||
|
@ -621,8 +667,10 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
|
|||
QualType SizeTy = getContext().getSizeType();
|
||||
|
||||
llvm::Value *NumElements = 0;
|
||||
llvm::Value *AllocSizeWithoutCookie = 0;
|
||||
llvm::Value *AllocSize = EmitCXXNewAllocSize(getContext(),
|
||||
*this, E, NumElements);
|
||||
*this, E, NumElements,
|
||||
AllocSizeWithoutCookie);
|
||||
|
||||
NewArgs.push_back(std::make_pair(RValue::get(AllocSize), SizeTy));
|
||||
|
||||
|
@ -714,12 +762,12 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
|
|||
NewPtr =
|
||||
Builder.CreateBitCast(NewPtr,
|
||||
ConvertType(getContext().getPointerType(AllocType)));
|
||||
EmitNewInitializer(*this, E, NewPtr, NumElements);
|
||||
EmitNewInitializer(*this, E, NewPtr, NumElements, AllocSizeWithoutCookie);
|
||||
NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType()));
|
||||
}
|
||||
else {
|
||||
NewPtr = Builder.CreateBitCast(NewPtr, ConvertType(E->getType()));
|
||||
EmitNewInitializer(*this, E, NewPtr, NumElements);
|
||||
EmitNewInitializer(*this, E, NewPtr, NumElements, AllocSizeWithoutCookie);
|
||||
}
|
||||
|
||||
if (NullCheckResult) {
|
||||
|
|
|
@ -1053,13 +1053,15 @@ public:
|
|||
const ConstantArrayType *ArrayTy,
|
||||
llvm::Value *ArrayPtr,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
CallExpr::const_arg_iterator ArgEnd);
|
||||
CallExpr::const_arg_iterator ArgEnd,
|
||||
bool ZeroInitialization = false);
|
||||
|
||||
void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
|
||||
llvm::Value *NumElements,
|
||||
llvm::Value *ArrayPtr,
|
||||
CallExpr::const_arg_iterator ArgBeg,
|
||||
CallExpr::const_arg_iterator ArgEnd);
|
||||
CallExpr::const_arg_iterator ArgEnd,
|
||||
bool ZeroInitialization = false);
|
||||
|
||||
void EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
|
||||
const ArrayType *Array,
|
||||
|
|
|
@ -90,19 +90,53 @@ A* t10() {
|
|||
return new(1, 2, 3.45, 100) A;
|
||||
}
|
||||
|
||||
// CHECK: define void @_Z3t11i
|
||||
struct B { int a; };
|
||||
void t11() {
|
||||
struct Bmemptr { int Bmemptr::* memptr; int a; };
|
||||
|
||||
void t11(int n) {
|
||||
// CHECK: call noalias i8* @_Znwm
|
||||
// CHECK: call void @llvm.memset.p0i8.i64(
|
||||
B* b = new B();
|
||||
|
||||
// CHECK: call noalias i8* @_Znam
|
||||
// CHECK: {{call void.*llvm.memset.p0i8.i64.*i8 0, i64 %}}
|
||||
B *b2 = new B[n]();
|
||||
|
||||
// CHECK: call noalias i8* @_Znam
|
||||
// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64
|
||||
// CHECK: br
|
||||
Bmemptr *b_memptr = new Bmemptr[n]();
|
||||
|
||||
// CHECK: ret void
|
||||
}
|
||||
|
||||
struct Empty { };
|
||||
|
||||
// We don't need to initialize an empty class.
|
||||
// CHECK: define void @_Z3t12v
|
||||
void t12() {
|
||||
// CHECK: define void @_Z3t12v
|
||||
// CHECK-NOT: br label
|
||||
// CHECK: ret void
|
||||
// CHECK: call noalias i8* @_Znam
|
||||
// CHECK-NOT: br
|
||||
(void)new Empty[10];
|
||||
|
||||
// CHECK: call noalias i8* @_Znam
|
||||
// CHECK-NOT: br
|
||||
(void)new Empty[10]();
|
||||
|
||||
// CHECK: ret void
|
||||
}
|
||||
|
||||
// Zero-initialization
|
||||
// CHECK: define void @_Z3t13i
|
||||
void t13(int n) {
|
||||
// CHECK: call noalias i8* @_Znwm
|
||||
// CHECK: store i32 0, i32*
|
||||
(void)new int();
|
||||
|
||||
// CHECK: call noalias i8* @_Znam
|
||||
// CHECK: {{call void.*llvm.memset.p0i8.i64.*i8 0, i64 %}}
|
||||
(void)new int[n]();
|
||||
|
||||
// CHECK-NEXT: ret void
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue