[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