[cfe-commits] r134890 - in /cfe/trunk: lib/CodeGen/CGDecl.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CodeGenFunction.h test/CodeGenCXX/destructors.cpp test/CodeGenCXX/partial-destruction.cpp

John McCall rjmccall at apple.com
Mon Jul 11 01:38:19 PDT 2011


Author: rjmccall
Date: Mon Jul 11 03:38:19 2011
New Revision: 134890

URL: http://llvm.org/viewvc/llvm-project?rev=134890&view=rev
Log:
Fix a lot of problems with the partial destruction of arrays:
 - an off-by-one error in emission of irregular array limits for
   InitListExprs
 - use an EH partial-destruction cleanup within the normal
   array-destruction cleanup
 - get the branch destinations right for the empty check
Also some refactoring which unfortunately obscures these changes.


Added:
    cfe/trunk/test/CodeGenCXX/partial-destruction.cpp
Modified:
    cfe/trunk/lib/CodeGen/CGDecl.cpp
    cfe/trunk/lib/CodeGen/CGExprAgg.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/test/CodeGenCXX/destructors.cpp

Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=134890&r1=134889&r2=134890&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Mon Jul 11 03:38:19 2011
@@ -306,15 +306,21 @@
 namespace {
   struct DestroyObject : EHScopeStack::Cleanup {
     DestroyObject(llvm::Value *addr, QualType type,
-                  CodeGenFunction::Destroyer *destroyer)
-      : addr(addr), type(type), destroyer(*destroyer) {}
+                  CodeGenFunction::Destroyer *destroyer,
+                  bool useEHCleanupForArray)
+      : addr(addr), type(type), destroyer(*destroyer),
+        useEHCleanupForArray(useEHCleanupForArray) {}
 
     llvm::Value *addr;
     QualType type;
     CodeGenFunction::Destroyer &destroyer;
+    bool useEHCleanupForArray;
 
-    void Emit(CodeGenFunction &CGF, bool IsForEH) {
-      CGF.emitDestroy(addr, type, destroyer);
+    void Emit(CodeGenFunction &CGF, bool isForEH) {
+      // Don't use an EH cleanup recursively from an EH cleanup.
+      bool useEHCleanupForArray = !isForEH && this->useEHCleanupForArray;
+
+      CGF.emitDestroy(addr, type, destroyer, useEHCleanupForArray);
     }
   };
 
@@ -1059,7 +1065,12 @@
 
   // If we haven't chosen a more specific destroyer, use the default.
   if (!destroyer) destroyer = &getDestroyer(dtorKind);
-  EHStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer);
+
+  // Use an EH cleanup in array destructors iff the destructor itself
+  // is being pushed as an EH cleanup.
+  bool useEHCleanup = (cleanupKind & EHCleanup);
+  EHStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer,
+                                     useEHCleanup);
 }
 
 void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
@@ -1119,12 +1130,26 @@
 }
 
 void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, llvm::Value *addr,
-                                  QualType type, Destroyer &destroyer) {
-  EHStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer);
+                                  QualType type, Destroyer &destroyer,
+                                  bool useEHCleanupForArray) {
+  EHStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer,
+                                     useEHCleanupForArray);
 }
 
+/// emitDestroy - Immediately perform the destruction of the given
+/// object.
+///
+/// \param addr - the address of the object; a type*
+/// \param type - the type of the object; if an array type, all
+///   objects are destroyed in reverse order
+/// \param destroyer - the function to call to destroy individual
+///   elements
+/// \param useEHCleanupForArray - whether an EH cleanup should be
+///   used when destroying array elements, in case one of the
+///   destructions throws an exception
 void CodeGenFunction::emitDestroy(llvm::Value *addr, QualType type,
-                                  Destroyer &destroyer) {
+                                  Destroyer &destroyer,
+                                  bool useEHCleanupForArray) {
   const ArrayType *arrayType = getContext().getAsArrayType(type);
   if (!arrayType)
     return destroyer(*this, addr, type);
@@ -1132,13 +1157,24 @@
   llvm::Value *begin = addr;
   llvm::Value *length = emitArrayLength(arrayType, type, begin);
   llvm::Value *end = Builder.CreateInBoundsGEP(begin, length);
-  emitArrayDestroy(begin, end, type, destroyer);
+  emitArrayDestroy(begin, end, type, destroyer, useEHCleanupForArray);
 }
 
