]> granicus.if.org Git - clang/commitdiff
When performing an array new of a multidimensional array with an initializer
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 11 Dec 2013 01:40:16 +0000 (01:40 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 11 Dec 2013 01:40:16 +0000 (01:40 +0000)
list, each element of the initializer list may provide more than one of the
base elements of the array. Be sure to initialize the right type and bump the
array pointer by the right amount.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@196995 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGExprCXX.cpp
test/CodeGenCXX/cxx11-initializer-array-new.cpp [new file with mode: 0644]

index d4e1e33d734c18c3c36d10c5eae1c8cce80f8224..7d5dc4c42c44492e99c14ef91af94c62ff1c9cf8 100644 (file)
@@ -720,7 +720,7 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
 
 static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const Expr *Init,
                                     QualType AllocType, llvm::Value *NewPtr) {
-
+  // FIXME: Refactor with EmitExprAsInit.
   CharUnits Alignment = CGF.getContext().getTypeAlignInChars(AllocType);
   switch (CGF.getEvaluationKind(AllocType)) {
   case TEK_Scalar:
@@ -766,10 +766,22 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E,
   QualType::DestructionKind dtorKind = elementType.isDestructedType();
   EHScopeStack::stable_iterator cleanup;
   llvm::Instruction *cleanupDominator = 0;
+
   // If the initializer is an initializer list, first do the explicit elements.
   if (const InitListExpr *ILE = dyn_cast<InitListExpr>(Init)) {
     initializerElements = ILE->getNumInits();
 
+    // If this is a multi-dimensional array new, we will initialize multiple
+    // elements with each init list element.
+    QualType AllocType = E->getAllocatedType();
+    if (const ConstantArrayType *CAT = dyn_cast_or_null<ConstantArrayType>(
+            AllocType->getAsArrayTypeUnsafe())) {
+      unsigned AS = explicitPtr->getType()->getPointerAddressSpace();
+      llvm::Type *AllocPtrTy = ConvertTypeForMem(AllocType)->getPointerTo(AS);
+      explicitPtr = Builder.CreateBitCast(explicitPtr, AllocPtrTy);
+      initializerElements *= getContext().getConstantArrayElementCount(CAT);
+    }
+
     // Enter a partial-destruction cleanup if necessary.
     if (needsEHCleanup(dtorKind)) {
       // In principle we could tell the cleanup where we are more
@@ -788,12 +800,16 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E,
       // element.  TODO: some of these stores can be trivially
       // observed to be unnecessary.
       if (endOfInit) Builder.CreateStore(explicitPtr, endOfInit);
-      StoreAnyExprIntoOneUnit(*this, ILE->getInit(i), elementType, explicitPtr);
-      explicitPtr =Builder.CreateConstGEP1_32(explicitPtr, 1, "array.exp.next");
+      StoreAnyExprIntoOneUnit(*this, ILE->getInit(i),
+                              ILE->getInit(i)->getType(), explicitPtr);
+      explicitPtr = Builder.CreateConstGEP1_32(explicitPtr, 1,
+                                               "array.exp.next");
     }
 
     // The remaining elements are filled with the array filler expression.
     Init = ILE->getArrayFiller();
+
+    explicitPtr = Builder.CreateBitCast(explicitPtr, beginPtr->getType());
   }
 
   // Create the continuation block.
diff --git a/test/CodeGenCXX/cxx11-initializer-array-new.cpp b/test/CodeGenCXX/cxx11-initializer-array-new.cpp
new file mode 100644 (file)
index 0000000..23577be
--- /dev/null
@@ -0,0 +1,106 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -std=c++11 %s -emit-llvm -o - | FileCheck %s
+
+// PR10878
+
+struct S { S(); S(int); ~S(); int n; };
+
+void *p = new S[2][3]{ { 1, 2, 3 }, { 4, 5, 6 } };
+
+// CHECK-LABEL: define
+// CHECK: %[[ALLOC:.*]] = call noalias i8* @_Znam(i64 32)
+// CHECK: %[[COOKIE:.*]] = bitcast i8* %[[ALLOC]] to i64*
+// CHECK: store i64 6, i64* %[[COOKIE]]
+// CHECK: %[[START_AS_i8:.*]] = getelementptr inbounds i8* %[[ALLOC]], i64 8
+// CHECK: %[[START_AS_S:.*]] = bitcast i8* %[[START_AS_i8]] to %[[S:.*]]*
+//
+// Explicit initializers:
+//
+// { 1, 2, 3 }
+//
+// CHECK: %[[S_0:.*]] = bitcast %[[S]]* %[[START_AS_S]] to [3 x %[[S]]]*
+//
+// CHECK: %[[S_0_0:.*]] = getelementptr inbounds [3 x %[[S]]]* %[[S_0]], i64 0, i64 0
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_0]], i32 1)
+// CHECK: %[[S_0_1:.*]] = getelementptr inbounds %[[S]]* %[[S_0_0]], i64 1
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_1]], i32 2)
+// CHECK: %[[S_0_2:.*]] = getelementptr inbounds %[[S]]* %[[S_0_1]], i64 1
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_2]], i32 3)
+//
+// { 4, 5, 6 }
+//
+// CHECK: %[[S_1:.*]] = getelementptr [3 x %[[S]]]* %[[S_0]], i32 1
+//
+// CHECK: %[[S_1_0:.*]] = getelementptr inbounds [3 x %[[S]]]* %[[S_1]], i64 0, i64 0
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_0]], i32 4)
+// CHECK: %[[S_1_1:.*]] = getelementptr inbounds %[[S]]* %[[S_1_0]], i64 1
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_1]], i32 5)
+// CHECK: %[[S_1_2:.*]] = getelementptr inbounds %[[S]]* %[[S_1_1]], i64 1
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_2]], i32 6)
+//
+// CHECK-NOT: br i1
+// CHECK-NOT: call
+// CHECK: }
+
+int n;
+void *q = new S[n][3]{ { 1, 2, 3 }, { 4, 5, 6 } };
+
+// CHECK-LABEL: define
+//
+// CHECK: load i32* @n
+// CHECK: call {{.*}} @llvm.umul.with.overflow.i64(i64 %[[N:.*]], i64 12)
+// CHECK: %[[ELTS:.*]] = mul i64 %[[N]], 3
+// CHECK: call {{.*}} @llvm.uadd.with.overflow.i64(i64 %{{.*}}, i64 8)
+// CHECK: %[[ALLOC:.*]] = call noalias i8* @_Znam(i64 %{{.*}})
+//
+// CHECK: %[[COOKIE:.*]] = bitcast i8* %[[ALLOC]] to i64*
+// CHECK: store i64 %[[ELTS]], i64* %[[COOKIE]]
+// CHECK: %[[START_AS_i8:.*]] = getelementptr inbounds i8* %[[ALLOC]], i64 8
+// CHECK: %[[START_AS_S:.*]] = bitcast i8* %[[START_AS_i8]] to %[[S]]*
+// CHECK: %[[END_AS_S:.*]] = getelementptr inbounds %[[S]]* %[[START_AS_S]], i64 %[[ELTS]]
+//
+// Explicit initializers:
+//
+// { 1, 2, 3 }
+//
+// CHECK: %[[S_0:.*]] = bitcast %[[S]]* %[[START_AS_S]] to [3 x %[[S]]]*
+//
+// CHECK: %[[S_0_0:.*]] = getelementptr inbounds [3 x %[[S]]]* %[[S_0]], i64 0, i64 0
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_0]], i32 1)
+// CHECK: %[[S_0_1:.*]] = getelementptr inbounds %[[S]]* %[[S_0_0]], i64 1
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_1]], i32 2)
+// CHECK: %[[S_0_2:.*]] = getelementptr inbounds %[[S]]* %[[S_0_1]], i64 1
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_0_2]], i32 3)
+//
+// { 4, 5, 6 }
+//
+// CHECK: %[[S_1:.*]] = getelementptr [3 x %[[S]]]* %[[S_0]], i32 1
+//
+// CHECK: %[[S_1_0:.*]] = getelementptr inbounds [3 x %[[S]]]* %[[S_1]], i64 0, i64 0
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_0]], i32 4)
+// CHECK: %[[S_1_1:.*]] = getelementptr inbounds %[[S]]* %[[S_1_0]], i64 1
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_1]], i32 5)
+// CHECK: %[[S_1_2:.*]] = getelementptr inbounds %[[S]]* %[[S_1_1]], i64 1
+// CHECK: call void @_ZN1SC1Ei(%[[S]]* %[[S_1_2]], i32 6)
+//
+// CHECK: %[[S_2:.*]] = getelementptr [3 x %[[S]]]* %[[S_1]], i32 1
+// CHECK: %[[S_2_AS_S:.*]] = bitcast [3 x %[[S]]]* %[[S_2]] to %[[S]]*
+// CHECK: icmp eq %[[S]]* %[[S_2_AS_S]], %[[END_AS_S]]
+// CHECK: br i1
+//
+// S[n-2][3] initialization loop:
+//
+// CHECK: %[[END_INNER:.*]] = getelementptr inbounds %[[S]]* %{{.*}}, i64 3
+// CHECK: br label
+//
+//   S[3] initialization loop:
+//
+//   CHECK: call void @_ZN1SC1Ev(%[[S]]*
+//   CHECK: %[[NEXT_INNER:.*]] = getelementptr inbounds %[[S]]* %{{.*}}, i64 1
+//   CHECK: icmp eq %[[S]]* %[[NEXT_INNER]], %[[END_INNER]]
+//   CHECK: br i1
+//
+// CHECK: %[[NEXT_OUTER:.*]] = getelementptr %[[S]]* %{{.*}}, i32 1
+// CHECK: icmp eq %[[S]]* %[[NEXT_OUTER]], %[[END_AS_S]]
+// CHECK: br i1
+//
+// CHECK: }