When emitting a multidimensional array copy, only emit a single flattened
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 14 Dec 2016 01:32:13 +0000 (01:32 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 14 Dec 2016 01:32:13 +0000 (01:32 +0000)
cleanup loop for exception handling.

llvm-svn: 289623

clang/lib/CodeGen/CGExprAgg.cpp
clang/test/CodeGenCXX/lambda-expressions.cpp

index 9ead6b8..35148be 100644 (file)
@@ -164,7 +164,8 @@ public:
   void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO);
   void VisitChooseExpr(const ChooseExpr *CE);
   void VisitInitListExpr(InitListExpr *E);
-  void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E);
+  void VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E,
+                              llvm::Value *outerBegin = nullptr);
   void VisitImplicitValueInitExpr(ImplicitValueInitExpr *E);
   void VisitNoInitExpr(NoInitExpr *E) { } // Do nothing.
   void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) {
@@ -1309,7 +1310,8 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
     cleanupDominator->eraseFromParent();
 }
 
-void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
+void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E,
+                                            llvm::Value *outerBegin) {
   // Emit the common subexpression.
   CodeGenFunction::OpaqueValueMapping binding(CGF, E->getCommonExpr());
 
@@ -1319,15 +1321,18 @@ void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
   if (!numElements)
     return;
 
-  // FIXME: Dig through nested ArrayInitLoopExprs to find the overall array
-  // size, and only emit a single loop for a multidimensional array.
-
   // destPtr is an array*. Construct an elementType* by drilling down a level.
   llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0);
   llvm::Value *indices[] = {zero, zero};
   llvm::Value *begin = Builder.CreateInBoundsGEP(destPtr.getPointer(), indices,
                                                  "arrayinit.begin");
 
+  // Prepare to special-case multidimensional array initialization: we avoid
+  // emitting multiple destructor loops in that case.
+  if (!outerBegin)
+    outerBegin = begin;
+  ArrayInitLoopExpr *InnerLoop = dyn_cast<ArrayInitLoopExpr>(E->getSubExpr());
+
   QualType elementType =
       CGF.getContext().getAsArrayType(E->getType())->getElementType();
   CharUnits elementSize = CGF.getContext().getTypeSizeInChars(elementType);
@@ -1347,9 +1352,12 @@ void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
   // Prepare for a cleanup.
   QualType::DestructionKind dtorKind = elementType.isDestructedType();
   EHScopeStack::stable_iterator cleanup;
-  if (CGF.needsEHCleanup(dtorKind)) {
-    CGF.pushRegularPartialArrayCleanup(
-        begin, element, elementType, elementAlign, CGF.getDestroyer(dtorKind));
+  if (CGF.needsEHCleanup(dtorKind) && !InnerLoop) {
+    if (outerBegin->getType() != element->getType())
+      outerBegin = Builder.CreateBitCast(outerBegin, element->getType());
+    CGF.pushRegularPartialArrayCleanup(outerBegin, element, elementType,
+                                       elementAlign,
+                                       CGF.getDestroyer(dtorKind));
     cleanup = CGF.EHStack.stable_begin();
   } else {
     dtorKind = QualType::DK_none;
@@ -1363,7 +1371,16 @@ void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) {
     CodeGenFunction::ArrayInitLoopExprScope Scope(CGF, index);
     LValue elementLV =
         CGF.MakeAddrLValue(Address(element, elementAlign), elementType);
-    EmitInitializationToLValue(E->getSubExpr(), elementLV);
+
+    if (InnerLoop) {
+      // If the subexpression is an ArrayInitLoopExpr, share its cleanup.
+      auto elementSlot = AggValueSlot::forLValue(
+          elementLV, AggValueSlot::IsDestructed,
+          AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased);
+      AggExprEmitter(CGF, elementSlot, false)
+          .VisitArrayInitLoopExpr(InnerLoop, outerBegin);
+    } else
+      EmitInitializationToLValue(E->getSubExpr(), elementLV);
   }
 
   // Move on to the next element.
index cefaeb4..2c625da 100644 (file)
@@ -140,7 +140,7 @@ namespace pr28595 {
     // CHECK: call {{.*}}after_init
     after_init();
 
-    // CHECK: %[[DST_0:.*]] = getelementptr inbounds [3 x [5 x %[[A]]]], {{.*}}, i64 0, i64 0
+    // CHECK: %[[DST_0:.*]] = getelementptr {{.*}} [3 x [5 x %[[A]]]]* %[[DST:.*]], i64 0, i64 0
     // CHECK: br label
     // CHECK: %[[I:.*]] = phi i64 [ 0, %{{.*}} ], [ %[[I_NEXT:.*]], {{.*}} ]
     // CHECK: %[[DST_I:.*]] = getelementptr {{.*}} [5 x %[[A]]]* %[[DST_0]], i64 %[[I]]
@@ -150,6 +150,7 @@ namespace pr28595 {
     // CHECK: br label
     // CHECK: %[[J:.*]] = phi i64 [ 0, %{{.*}} ], [ %[[J_NEXT:.*]], {{.*}} ]
     // CHECK: %[[DST_I_J:.*]] = getelementptr {{.*}} %[[A]]* %[[DST_I_0]], i64 %[[J]]
+    // CHECK: %[[DST_0_0:.*]] = bitcast [5 x %[[A]]]* %[[DST_0]] to %[[A]]*
     // CHECK: %[[SRC_I_J:.*]] = getelementptr {{.*}} [5 x %[[A]]]* %[[SRC_I]], i64 0, i64 %[[J]]
     //
     // CHECK: invoke void @_ZN7pr285954TempC1Ev
@@ -173,21 +174,12 @@ namespace pr28595 {
     // CHECK: invoke void @_ZN7pr285954TempD1Ev
     // CHECK: br label %[[CLEANUP]]
     //
-    // FIXME: only emit a single cleanup loop here
     // CHECK: [[CLEANUP]]:
-    // CHECK: icmp eq %[[A]]* %[[DST_I_0]], %[[DST_I_J]]
+    // CHECK: icmp eq %[[A]]* %[[DST_0_0]], %[[DST_I_J]]
     // CHECK: %[[T0:.*]] = phi %[[A]]*
     // CHECK: %[[T1:.*]] = getelementptr inbounds %[[A]], %[[A]]* %[[T0]], i64 -1
     // CHECK: call void @_ZN7pr285951AD1Ev(%[[A]]* %[[T1]])
-    // CHECK: icmp eq %[[A]]* %[[T1]], %[[DST_I_0]]
-    //
-    // CHECK: %[[BEGIN:.*]] = getelementptr {{.*}} %[[DST_0]], i64 0, i64 0
-    // CHECK: %[[END:.*]] = getelementptr {{.*}} %[[DST_I]], i64 0, i64 0
-    // CHECK: icmp eq %[[A]]* %[[BEGIN]], %[[END]]
-    // CHECK: %[[T0:.*]] = phi %[[A]]*
-    // CHECK: %[[T1:.*]] = getelementptr inbounds %[[A]], %[[A]]* %[[T0]], i64 -1
-    // CHECK: call void @_ZN7pr285951AD1Ev(%[[A]]* %[[T1]])
-    // CHECK: icmp eq %[[A]]* %[[T1]], %[[BEGIN]]
+    // CHECK: icmp eq %[[A]]* %[[T1]], %[[DST_0_0]]
     (void) [array]{};
   }
 }