+/// emitArrayDestroy - Destroys all the elements of the given array,
+/// beginning from last to first.  The array cannot be zero-length.
+///
+/// \param begin - a type* denoting the first element of the array
+/// \param end - a type* denoting one past the end of the array
+/// \param type - the element type of the array
+/// \param destroyer - the function to call to destroy elements
+/// \param useEHCleanup - whether to push an EH cleanup to destroy
+///   the remaining elements in case the destruction of a single
+///   element throws
 void CodeGenFunction::emitArrayDestroy(llvm::Value *begin,
                                        llvm::Value *end,
                                        QualType type,
-                                       Destroyer &destroyer) {
+                                       Destroyer &destroyer,
+                                       bool useEHCleanup) {
   assert(!type->isArrayType());
 
   // The basic structure here is a do-while loop, because we don't
@@ -1158,9 +1194,15 @@
   llvm::Value *element = Builder.CreateInBoundsGEP(elementPast, negativeOne,
                                                    "arraydestroy.element");
 
+  if (useEHCleanup)
+    pushRegularPartialArrayCleanup(begin, element, type, destroyer);
+
   // Perform the actual destruction there.
   destroyer(*this, element, type);
 
+  if (useEHCleanup)
+    PopCleanupBlock();
+
   // Check whether we've reached the end.
   llvm::Value *done = Builder.CreateICmpEQ(element, begin, "arraydestroy.done");
   Builder.CreateCondBr(done, doneBB, bodyBB);
@@ -1170,73 +1212,131 @@
   EmitBlock(doneBB);
 }
 
