[cfe-commits] r108977 - in /cfe/trunk: lib/CodeGen/CGClass.cpp lib/CodeGen/CGExprCXX.cpp lib/CodeGen/CodeGenFunction.h test/CodeGenCXX/new.cpp
Douglas Gregor
dgregor at apple.com
Tue Jul 20 18:10:18 PDT 2010
Author: dgregor
Date: Tue Jul 20 20:10:17 2010
New Revision: 108977
URL: http://llvm.org/viewvc/llvm-project?rev=108977&view=rev
Log:
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.
Modified:
cfe/trunk/lib/CodeGen/CGClass.cpp
cfe/trunk/lib/CodeGen/CGExprCXX.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/test/CodeGenCXX/new.cpp
Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=108977&r1=108976&r2=108977&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Tue Jul 20 20:10:17 2010
@@ -873,19 +873,24 @@
/// '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 @@
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 @@
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
Modified: cfe/trunk/lib/CodeGen/CGExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprCXX.cpp?rev=108977&r1=108976&r2=108977&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprCXX.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprCXX.cpp Tue Jul 20 20:10:17 2010
@@ -423,13 +423,16 @@
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 @@
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 @@
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 @@
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 @@
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) {
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=108977&r1=108976&r2=108977&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Tue Jul 20 20:10:17 2010
@@ -1053,13 +1053,15 @@
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,
Modified: cfe/trunk/test/CodeGenCXX/new.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/new.cpp?rev=108977&r1=108976&r2=108977&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/new.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/new.cpp Tue Jul 20 20:10:17 2010
@@ -90,19 +90,53 @@
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
}
More information about the cfe-commits
mailing list