+/// Perform partial array destruction as if in an EH cleanup.  Unlike
+/// emitArrayDestroy, the element type here may still be an array type.
+///
+/// Essentially does an emitArrayDestroy, but checking for the
+/// possibility of a zero-length array (in case the initializer for
+/// the first element throws).
+static void emitPartialArrayDestroy(CodeGenFunction &CGF,
+                                    llvm::Value *begin, llvm::Value *end,
+                                    QualType type,
+                                    CodeGenFunction::Destroyer &destroyer) {
+  // Check whether the array is empty.  For the sake of prettier IR,
+  // we want to jump to the end of the array destroy loop instead of
+  // jumping to yet another block.  We can do this with some modest
+  // assumptions about how emitArrayDestroy works.
+
+  llvm::Value *earlyTest =
+    CGF.Builder.CreateICmpEQ(begin, end, "pad.isempty");
+
+  llvm::BasicBlock *nextBB = CGF.createBasicBlock("pad.arraydestroy");
+
+  // Temporarily, build the conditional branch with identical
+  // successors.  We'll patch this in a bit.
+  llvm::BranchInst *br =
+    CGF.Builder.CreateCondBr(earlyTest, nextBB, nextBB);
+  CGF.EmitBlock(nextBB);
+
+  llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0);
+
+  // If the element type is itself an array, drill down.
+  llvm::SmallVector<llvm::Value*,4> gepIndices;
+  gepIndices.push_back(zero);
+  while (const ArrayType *arrayType = CGF.getContext().getAsArrayType(type)) {
+    // VLAs don't require a GEP index to walk into.
+    if (!isa<VariableArrayType>(arrayType))
+      gepIndices.push_back(zero);
+    type = arrayType->getElementType();
+  }
+  if (gepIndices.size() != 1) {
+    begin = CGF.Builder.CreateInBoundsGEP(begin, gepIndices.begin(),
+                                          gepIndices.end(), "pad.arraybegin");
+    end = CGF.Builder.CreateInBoundsGEP(end, gepIndices.begin(),
+                                        gepIndices.end(), "pad.arrayend");
+  }
+
+  // Now that we know that the array isn't empty, destroy it.  We
+  // don't ever need an EH cleanup because we assume that we're in an
+  // EH cleanup ourselves, so a throwing destructor causes an
+  // immediate terminate.
+  CGF.emitArrayDestroy(begin, end, type, destroyer, /*useEHCleanup*/ false);
+
+  // Set the conditional branch's 'false' successor to doneBB.
+  llvm::BasicBlock *doneBB = CGF.Builder.GetInsertBlock();
+  assert(CGF.Builder.GetInsertPoint() == doneBB->begin());
+  br->setSuccessor(0, doneBB);
+}
+
 namespace {
-  class PartialArrayDestroy : public EHScopeStack::Cleanup {
+  /// RegularPartialArrayDestroy - a cleanup which performs a partial
+  /// array destroy where the end pointer is regularly determined and
+  /// does not need to be loaded from a local.
+  class RegularPartialArrayDestroy : public EHScopeStack::Cleanup {
+    llvm::Value *ArrayBegin;
+    llvm::Value *ArrayEnd;
+    QualType ElementType;
+    CodeGenFunction::Destroyer &Destroyer;
+  public:
+    RegularPartialArrayDestroy(llvm::Value *arrayBegin, llvm::Value *arrayEnd,
+                               QualType elementType,
+                               CodeGenFunction::Destroyer *destroyer)
+      : ArrayBegin(arrayBegin), ArrayEnd(arrayEnd),
+        ElementType(elementType), Destroyer(*destroyer) {}
+
+    void Emit(CodeGenFunction &CGF, bool isForEH) {
+      emitPartialArrayDestroy(CGF, ArrayBegin, ArrayEnd,
+                              ElementType, Destroyer);
+    }
+  };
+
+  /// IrregularPartialArrayDestroy - a cleanup which performs a
+  /// partial array destroy where the end pointer is irregularly
+  /// determined and must be loaded from a local.
+  class IrregularPartialArrayDestroy : public EHScopeStack::Cleanup {
     llvm::Value *ArrayBegin;
     llvm::Value *ArrayEndPointer;
     QualType ElementType;
     CodeGenFunction::Destroyer &Destroyer;
   public:
-    PartialArrayDestroy(llvm::Value *arrayBegin, llvm::Value *arrayEndPointer,
-                        QualType elementType,
-                        CodeGenFunction::Destroyer *destroyer)
+    IrregularPartialArrayDestroy(llvm::Value *arrayBegin,
+                                 llvm::Value *arrayEndPointer,
+                                 QualType elementType,
+                                 CodeGenFunction::Destroyer *destroyer)
       : ArrayBegin(arrayBegin), ArrayEndPointer(arrayEndPointer),
         ElementType(elementType), Destroyer(*destroyer) {}
 
     void Emit(CodeGenFunction &CGF, bool isForEH) {
-      llvm::Value *arrayBegin = ArrayBegin;
       llvm::Value *arrayEnd = CGF.Builder.CreateLoad(ArrayEndPointer);
-
-      // It's possible for the count to be zero here, so we're going
-      // to need a check.  For the sake of prettier IR, we just want
-      // to jump to the end of the array destroy loop.  This assumes
-      // the structure of the IR generated by emitArrayDestroy, but
-      // that assumption is pretty reliable.
-      llvm::Value *earlyTest =
-        CGF.Builder.CreateICmpEQ(arrayBegin, arrayEnd, "pad.isempty");
-
-      llvm::BasicBlock *nextBB = CGF.createBasicBlock("pad.arraydestroy");
-
-      // For now, use a conditional branch with both successors the
-      // same.  We'll patch this later.
-      llvm::BranchInst *br =
-        CGF.Builder.CreateCondBr(earlyTest, nextBB, nextBB);
-      CGF.EmitBlock(nextBB);
-
-      llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0);
-
-      // If the element type is itself an array, drill down.
-      QualType type = ElementType;
-      llvm::SmallVector<llvm::Value*,4> gepIndices;
-      gepIndices.push_back(zero);
-      while (const ArrayType *arrayType = CGF.getContext().getAsArrayType(type)) {
-        // VLAs don't require a GEP index to walk into.
-        if (!isa<VariableArrayType>(arrayType))
-          gepIndices.push_back(zero);
-        type = arrayType->getElementType();
-      }
-      if (gepIndices.size() != 1) {
-        arrayBegin =
-          CGF.Builder.CreateInBoundsGEP(arrayBegin, gepIndices.begin(),
-                                        gepIndices.end(), "pad.arraybegin");
-        arrayEnd =
-          CGF.Builder.CreateInBoundsGEP(arrayEnd, gepIndices.begin(),
-                                        gepIndices.end(), "pad.arrayend");
-      }
-
-      CGF.emitArrayDestroy(arrayBegin, arrayEnd, type, Destroyer);
-
-      // Set the conditional branch's 'false' successor to doneBB.
-      llvm::BasicBlock *doneBB = CGF.Builder.GetInsertBlock();
-      assert(CGF.Builder.GetInsertPoint() == doneBB->begin());
-      br->setSuccessor(1, doneBB);
+      emitPartialArrayDestroy(CGF, ArrayBegin, arrayEnd,
+                              ElementType, Destroyer);
     }
   };
 }
 
-/// pushPartialArrayCleanup - Push a cleanup to destroy
+/// pushIrregularPartialArrayCleanup - Push an EH cleanup to destroy
+/// already-constructed elements of the given array.  The cleanup
+/// may be popped with DeactivateCleanupBlock or PopCleanupBlock.
+/// 
+/// \param elementType - the immediate element type of the array;
+///   possibly still an array type
+/// \param array - a value of type elementType*
+/// \param destructionKind - the kind of destruction required
+/// \param initializedElementCount - a value of type size_t* holding
+///   the number of successfully-constructed elements
+void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *array,
+                                                 llvm::Value *arrayEndPointer,
+                                                       QualType elementType,
+                                                       Destroyer &destroyer) {
+  // FIXME: can this be in a conditional expression?
+  EHStack.pushCleanup<IrregularPartialArrayDestroy>(EHCleanup, array,
+                                                    arrayEndPointer,
+                                                    elementType, &destroyer);
+}
+
+/// pushRegularPartialArrayCleanup - Push an EH cleanup to destroy
 /// already-constructed elements of the given array.  The cleanup
-/// may be popped with DeactivateCleanupBlock.
+/// may be popped with DeactivateCleanupBlock or PopCleanupBlock.
 /// 
 /// \param elementType - the immediate element type of the array;
 ///   possibly still an array type
@@ -1244,13 +1344,14 @@
 /// \param destructionKind - the kind of destruction required
 /// \param initializedElementCount - a value of type size_t* holding
 ///   the number of successfully-constructed elements
-void CodeGenFunction::pushPartialArrayCleanup(llvm::Value *array,
-                                              QualType elementType,
-                                              Destroyer &destroyer,
-                                              llvm::Value *arrayEndPointer) {
+void CodeGenFunction::pushRegularPartialArrayCleanup(llvm::Value *arrayBegin,
+                                                     llvm::Value *arrayEnd,
+                                                     QualType elementType,
+                                                     Destroyer &destroyer) {
   // FIXME: can this be in a conditional expression?
-  EHStack.pushCleanup<PartialArrayDestroy>(EHCleanup, array, arrayEndPointer,
-                                           elementType, &destroyer);
+  EHStack.pushCleanup<RegularPartialArrayDestroy>(EHCleanup,
+                                                  arrayBegin, arrayEnd,
+                                                  elementType, &destroyer);
 }
 
 namespace {

Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=134890&r1=134889&r2=134890&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Mon Jul 11 03:38:19 2011
@@ -689,8 +689,8 @@
       endOfInit = CGF.CreateTempAlloca(begin->getType(),
                                        "arrayinit.endOfInit");
       Builder.CreateStore(begin, endOfInit);
-      CGF.pushPartialArrayCleanup(begin, elementType,
-                                  CGF.getDestroyer(dtorKind), endOfInit);
+      CGF.pushIrregularPartialArrayCleanup(begin, endOfInit, elementType,
+                                           CGF.getDestroyer(dtorKind));
       cleanup = CGF.EHStack.stable_begin();
 
     // Otherwise, remember that we didn't need a cleanup.
@@ -710,16 +710,17 @@
     // Emit the explicit initializers.
     for (uint64_t i = 0; i != NumInitElements; ++i) {
       // Advance to the next element.
-      if (i > 0)
+      if (i > 0) {
         element = Builder.CreateInBoundsGEP(element, one, "arrayinit.element");
 
+        // Tell the cleanup that it needs to destroy up to this
+        // element.  TODO: some of these stores can be trivially
+        // observed to be unnecessary.
+        if (endOfInit) Builder.CreateStore(element, endOfInit);
+      }
+
       LValue elementLV = CGF.MakeAddrLValue(element, elementType);
       EmitInitializationToLValue(E->getInit(i), elementLV);
-
-      // Tell the cleanup that it needs to destroy this element.
-      // TODO: some of these stores can be trivially observed to be
-      // unnecessary.
-      if (endOfInit) Builder.CreateStore(element, endOfInit);
     }
 
     // Check whether there's a non-trivial array-fill expression.
@@ -743,8 +744,10 @@
       //   do { *array++ = filler; } while (array != end);
 
       // Advance to the start of the rest of the array.
-      if (NumInitElements)
+      if (NumInitElements) {
         element = Builder.CreateInBoundsGEP(element, one, "arrayinit.start");
+        if (endOfInit) Builder.CreateStore(element, endOfInit);
+      }
 
       // Compute the end of the array.
       llvm::Value *end = Builder.CreateInBoundsGEP(begin,
@@ -767,13 +770,13 @@
       else
         EmitNullInitializationToLValue(elementLV);
 
-      // Tell the EH cleanup that we finished with that element.
-      if (endOfInit) Builder.CreateStore(element, endOfInit);
-
       // Move on to the next element.
       llvm::Value *nextElement =
         Builder.CreateInBoundsGEP(currentElement, one, "arrayinit.next");
 
+      // Tell the EH cleanup that we finished with the last element.
+      if (endOfInit) Builder.CreateStore(nextElement, endOfInit);
+
       // Leave the loop if we're done.
       llvm::Value *done = Builder.CreateICmpEQ(nextElement, end,
                                                "arrayinit.done");

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=134890&r1=134889&r2=134890&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Mon Jul 11 03:38:19 2011
@@ -1156,17 +1156,23 @@
 
   typedef void Destroyer(CodeGenFunction &CGF, llvm::Value *addr, QualType ty);
 
-  void pushPartialArrayCleanup(llvm::Value *arrayBegin,
-                               QualType elementType,
-                               Destroyer &destroyer,
-                               llvm::Value *arrayEndPointer);
+  void pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
+                                        llvm::Value *arrayEndPointer,
+                                        QualType elementType,
+                                        Destroyer &destroyer);
+  void pushRegularPartialArrayCleanup(llvm::Value *arrayBegin,
+                                      llvm::Value *arrayEnd,
+                                      QualType elementType,
+                                      Destroyer &destroyer);
 
   Destroyer &getDestroyer(QualType::DestructionKind destructionKind);
   void pushDestroy(CleanupKind kind, llvm::Value *addr, QualType type,
-                   Destroyer &destroyer);
-  void emitDestroy(llvm::Value *addr, QualType type, Destroyer &destroyer);
+                   Destroyer &destroyer, bool useEHCleanupForArray);
+  void emitDestroy(llvm::Value *addr, QualType type, Destroyer &destroyer,
+                   bool useEHCleanupForArray);
   void emitArrayDestroy(llvm::Value *begin, llvm::Value *end,
-                        QualType type, Destroyer &destroyer);
+                        QualType type, Destroyer &destroyer,
+                        bool useEHCleanup);
 
   /// Determines whether an EH cleanup is required to destroy a type
   /// with the given destruction kind.

Modified: cfe/trunk/test/CodeGenCXX/destructors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/destructors.cpp?rev=134890&r1=134889&r2=134890&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/destructors.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/destructors.cpp Mon Jul 11 03:38:19 2011
@@ -235,15 +235,26 @@
 
   // CHECK: define void @_ZN5test53fooEv()
   // CHECK:      [[ELEMS:%.*]] = alloca [5 x [[A:%.*]]], align
+  // CHECK-NEXT: [[EXN:%.*]] = alloca i8*
+  // CHECK-NEXT: [[SEL:%.*]] = alloca i32
+  // CHECK-NEXT: [[EHCLEANUP:%.*]] = alloca i32
   // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [5 x [[A]]]* [[ELEMS]], i32 0, i32 0
   // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 5
   // CHECK-NEXT: br label
   // CHECK:      [[POST:%.*]] = phi [[A]]* [ [[END]], {{%.*}} ], [ [[ELT:%.*]], {{%.*}} ]
   // CHECK-NEXT: [[ELT]] = getelementptr inbounds [[A]]* [[POST]], i64 -1
-  // CHECK-NEXT: call void @_ZN5test51AD1Ev([[A]]* [[ELT]])
-  // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[ELT]], [[BEGIN]]
+  // CHECK-NEXT: invoke void @_ZN5test51AD1Ev([[A]]* [[ELT]])
+  // CHECK:      [[T0:%.*]] = icmp eq [[A]]* [[ELT]], [[BEGIN]]
   // CHECK-NEXT: br i1 [[T0]],
   // CHECK:      ret void
+  // lpad
+  // CHECK:      [[EMPTY:%.*]] = icmp eq [[A]]* [[BEGIN]], [[ELT]]
+  // CHECK-NEXT: br i1 [[EMPTY]]
+  // CHECK:      [[AFTER:%.*]] = phi [[A]]* [ [[ELT]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ]
+  // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]]* [[AFTER]], i64 -1
+  // CHECK-NEXT: invoke void @_ZN5test51AD1Ev([[A]]* [[CUR]])
+  // CHECK:      [[DONE:%.*]] = icmp eq [[A]]* [[CUR]], [[BEGIN]]
+  // CHECK-NEXT: br i1 [[DONE]],
   void foo() {
     A elems[5];
   }

Added: cfe/trunk/test/CodeGenCXX/partial-destruction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/partial-destruction.cpp?rev=134890&view=auto
==============================================================================
--- cfe/trunk/test/CodeGenCXX/partial-destruction.cpp (added)
+++ cfe/trunk/test/CodeGenCXX/partial-destruction.cpp Mon Jul 11 03:38:19 2011
@@ -0,0 +1,90 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - -fcxx-exceptions -fexceptions | FileCheck %s
+
+// Test IR generation for partial destruction of aggregates.
+
+void opaque();
+
+// Initializer lists.
+namespace test0 {
+  struct A { A(int); A(); ~A(); void *v; };
+  void test() {
+    A as[10] = { 5, 7 };
+    opaque();
+  }
+  // CHECK:    define void @_ZN5test04testEv()
+  // CHECK:      [[AS:%.*]] = alloca [10 x [[A:%.*]]], align
+  // CHECK-NEXT: [[ENDVAR:%.*]] = alloca [[A]]*
+  // CHECK-NEXT: [[EXN:%.*]] = alloca i8*
+  // CHECK-NEXT: [[SEL:%.*]] = alloca i32
+  // CHECK-NEXT: [[CLEANUP:%.*]] = alloca i32
+
+  // Initialize.
+  // CHECK-NEXT: [[E_BEGIN:%.*]] = getelementptr inbounds [10 x [[A]]]* [[AS]], i64 0, i64 0
+  // CHECK-NEXT: store [[A]]* [[E_BEGIN]], [[A]]** [[ENDVAR]]
+  // CHECK-NEXT: invoke void @_ZN5test01AC1Ei([[A]]* [[E_BEGIN]], i32 5)
+  // CHECK:      [[E1:%.*]] = getelementptr inbounds [[A]]* [[E_BEGIN]], i64 1
+  // CHECK-NEXT: store [[A]]* [[E1]], [[A]]** [[ENDVAR]]
+  // CHECK-NEXT: invoke void @_ZN5test01AC1Ei([[A]]* [[E1]], i32 7)
+  // CHECK:      [[E2:%.*]] = getelementptr inbounds [[A]]* [[E1]], i64 1
+  // CHECK-NEXT: store [[A]]* [[E2]], [[A]]** [[ENDVAR]]
+  // CHECK-NEXT: [[E_END:%.*]] = getelementptr inbounds [[A]]* [[E_BEGIN]], i64 10
+  // CHECK-NEXT: br label
+  // CHECK:      [[E_CUR:%.*]] = phi [[A]]* [ [[E2]], {{%.*}} ], [ [[E_NEXT:%.*]], {{%.*}} ]
+  // CHECK-NEXT: invoke void @_ZN5test01AC1Ev([[A]]* [[E_CUR]])
+  // CHECK:      [[E_NEXT]] = getelementptr inbounds [[A]]* [[E_CUR]], i64 1
+  // CHECK-NEXT: store [[A]]* [[E_NEXT]], [[A]]** [[ENDVAR]]
+  // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[E_NEXT]], [[E_END]]
+  // CHECK-NEXT: br i1 [[T0]],
+
+  // Run.
+  // CHECK:      invoke void @_Z6opaquev()
+
+  // Normal destroy.
+  // CHECK:      [[ED_BEGIN:%.*]] = getelementptr inbounds [10 x [[A]]]* [[AS]], i32 0, i32 0
+  // CHECK-NEXT: [[ED_END:%.*]] = getelementptr inbounds [[A]]* [[ED_BEGIN]], i64 10
+  // CHECK-NEXT: br label
+  // CHECK:      [[ED_AFTER:%.*]] = phi [[A]]* [ [[ED_END]], {{%.*}} ], [ [[ED_CUR:%.*]], {{%.*}} ]
+  // CHECK-NEXT: [[ED_CUR]] = getelementptr inbounds [[A]]* [[ED_AFTER]], i64 -1
+  // CHECK-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[ED_CUR]])
+  // CHECK:      [[T0:%.*]] = icmp eq [[A]]* [[ED_CUR]], [[ED_BEGIN]]
+  // CHECK-NEXT: br i1 [[T0]],
+  // CHECK:      ret void
+
+  // Partial destroy for initialization.
+  // CHECK:      llvm.eh.selector({{.*}}, i32 0)
+  // CHECK:      [[PARTIAL_END:%.*]] = load [[A]]** [[ENDVAR]]
+  // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[E_BEGIN]], [[PARTIAL_END]]
+  // CHECK-NEXT: br i1 [[T0]],
+  // CHECK:      [[E_AFTER:%.*]] = phi [[A]]* [ [[PARTIAL_END]], {{%.*}} ], [ [[E_CUR:%.*]], {{%.*}} ]
+  // CHECK-NEXT: [[E_CUR]] = getelementptr inbounds [[A]]* [[E_AFTER]], i64 -1
+  // CHECK-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[E_CUR]])
+  // CHECK:      [[T0:%.*]] = icmp eq [[A]]* [[E_CUR]], [[E_BEGIN]]
+  // CHECK-NEXT: br i1 [[T0]],
+
+  // Primary EH destructor.
+  // CHECK:      llvm.eh.selector({{.*}}, i32 0)
+  // CHECK:      [[E0:%.*]] = getelementptr inbounds [10 x [[A]]]* [[AS]], i32 0, i32 0
+  // CHECK-NEXT: [[E_END:%.*]] = getelementptr inbounds [[A]]* [[E0]], i64 10
+  // CHECK-NEXT: br label
+
+  // Partial destructor for primary normal destructor.
+  // FIXME: There's some really bad block ordering here which causes
+  // the partial destroy for the primary normal destructor to fall
+  // within the primary EH destructor.
+  // CHECK:      llvm.eh.selector({{.*}}, i32 0)
+  // CHECK:      [[T0:%.*]] = icmp eq [[A]]* [[ED_BEGIN]], [[ED_CUR]]
+  // CHECK-NEXT: br i1 [[T0]]
+  // CHECK:      [[EDD_AFTER:%.*]] = phi [[A]]* [ [[ED_CUR]], {{%.*}} ], [ [[EDD_CUR:%.*]], {{%.*}} ]
+  // CHECK-NEXT: [[EDD_CUR]] = getelementptr inbounds [[A]]* [[EDD_AFTER]], i64 -1
+  // CHECK-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[EDD_CUR]])
+  // CHECK:      [[T0:%.*]] = icmp eq [[A]]* [[EDD_CUR]], [[ED_BEGIN]]
+  // CHECK-NEXT: br i1 [[T0]]
+
+  // Back to the primary EH destructor.
+  // CHECK:      [[E_AFTER:%.*]] = phi [[A]]* [ [[E_END]], {{%.*}} ], [ [[E_CUR:%.*]], {{%.*}} ]
+  // CHECK-NEXT: [[E_CUR]] = getelementptr inbounds [[A]]* [[E_AFTER]], i64 -1
+  // CHECK-NEXT: invoke void @_ZN5test01AD1Ev([[A]]* [[E_CUR]])
+  // CHECK:      [[T0:%.*]] = icmp eq [[A]]* [[E_CUR]], [[E0]]
+  // CHECK-NEXT: br i1 [[T0]],
+
+}





More information about the cfe-commits mailing list