[cfe-commits] r134784 - in /cfe/trunk: lib/CodeGen/CGClass.cpp lib/CodeGen/CGDecl.cpp lib/CodeGen/CGExprAgg.cpp lib/CodeGen/CGObjC.cpp lib/CodeGen/CodeGenFunction.cpp lib/CodeGen/CodeGenFunction.h test/CodeGenCXX/destructors.cpp test/CodeGenCXX/temporaries.cpp test/CodeGenCXX/value-init.cpp test/CodeGenObjC/arc.m

John McCall rjmccall at apple.com
Fri Jul 8 18:37:26 PDT 2011


Author: rjmccall
Date: Fri Jul  8 20:37:26 2011
New Revision: 134784

URL: http://llvm.org/viewvc/llvm-project?rev=134784&view=rev
Log:
A number of array-related IR-gen cleanups.
  - Emit default-initialization of arrays that were partially initialized
    with initializer lists with a loop, rather than emitting the default
    initializer N times;
  - support destroying VLAs of non-trivial type, although this is not
    yet exposed to users; and
  - support the partial destruction of arrays initialized with
    initializer lists when an initializer throws an exception.



Modified:
    cfe/trunk/lib/CodeGen/CGClass.cpp
    cfe/trunk/lib/CodeGen/CGDecl.cpp
    cfe/trunk/lib/CodeGen/CGExprAgg.cpp
    cfe/trunk/lib/CodeGen/CGObjC.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/test/CodeGenCXX/destructors.cpp
    cfe/trunk/test/CodeGenCXX/temporaries.cpp
    cfe/trunk/test/CodeGenCXX/value-init.cpp
    cfe/trunk/test/CodeGenObjC/arc.m

Modified: cfe/trunk/lib/CodeGen/CGClass.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGClass.cpp?rev=134784&r1=134783&r2=134784&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGClass.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGClass.cpp Fri Jul  8 20:37:26 2011
@@ -1172,6 +1172,17 @@
   EmitBlock(AfterFor, true);
 }
 
+void CodeGenFunction::destroyCXXObject(CodeGenFunction &CGF,
+                                       llvm::Value *addr,
+                                       QualType type) {
+  const RecordType *rtype = type->castAs<RecordType>();
+  const CXXRecordDecl *record = cast<CXXRecordDecl>(rtype->getDecl());
+  const CXXDestructorDecl *dtor = record->getDestructor();
+  assert(!dtor->isTrivial());
+  CGF.EmitCXXDestructorCall(dtor, Dtor_Complete, /*for vbase*/ false,
+                            addr);
+}
+
 /// EmitCXXAggrDestructorCall - calls the default destructor on array
 /// elements in reverse order of construction.
 void

Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=134784&r1=134783&r2=134784&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Fri Jul  8 20:37:26 2011
@@ -304,30 +304,25 @@
 }
 
 namespace {
-  struct CallArrayDtor : EHScopeStack::Cleanup {
-    CallArrayDtor(const CXXDestructorDecl *Dtor, 
-                  const ConstantArrayType *Type,
-                  llvm::Value *Loc)
-      : Dtor(Dtor), Type(Type), Loc(Loc) {}
-
-    const CXXDestructorDecl *Dtor;
-    const ConstantArrayType *Type;
-    llvm::Value *Loc;
+  struct DestroyObject : EHScopeStack::Cleanup {
+    DestroyObject(llvm::Value *addr, QualType type,
+                  CodeGenFunction::Destroyer *destroyer)
+      : addr(addr), type(type), destroyer(*destroyer) {}
+
+    llvm::Value *addr;
+    QualType type;
+    CodeGenFunction::Destroyer &destroyer;
 
     void Emit(CodeGenFunction &CGF, bool IsForEH) {
-      QualType BaseElementTy = CGF.getContext().getBaseElementType(Type);
-      const llvm::Type *BasePtr = CGF.ConvertType(BaseElementTy);
-      BasePtr = llvm::PointerType::getUnqual(BasePtr);
-      llvm::Value *BaseAddrPtr = CGF.Builder.CreateBitCast(Loc, BasePtr);
-      CGF.EmitCXXAggrDestructorCall(Dtor, Type, BaseAddrPtr);
+      CGF.emitDestroy(addr, type, destroyer);
     }
   };
 
-  struct CallVarDtor : EHScopeStack::Cleanup {
-    CallVarDtor(const CXXDestructorDecl *Dtor,
-                llvm::Value *NRVOFlag,
-                llvm::Value *Loc)
-      : Dtor(Dtor), NRVOFlag(NRVOFlag), Loc(Loc) {}
+  struct DestroyNRVOVariable : EHScopeStack::Cleanup {
+    DestroyNRVOVariable(llvm::Value *addr,
+                        const CXXDestructorDecl *Dtor,
+                        llvm::Value *NRVOFlag)
+      : Dtor(Dtor), NRVOFlag(NRVOFlag), Loc(addr) {}
 
     const CXXDestructorDecl *Dtor;
     llvm::Value *NRVOFlag;
@@ -1014,6 +1009,59 @@
   }
 }
 
+/// Enter a destroy cleanup for the given local variable.
+void CodeGenFunction::emitAutoVarTypeCleanup(
+                            const CodeGenFunction::AutoVarEmission &emission,
+                            QualType::DestructionKind dtorKind) {
+  assert(dtorKind != QualType::DK_none);
+
+  // Note that for __block variables, we want to destroy the
+  // original stack object, not the possibly forwarded object.
+  llvm::Value *addr = emission.getObjectAddress(*this);
+
+  const VarDecl *var = emission.Variable;
+  QualType type = var->getType();
+
+  CleanupKind cleanupKind = NormalAndEHCleanup;
+  CodeGenFunction::Destroyer *destroyer = 0;
+
+  switch (dtorKind) {
+  case QualType::DK_none:
+    llvm_unreachable("no cleanup for trivially-destructible variable");
+
+  case QualType::DK_cxx_destructor:
+    // If there's an NRVO flag on the emission, we need a different
+    // cleanup.
+    if (emission.NRVOFlag) {
+      assert(!type->isArrayType());
+      CXXDestructorDecl *dtor = type->getAsCXXRecordDecl()->getDestructor();
+      EHStack.pushCleanup<DestroyNRVOVariable>(cleanupKind, addr, dtor,
+                                               emission.NRVOFlag);
+      return;
+    }
+    break;
+
+  case QualType::DK_objc_strong_lifetime:
+    // Suppress cleanups for pseudo-strong variables.
+    if (var->isARCPseudoStrong()) return;
+    
+    // Otherwise, consider whether to use an EH cleanup or not.
+    cleanupKind = getARCCleanupKind();
+
+    // Use the imprecise destroyer by default.
+    if (!var->hasAttr<ObjCPreciseLifetimeAttr>())
+      destroyer = CodeGenFunction::destroyARCStrongImprecise;
+    break;
+
+  case QualType::DK_objc_weak_lifetime:
+    break;
+  }
+
+  // If we haven't chosen a more specific destroyer, use the default.
+  if (!destroyer) destroyer = &getDestroyer(dtorKind);
+  EHStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer);
+}
+
 void CodeGenFunction::EmitAutoVarCleanups(const AutoVarEmission &emission) {
   assert(emission.Variable && "emission was not valid!");
 
@@ -1022,44 +1070,9 @@
 
   const VarDecl &D = *emission.Variable;
 
-  // Handle C++ or ARC destruction of variables.
-  if (getLangOptions().CPlusPlus) {
-    QualType type = D.getType();
-    QualType baseType = getContext().getBaseElementType(type);
-    if (const RecordType *RT = baseType->getAs<RecordType>()) {
-      CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());
-      if (!ClassDecl->hasTrivialDestructor()) {
-        // Note: We suppress the destructor call when the corresponding NRVO
-        // flag has been set.
-
-        // Note that for __block variables, we want to destroy the
-        // original stack object, not the possible forwarded object.
-        llvm::Value *Loc = emission.getObjectAddress(*this);
-        
-        const CXXDestructorDecl *D = ClassDecl->getDestructor();
-        assert(D && "EmitLocalBlockVarDecl - destructor is nul");
-        
-        if (type != baseType) {
-          const ConstantArrayType *Array = 
-            getContext().getAsConstantArrayType(type);
-          assert(Array && "types changed without array?");
-          EHStack.pushCleanup<CallArrayDtor>(NormalAndEHCleanup,
-                                             D, Array, Loc);
-        } else {
-          EHStack.pushCleanup<CallVarDtor>(NormalAndEHCleanup,
-                                           D, emission.NRVOFlag, Loc);
-        }
-      }
-    }
-  }
-
-  if (Qualifiers::ObjCLifetime lifetime
-        = D.getType().getQualifiers().getObjCLifetime()) {
-    if (!D.isARCPseudoStrong()) {
-      llvm::Value *loc = emission.getObjectAddress(*this);
-      EmitAutoVarWithLifetime(*this, D, loc, lifetime);
-    }
-  }
+  // Check the type for a cleanup.
+  if (QualType::DestructionKind dtorKind = D.getType().isDestructedType())
+    emitAutoVarTypeCleanup(emission, dtorKind);
 
   // In GC mode, honor objc_precise_lifetime.
   if (getLangOptions().getGCMode() != LangOptions::NonGC &&
@@ -1084,6 +1097,151 @@
     enterByrefCleanup(emission);
 }
 
+CodeGenFunction::Destroyer &
+CodeGenFunction::getDestroyer(QualType::DestructionKind kind) {
+  switch (kind) {
+  case QualType::DK_none: llvm_unreachable("no destroyer for trivial dtor");
+  case QualType::DK_cxx_destructor: return destroyCXXObject;
+  case QualType::DK_objc_strong_lifetime: return destroyARCStrongPrecise;
+  case QualType::DK_objc_weak_lifetime: return destroyARCWeak;
+  }
+}
+
+void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, llvm::Value *addr,
+                                  QualType type, Destroyer &destroyer) {
+  EHStack.pushCleanup<DestroyObject>(cleanupKind, addr, type, destroyer);
+}
+
+void CodeGenFunction::emitDestroy(llvm::Value *addr, QualType type,
+                                  Destroyer &destroyer) {
+  const ArrayType *arrayType = getContext().getAsArrayType(type);
+  if (!arrayType)
+    return destroyer(*this, addr, type);
+
+  llvm::Value *begin = addr;
+  llvm::Value *length = emitArrayLength(arrayType, type, begin);
+  llvm::Value *end = Builder.CreateInBoundsGEP(begin, length);
+  emitArrayDestroy(begin, end, type, destroyer);
+}
+
+void CodeGenFunction::emitArrayDestroy(llvm::Value *begin,
+                                       llvm::Value *end,
+                                       QualType type,
+                                       Destroyer &destroyer) {
+  assert(!type->isArrayType());
+
+  // The basic structure here is a do-while loop, because we don't
+  // need to check for the zero-element case.
+  llvm::BasicBlock *bodyBB = createBasicBlock("arraydestroy.body");
+  llvm::BasicBlock *doneBB = createBasicBlock("arraydestroy.done");
+
+  // Enter the loop body, making that address the current address.
+  llvm::BasicBlock *entryBB = Builder.GetInsertBlock();
+  EmitBlock(bodyBB);
+  llvm::PHINode *elementPast =
+    Builder.CreatePHI(begin->getType(), 2, "arraydestroy.elementPast");
+  elementPast->addIncoming(end, entryBB);
+
+  // Shift the address back by one element.
+  llvm::Value *negativeOne = llvm::ConstantInt::get(SizeTy, -1, true);
+  llvm::Value *element = Builder.CreateInBoundsGEP(elementPast, negativeOne,
+                                                   "arraydestroy.element");
+
+  // Perform the actual destruction there.
+  destroyer(*this, element, type);
+
+  // Check whether we've reached the end.
+  llvm::Value *done = Builder.CreateICmpEQ(element, begin, "arraydestroy.done");
+  Builder.CreateCondBr(done, doneBB, bodyBB);
+  elementPast->addIncoming(element, Builder.GetInsertBlock());
+
+  // Done.
+  EmitBlock(doneBB);
+}
+
+namespace {
+  class PartialArrayDestroy : 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)
+      : 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);
+    }
+  };
+}
+
+/// pushPartialArrayCleanup - Push a cleanup to destroy
+/// already-constructed elements of the given array.  The cleanup
+/// may be popped with DeactivateCleanupBlock.
+/// 
+/// \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::pushPartialArrayCleanup(llvm::Value *array,
+                                              QualType elementType,
+                                              Destroyer &destroyer,
+                                              llvm::Value *arrayEndPointer) {
+  // FIXME: can this be in a conditional expression?
+  EHStack.pushCleanup<PartialArrayDestroy>(EHCleanup, array, arrayEndPointer,
+                                           elementType, &destroyer);
+}
+
 namespace {
   /// A cleanup to perform a release of an object at the end of a
   /// function.  This is used to balance out the incoming +1 of a

Modified: cfe/trunk/lib/CodeGen/CGExprAgg.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprAgg.cpp?rev=134784&r1=134783&r2=134784&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprAgg.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprAgg.cpp Fri Jul  8 20:37:26 2011
@@ -661,45 +661,132 @@
     }
 
     uint64_t NumArrayElements = AType->getNumElements();
-    QualType ElementType = CGF.getContext().getCanonicalType(E->getType());
-    ElementType = CGF.getContext().getAsArrayType(ElementType)->getElementType();
-    ElementType = CGF.getContext().getQualifiedType(ElementType, 
-                                                    Dest.getQualifiers());
-
-    bool hasNonTrivialCXXConstructor = false;
-    if (CGF.getContext().getLangOptions().CPlusPlus)
-      if (const RecordType *RT = CGF.getContext()
-                        .getBaseElementType(ElementType)->getAs<RecordType>()) {
-        const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
-        hasNonTrivialCXXConstructor = !RD->hasTrivialDefaultConstructor();
-      }
+    assert(NumInitElements <= NumArrayElements);
 
-    for (uint64_t i = 0; i != NumArrayElements; ++i) {
-      // If we're done emitting initializers and the destination is known-zeroed
-      // then we're done.
-      if (i == NumInitElements &&
-          Dest.isZeroed() &&
-          CGF.getTypes().isZeroInitializable(ElementType) &&
-          !hasNonTrivialCXXConstructor)
-        break;
+    QualType elementType = E->getType().getCanonicalType();
+    elementType = CGF.getContext().getQualifiedType(
+                    cast<ArrayType>(elementType)->getElementType(),
+                    elementType.getQualifiers() + Dest.getQualifiers());
+
+    // 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, indices, indices+2, "arrayinit.begin");
+
+    // Exception safety requires us to destroy all the
+    // already-constructed members if an initializer throws.
+    // For that, we'll need an EH cleanup.
+    QualType::DestructionKind dtorKind = elementType.isDestructedType();
+    llvm::AllocaInst *endOfInit = 0;
+    EHScopeStack::stable_iterator cleanup;
+    if (CGF.needsEHCleanup(dtorKind)) {
+      // In principle we could tell the cleanup where we are more
+      // directly, but the control flow can get so varied here that it
+      // would actually be quite complex.  Therefore we go through an
+      // alloca.
+      endOfInit = CGF.CreateTempAlloca(begin->getType(),
+                                       "arrayinit.endOfInit");
+      Builder.CreateStore(begin, endOfInit);
+      CGF.pushPartialArrayCleanup(begin, elementType,
+                                  CGF.getDestroyer(dtorKind), endOfInit);
+      cleanup = CGF.EHStack.stable_begin();
 
-      llvm::Value *NextVal = Builder.CreateStructGEP(DestPtr, i, ".array");
-      LValue LV = CGF.MakeAddrLValue(NextVal, ElementType);
-      
-      if (i < NumInitElements)
-        EmitInitializationToLValue(E->getInit(i), LV);
-      else if (Expr *filler = E->getArrayFiller())
-        EmitInitializationToLValue(filler, LV);
+    // Otherwise, remember that we didn't need a cleanup.
+    } else {
+      dtorKind = QualType::DK_none;
+    }
+
+    llvm::Value *one = llvm::ConstantInt::get(CGF.SizeTy, 1);
+
+    // The 'current element to initialize'.  The invariants on this
+    // variable are complicated.  Essentially, after each iteration of
+    // the loop, it points to the last initialized element, except
+    // that it points to the beginning of the array before any
+    // elements have been initialized.
+    llvm::Value *element = begin;
+
+    // Emit the explicit initializers.
+    for (uint64_t i = 0; i != NumInitElements; ++i) {
+      // Advance to the next element.
+      if (i > 0)
+        element = Builder.CreateInBoundsGEP(element, one, "arrayinit.element");
+
+      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.
+    // Note that this will be a CXXConstructExpr even if the element
+    // type is an array (or array of array, etc.) of class type.
+    Expr *filler = E->getArrayFiller();
+    bool hasTrivialFiller = true;
+    if (CXXConstructExpr *cons = dyn_cast_or_null<CXXConstructExpr>(filler)) {
+      assert(cons->getConstructor()->isDefaultConstructor());
+      hasTrivialFiller = cons->getConstructor()->isTrivial();
+    }
+
+    // Any remaining elements need to be zero-initialized, possibly
+    // using the filler expression.  We can skip this if the we're
+    // emitting to zeroed memory.
+    if (NumInitElements != NumArrayElements &&
+        !(Dest.isZeroed() && hasTrivialFiller &&
+          CGF.getTypes().isZeroInitializable(elementType))) {
+
+      // Use an actual loop.  This is basically
+      //   do { *array++ = filler; } while (array != end);
+
+      // Advance to the start of the rest of the array.
+      if (NumInitElements)
+        element = Builder.CreateInBoundsGEP(element, one, "arrayinit.start");
+
+      // Compute the end of the array.
+      llvm::Value *end = Builder.CreateInBoundsGEP(begin,
+                        llvm::ConstantInt::get(CGF.SizeTy, NumArrayElements),
+                                                   "arrayinit.end");
+
+      llvm::BasicBlock *entryBB = Builder.GetInsertBlock();
+      llvm::BasicBlock *bodyBB = CGF.createBasicBlock("arrayinit.body");
+
+      // Jump into the body.
+      CGF.EmitBlock(bodyBB);
+      llvm::PHINode *currentElement =
+        Builder.CreatePHI(element->getType(), 2, "arrayinit.cur");
+      currentElement->addIncoming(element, entryBB);
+
+      // Emit the actual filler expression.
+      LValue elementLV = CGF.MakeAddrLValue(currentElement, elementType);
+      if (filler)
+        EmitInitializationToLValue(filler, elementLV);
       else
-        EmitNullInitializationToLValue(LV);
-      
-      // If the GEP didn't get used because of a dead zero init or something
-      // else, clean it up for -O0 builds and general tidiness.
-      if (llvm::GetElementPtrInst *GEP =
-            dyn_cast<llvm::GetElementPtrInst>(NextVal))
-        if (GEP->use_empty())
-          GEP->eraseFromParent();
+        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");
+
+      // Leave the loop if we're done.
+      llvm::Value *done = Builder.CreateICmpEQ(nextElement, end,
+                                               "arrayinit.done");
+      llvm::BasicBlock *endBB = CGF.createBasicBlock("arrayinit.end");
+      Builder.CreateCondBr(done, endBB, bodyBB);
+      currentElement->addIncoming(nextElement, Builder.GetInsertBlock());
+
+      CGF.EmitBlock(endBB);
     }
+
+    // Leave the partial-array cleanup if we entered one.
+    if (dtorKind) CGF.DeactivateCleanupBlock(cleanup);
+
     return;
   }
 

Modified: cfe/trunk/lib/CodeGen/CGObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjC.cpp?rev=134784&r1=134783&r2=134784&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjC.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjC.cpp Fri Jul  8 20:37:26 2011
@@ -1807,25 +1807,43 @@
                               getContext().VoidTy, DrainSel, Arg, Args); 
 }
 
+void CodeGenFunction::destroyARCStrongPrecise(CodeGenFunction &CGF,
+                                              llvm::Value *addr,
+                                              QualType type) {
+  llvm::Value *ptr = CGF.Builder.CreateLoad(addr, "strongdestroy");
+  CGF.EmitARCRelease(ptr, /*precise*/ true);
+}
+
+void CodeGenFunction::destroyARCStrongImprecise(CodeGenFunction &CGF,
+                                                llvm::Value *addr,
+                                                QualType type) {
+  llvm::Value *ptr = CGF.Builder.CreateLoad(addr, "strongdestroy");
+  CGF.EmitARCRelease(ptr, /*precise*/ false);  
+}
+
+void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF,
+                                     llvm::Value *addr,
+                                     QualType type) {
+  CGF.EmitARCDestroyWeak(addr);
+}
+
 namespace {
   struct ObjCReleasingCleanup : EHScopeStack::Cleanup {
   private:
     QualType type;
     llvm::Value *addr;
+    CodeGenFunction::Destroyer &destroyer;
 
   protected:
-    ObjCReleasingCleanup(QualType type, llvm::Value *addr)
-      : type(type), addr(addr) {}
+    ObjCReleasingCleanup(QualType type, llvm::Value *addr,
+                         CodeGenFunction::Destroyer *destroyer)
+      : type(type), addr(addr), destroyer(*destroyer) {}
 
     virtual llvm::Value *getAddress(CodeGenFunction &CGF,
                                     llvm::Value *addr) {
       return addr;
     }
 
-    virtual void release(CodeGenFunction &CGF,
-                         QualType type,
-                         llvm::Value *addr) = 0;
-
   public:
     void Emit(CodeGenFunction &CGF, bool isForEH) {
       const ArrayType *arrayType = CGF.getContext().getAsArrayType(type);
@@ -1834,14 +1852,13 @@
 
       // If we don't have an array type, this is easy.
       if (!arrayType)
-        return release(CGF, type, addr);
+        return destroyer(CGF, addr, type);
 
       llvm::Value *begin = addr;
       QualType baseType;
 
       // Otherwise, this is more painful.
-      llvm::Value *count = emitArrayLength(CGF, arrayType, baseType,
-                                           begin);
+      llvm::Value *count = CGF.emitArrayLength(arrayType, baseType, begin);
 
       assert(baseType == CGF.getContext().getBaseElementType(arrayType));
 
@@ -1867,7 +1884,7 @@
       CGF.EmitBlock(bodyBB);
 
       // Release the value at 'cur'.
-      release(CGF, baseType, cur);
+      destroyer(CGF, cur, baseType);
 
       //   ++cur;
       //   goto loopBB;
@@ -1878,112 +1895,18 @@
       // endBB:
       CGF.EmitBlock(endBB);
     }
-
-  private:
-    /// Computes the length of an array in elements, as well
-    /// as the base
-    static llvm::Value *emitArrayLength(CodeGenFunction &CGF,
-                                        const ArrayType *origArrayType,
-                                        QualType &baseType,
-                                        llvm::Value *&addr) {
-      ASTContext &Ctx = CGF.getContext();
-      const ArrayType *arrayType = origArrayType;
-
-      // If it's a VLA, we have to load the stored size.  Note that
-      // this is the size of the VLA in bytes, not its size in elements.
-      llvm::Value *numVLAElements = 0;
-      if (isa<VariableArrayType>(arrayType)) {
-        numVLAElements =
-          CGF.getVLASize(cast<VariableArrayType>(arrayType)).first;
-
-        // Walk into all VLAs.  This doesn't require changes to addr,
-        // which has type T* where T is the first non-VLA element type.
-        do {
-          QualType elementType = arrayType->getElementType();
-          arrayType = Ctx.getAsArrayType(elementType);
-
-          // If we only have VLA components, 'addr' requires no adjustment.
-          if (!arrayType) {
-            baseType = elementType;
-            return numVLAElements;
-          }
-        } while (isa<VariableArrayType>(arrayType));
-
-        // We get out here only if we find a constant array type
-        // inside the VLA.
-      }
-
-      // We have some number of constant-length arrays, so addr should
-      // have LLVM type [M x [N x [...]]]*.  Build a GEP that walks
-      // down to the first element of addr.
-      llvm::SmallVector<llvm::Value*, 8> gepIndices;
-
-      // GEP down to the array type.
-      llvm::ConstantInt *zero = CGF.Builder.getInt32(0);
-      gepIndices.push_back(zero);
-
-      // It's more efficient to calculate the count from the LLVM
-      // constant-length arrays than to re-evaluate the array bounds.
-      uint64_t countFromCLAs = 1;
-
-      const llvm::ArrayType *llvmArrayType =
-        cast<llvm::ArrayType>(
-          cast<llvm::PointerType>(addr->getType())->getElementType());
-      while (true) {
-        assert(isa<ConstantArrayType>(arrayType));
-        assert(cast<ConstantArrayType>(arrayType)->getSize().getZExtValue()
-                 == llvmArrayType->getNumElements());
-
-        gepIndices.push_back(zero);
-        countFromCLAs *= llvmArrayType->getNumElements();
-
-        llvmArrayType =
-          dyn_cast<llvm::ArrayType>(llvmArrayType->getElementType());
-        if (!llvmArrayType) break;
-
-        arrayType = Ctx.getAsArrayType(arrayType->getElementType());
-        assert(arrayType && "LLVM and Clang types are out-of-synch");
-      }
-
-      baseType = arrayType->getElementType();
-
-      // Create the actual GEP.
-      addr = CGF.Builder.CreateInBoundsGEP(addr, gepIndices.begin(),
-                                           gepIndices.end(), "array.begin");
-
-      llvm::Value *numElements
-        = llvm::ConstantInt::get(CGF.IntPtrTy, countFromCLAs);
-
-      // If we had any VLA dimensions, factor them in.
-      if (numVLAElements)
-        numElements = CGF.Builder.CreateNUWMul(numVLAElements, numElements);
-
-      return numElements;
-    }
-
-    static llvm::Value *divideVLASizeByBaseType(CodeGenFunction &CGF,
-                                                llvm::Value *vlaSizeInBytes,
-                                                QualType baseType) {
-      // Divide the base type size back out of the 
-      CharUnits baseSize = CGF.getContext().getTypeSizeInChars(baseType);
-      llvm::Value *baseSizeInBytes =
-        llvm::ConstantInt::get(vlaSizeInBytes->getType(),
-                               baseSize.getQuantity());
-
-      return CGF.Builder.CreateUDiv(vlaSizeInBytes, baseSizeInBytes,
-                                    "array.vla-count");
-    }
   };
 
   /// A cleanup that calls @objc_release on all the objects to release.
   struct CallReleaseForObject : ObjCReleasingCleanup {
-    bool precise;
-    CallReleaseForObject(QualType type, llvm::Value *addr, bool precise)
-      : ObjCReleasingCleanup(type, addr), precise(precise) {}
+    CallReleaseForObject(QualType type, llvm::Value *addr,
+                         CodeGenFunction::Destroyer *destroyer)
+      : ObjCReleasingCleanup(type, addr, destroyer) {}
 
     using ObjCReleasingCleanup::Emit;
     static void Emit(CodeGenFunction &CGF, bool IsForEH,
-                     QualType type, llvm::Value *addr, bool precise) {
+                     QualType type, llvm::Value *addr,
+                     CodeGenFunction::Destroyer *destroyer) {
       // EHScopeStack::Cleanup objects can never have their destructors called,
       // so use placement new to construct our temporary object.
       union {
@@ -1992,15 +1915,10 @@
       };
       
       CallReleaseForObject *Object
-        = new (&align) CallReleaseForObject(type, addr, precise);
+        = new (&align) CallReleaseForObject(type, addr, destroyer);
       Object->Emit(CGF, IsForEH);
       (void)data[0];
     }
-
-    void release(CodeGenFunction &CGF, QualType type, llvm::Value *addr) {
-      llvm::Value *ptr = CGF.Builder.CreateLoad(addr, "tmp");
-      CGF.EmitARCRelease(ptr, precise);
-    }
   };
 
   /// A cleanup that calls @objc_storeStrong(nil) on all the objects to
@@ -2008,7 +1926,8 @@
   struct CallReleaseForIvar : ObjCReleasingCleanup {
     const ObjCIvarDecl *ivar;
     CallReleaseForIvar(const ObjCIvarDecl *ivar, llvm::Value *self)
-      : ObjCReleasingCleanup(ivar->getType(), self), ivar(ivar) {}
+      : ObjCReleasingCleanup(ivar->getType(), self,
+                             destroyARCStrongIvar), ivar(ivar) {}
 
     llvm::Value *getAddress(CodeGenFunction &CGF, llvm::Value *addr) {
       LValue lvalue
@@ -2016,8 +1935,9 @@
       return lvalue.getAddress();
     }
 
-    void release(CodeGenFunction &CGF, QualType type, llvm::Value *addr) {
-      // Release ivars by storing nil into them;  it just makes things easier.
+    static void destroyARCStrongIvar(CodeGenFunction &CGF,
+                                     llvm::Value *addr,
+                                     QualType type) {
       llvm::Value *null = getNullForVariable(addr);
       CGF.EmitARCStoreStrongCall(addr, null, /*ignored*/ true);
     }
@@ -2029,7 +1949,8 @@
     const FieldDecl *Field;
     
     explicit CallReleaseForField(const FieldDecl *Field)
-      : CallReleaseForObject(Field->getType(), 0, /*precise=*/true),
+      : CallReleaseForObject(Field->getType(), 0,
+                             CodeGenFunction::destroyARCStrongPrecise),
         Field(Field) { }
     
     llvm::Value *getAddress(CodeGenFunction &CGF, llvm::Value *) {
@@ -2043,7 +1964,7 @@
   /// release in an object.
   struct CallWeakReleaseForObject : ObjCReleasingCleanup {
     CallWeakReleaseForObject(QualType type, llvm::Value *addr)
-      : ObjCReleasingCleanup(type, addr) {}
+      : ObjCReleasingCleanup(type, addr, CodeGenFunction::destroyARCWeak) {}
 
     using ObjCReleasingCleanup::Emit;
     static void Emit(CodeGenFunction &CGF, bool IsForEH,
@@ -2060,10 +1981,6 @@
       Object->Emit(CGF, IsForEH);
       (void)data[0];
     }
-    
-    void release(CodeGenFunction &CGF, QualType type, llvm::Value *addr) {
-      CGF.EmitARCDestroyWeak(addr);
-    }
   };
 
   
@@ -2129,10 +2046,12 @@
                                             llvm::Value *addr,
                                             bool precise,
                                             bool forFullExpr) {
+  Destroyer *dtor =
+    (precise ? destroyARCStrongPrecise : destroyARCStrongImprecise);
   if (forFullExpr)
-    pushFullExprCleanup<CallReleaseForObject>(cleanupKind, type, addr, precise);
+    pushFullExprCleanup<CallReleaseForObject>(cleanupKind, type, addr, dtor);
   else
-    EHStack.pushCleanup<CallReleaseForObject>(cleanupKind, type, addr, precise);
+    EHStack.pushCleanup<CallReleaseForObject>(cleanupKind, type, addr, dtor);
 }
 
 /// PushARCWeakReleaseCleanup - Enter a cleanup to perform a weak

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=134784&r1=134783&r2=134784&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Fri Jul  8 20:37:26 2011
@@ -785,6 +785,84 @@
   return IndirectBranch->getParent();
 }
 
+/// Computes the length of an array in elements, as well as the base
+/// element type and a properly-typed first element pointer.
+llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType,
+                                              QualType &baseType,
+                                              llvm::Value *&addr) {
+  const ArrayType *arrayType = origArrayType;
+
+  // If it's a VLA, we have to load the stored size.  Note that
+  // this is the size of the VLA in bytes, not its size in elements.
+  llvm::Value *numVLAElements = 0;
+  if (isa<VariableArrayType>(arrayType)) {
+    numVLAElements = getVLASize(cast<VariableArrayType>(arrayType)).first;
+
+    // Walk into all VLAs.  This doesn't require changes to addr,
+    // which has type T* where T is the first non-VLA element type.
+    do {
+      QualType elementType = arrayType->getElementType();
+      arrayType = getContext().getAsArrayType(elementType);
+
+      // If we only have VLA components, 'addr' requires no adjustment.
+      if (!arrayType) {
+        baseType = elementType;
+        return numVLAElements;
+      }
+    } while (isa<VariableArrayType>(arrayType));
+
+    // We get out here only if we find a constant array type
+    // inside the VLA.
+  }
+
+  // We have some number of constant-length arrays, so addr should
+  // have LLVM type [M x [N x [...]]]*.  Build a GEP that walks
+  // down to the first element of addr.
+  llvm::SmallVector<llvm::Value*, 8> gepIndices;
+
+  // GEP down to the array type.
+  llvm::ConstantInt *zero = Builder.getInt32(0);
+  gepIndices.push_back(zero);
+
+  // It's more efficient to calculate the count from the LLVM
+  // constant-length arrays than to re-evaluate the array bounds.
+  uint64_t countFromCLAs = 1;
+
+  const llvm::ArrayType *llvmArrayType =
+    cast<llvm::ArrayType>(
+      cast<llvm::PointerType>(addr->getType())->getElementType());
+  while (true) {
+    assert(isa<ConstantArrayType>(arrayType));
+    assert(cast<ConstantArrayType>(arrayType)->getSize().getZExtValue()
+             == llvmArrayType->getNumElements());
+
+    gepIndices.push_back(zero);
+    countFromCLAs *= llvmArrayType->getNumElements();
+
+    llvmArrayType =
+      dyn_cast<llvm::ArrayType>(llvmArrayType->getElementType());
+    if (!llvmArrayType) break;
+
+    arrayType = getContext().getAsArrayType(arrayType->getElementType());
+    assert(arrayType && "LLVM and Clang types are out-of-synch");
+  }
+
+  baseType = arrayType->getElementType();
+
+  // Create the actual GEP.
+  addr = Builder.CreateInBoundsGEP(addr, gepIndices.begin(),
+                                   gepIndices.end(), "array.begin");
+
+  llvm::Value *numElements
+    = llvm::ConstantInt::get(SizeTy, countFromCLAs);
+
+  // If we had any VLA dimensions, factor them in.
+  if (numVLAElements)
+    numElements = Builder.CreateNUWMul(numVLAElements, numElements);
+
+  return numElements;
+}
+
 std::pair<llvm::Value*, QualType>
 CodeGenFunction::getVLASize(QualType type) {
   const VariableArrayType *vla = getContext().getAsVariableArrayType(type);

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=134784&r1=134783&r2=134784&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Fri Jul  8 20:37:26 2011
@@ -1151,6 +1151,40 @@
   llvm::LLVMContext &getLLVMContext() { return CGM.getLLVMContext(); }
 
   //===--------------------------------------------------------------------===//
+  //                                  Cleanups
+  //===--------------------------------------------------------------------===//
+
+  typedef void Destroyer(CodeGenFunction &CGF, llvm::Value *addr, QualType ty);
+
+  void pushPartialArrayCleanup(llvm::Value *arrayBegin,
+                               QualType elementType,
+                               Destroyer &destroyer,
+                               llvm::Value *arrayEndPointer);
+
+  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);
+  void emitArrayDestroy(llvm::Value *begin, llvm::Value *end,
+                        QualType type, Destroyer &destroyer);
+
+  /// Determines whether an EH cleanup is required to destroy a type
+  /// with the given destruction kind.
+  bool needsEHCleanup(QualType::DestructionKind kind) {
+    switch (kind) {
+    case QualType::DK_none:
+      return false;
+    case QualType::DK_cxx_destructor:
+    case QualType::DK_objc_weak_lifetime:
+      return getLangOptions().Exceptions;
+    case QualType::DK_objc_strong_lifetime:
+      return getLangOptions().Exceptions &&
+             CGM.getCodeGenOpts().ObjCAutoRefCountExceptions;
+    }
+    llvm_unreachable("bad destruction kind");
+  }
+
+  //===--------------------------------------------------------------------===//
   //                                  Objective-C
   //===--------------------------------------------------------------------===//
 
@@ -1526,6 +1560,12 @@
   // instruction in LLVM instead once it works well enough.
   llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty);
 
+  /// emitArrayLength - Compute the length of an array, even if it's a
+  /// VLA, and drill down to the base element type.
+  llvm::Value *emitArrayLength(const ArrayType *arrayType,
+                               QualType &baseType,
+                               llvm::Value *&addr);
+
   /// EmitVLASize - Capture all the sizes for the VLA expressions in
   /// the given variably-modified type and store them in the VLASizeMap.
   ///
@@ -1616,6 +1656,8 @@
                                  const ArrayType *Array,
                                  llvm::Value *This);
 
+  static Destroyer destroyCXXObject;
+
   void EmitCXXAggrDestructorCall(const CXXDestructorDecl *D,
                                  llvm::Value *NumElements,
                                  llvm::Value *This);
@@ -1720,6 +1762,8 @@
   AutoVarEmission EmitAutoVarAlloca(const VarDecl &var);
   void EmitAutoVarInit(const AutoVarEmission &emission);
   void EmitAutoVarCleanups(const AutoVarEmission &emission);  
+  void emitAutoVarTypeCleanup(const AutoVarEmission &emission,
+                              QualType::DestructionKind dtorKind);
 
   void EmitStaticVarDecl(const VarDecl &D,
                          llvm::GlobalValue::LinkageTypes Linkage);
@@ -2101,8 +2145,20 @@
   void PushARCReleaseCleanup(CleanupKind kind, QualType type,
                              llvm::Value *addr, bool precise,
                              bool forFullExpr = false);
+  void PushARCArrayReleaseCleanup(CleanupKind kind, QualType elementType,
+                                  llvm::Value *addr,
+                                  llvm::Value *countOrCountPtr,
+                                  bool precise, bool forFullExpr = false);
   void PushARCWeakReleaseCleanup(CleanupKind kind, QualType type,
                                  llvm::Value *addr, bool forFullExpr = false);
+  void PushARCArrayWeakReleaseCleanup(CleanupKind kind, QualType elementType,
+                                      llvm::Value *addr,
+                                      llvm::Value *countOrCountPtr,
+                                      bool forFullExpr = false);
+  static Destroyer destroyARCStrongImprecise;
+  static Destroyer destroyARCStrongPrecise;
+  static Destroyer destroyARCWeak;
+
   void PushARCFieldReleaseCleanup(CleanupKind cleanupKind,
                                   const FieldDecl *Field);
   void PushARCFieldWeakReleaseCleanup(CleanupKind cleanupKind,

Modified: cfe/trunk/test/CodeGenCXX/destructors.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/destructors.cpp?rev=134784&r1=134783&r2=134784&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/destructors.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/destructors.cpp Fri Jul  8 20:37:26 2011
@@ -233,27 +233,16 @@
 namespace test5 {
   struct A { ~A(); };
 
-  // This is really unnecessarily verbose; we should be using phis,
-  // even at -O0.
-
   // CHECK: define void @_ZN5test53fooEv()
   // CHECK:      [[ELEMS:%.*]] = alloca [5 x [[A:%.*]]], align
-  // CHECK-NEXT: [[IVAR:%.*]] = alloca i64
-  // CHECK:      [[ELEMSARRAY:%.*]] = bitcast [5 x [[A]]]* [[ELEMS]] to [[A]]
-  // CHECK-NEXT: store i64 5, i64* [[IVAR]]
-  // CHECK-NEXT: br label
-  // CHECK:      [[I:%.*]] = load i64* [[IVAR]]
-  // CHECK-NEXT: icmp ne i64 [[I]], 0
-  // CHECK-NEXT: br i1
-  // CHECK:      [[I:%.*]] = load i64* [[IVAR]]
-  // CHECK-NEXT: [[I2:%.*]] = sub i64 [[I]], 1
-  // CHECK-NEXT: getelementptr inbounds [[A]]* [[ELEMSARRAY]], i64 [[I2]]
-  // CHECK-NEXT: call void @_ZN5test51AD1Ev(
-  // CHECK-NEXT: br label
-  // CHECK:      [[I:%.*]] = load i64* [[IVAR]]
-  // CHECK-NEXT: [[I1:%.*]] = sub i64 [[I]], 1
-  // CHECK-NEXT: store i64 [[I1]], i64* [[IVAR]]
+  // 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: br i1 [[T0]],
   // CHECK:      ret void
   void foo() {
     A elems[5];

Modified: cfe/trunk/test/CodeGenCXX/temporaries.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/temporaries.cpp?rev=134784&r1=134783&r2=134784&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/temporaries.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/temporaries.cpp Fri Jul  8 20:37:26 2011
@@ -421,28 +421,24 @@
   void test4() {
     // CHECK:      [[X:%.*]] = alloca [[A]], align 8
     // CHECK-NEXT: [[XS:%.*]] = alloca [2 x [[A]]], align 16
-    // CHECK-NEXT: [[I:%.*]] = alloca i64
 
     // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[X]])
     A x;
 
-    // CHECK-NEXT: [[XS0:%.*]] = getelementptr inbounds [2 x [[A]]]* [[XS]], i32 0, i32 0
+    // CHECK-NEXT: [[XS0:%.*]] = getelementptr inbounds [2 x [[A]]]* [[XS]], i64 0, i64 0
     // CHECK-NEXT: call void @_ZN7Elision1AC1Ev([[A]]* [[XS0]])
-    // CHECK-NEXT: [[XS1:%.*]] = getelementptr inbounds [2 x [[A]]]* [[XS]], i32 0, i32 1
+    // CHECK-NEXT: [[XS1:%.*]] = getelementptr inbounds [[A]]* [[XS0]], i64 1
     // CHECK-NEXT: call void @_ZN7Elision1AC1ERKS0_([[A]]* [[XS1]], [[A]]* [[X]])
-    // CHECK-NEXT: [[XSB:%.*]] = bitcast [2 x [[A]]]* [[XS]] to [[A]]*
     A xs[] = { A(), x };
 
-    // CHECK-NEXT: store i64 2, i64* [[I]]
-    // CHECK-NEXT: br label
-    // CHECK:      [[I0:%.*]] = load i64* [[I]]
-    // CHECK-NEXT: icmp ne i64 [[I0]], 0
-    // CHECK-NEXT: br i1
-    // CHECK:      [[I1:%.*]] = load i64* [[I]]
-    // CHECK-NEXT: [[I2:%.*]] = sub i64 [[I1]], 1
-    // CHECK-NEXT: [[XSI:%.*]] = getelementptr inbounds [[A]]* [[XSB]], i64 [[I2]]
-    // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[XSI]])
+    // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [2 x [[A]]]* [[XS]], i32 0, i32 0
+    // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 2
     // CHECK-NEXT: br label
+    // CHECK:      [[AFTER:%.*]] = phi [[A]]*
+    // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]]* [[AFTER]], i64 -1
+    // CHECK-NEXT: call void @_ZN7Elision1AD1Ev([[A]]* [[CUR]])
+    // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[CUR]], [[BEGIN]]
+    // CHECK-NEXT: br i1 [[T0]],
 
     // CHECK:      call void @_ZN7Elision1AD1Ev([[A]]* [[X]])
   }

Modified: cfe/trunk/test/CodeGenCXX/value-init.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/value-init.cpp?rev=134784&r1=134783&r2=134784&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/value-init.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/value-init.cpp Fri Jul  8 20:37:26 2011
@@ -105,34 +105,24 @@
   // CHECK: call void @_ZN6PR98014TestC1Ei
   // CHECK-NOT: call void @llvm.memset.p0i8.i64
   // CHECK: call void @_ZN6PR98014TestC1Ev
-  // CHECK-NOT: call void @llvm.memset.p0i8.i64
-  // CHECK: call void @_ZN6PR98014TestC1Ev
   Test partial[3] = { 1 };
 
   // CHECK-NOT: call void @llvm.memset.p0i8.i64
   // CHECK: call void @_ZN6PR98014TestC1Ev
-  // CHECK-NOT: call void @llvm.memset.p0i8.i64
-  // CHECK: call void @_ZN6PR98014TestC1Ev
-  // CHECK-NOT: call void @llvm.memset.p0i8.i64
-  // CHECK: call void @_ZN6PR98014TestC1Ev
+  // CHECK-NOT: call void @_ZN6PR98014TestC1Ev
   Test empty[3] = {};
 
   // CHECK: call void @llvm.memset.p0i8.i64
   // CHECK-NOT: call void @llvm.memset.p0i8.i64
   // CHECK: call void @_ZN6PR98015Test2C1Ev
-  // CHECK-NOT: call void @llvm.memset.p0i8.i64
-  // CHECK: call void @_ZN6PR98015Test2C1Ev
-  // CHECK-NOT: call void @llvm.memset.p0i8.i64
-  // CHECK: call void @_ZN6PR98015Test2C1Ev
+  // CHECK-NOT: call void @_ZN6PR98015Test2C1Ev
   Test2 empty2[3] = {};
 
   // CHECK: call void @llvm.memset.p0i8.i64
   // CHECK-NOT: call void @llvm.memset.p0i8.i64
   // CHECK: call void @_ZN6PR98015Test3C1Ev
   // CHECK-NOT: call void @llvm.memset.p0i8.i64
-  // CHECK: call void @_ZN6PR98015Test3C1Ev
-  // CHECK-NOT: call void @llvm.memset.p0i8.i64
-  // CHECK: call void @_ZN6PR98015Test3C1Ev
+  // CHECK-NOT: call void @_ZN6PR98015Test3C1Ev
   Test3 empty3[3] = {};
 }
 
@@ -189,10 +179,7 @@
     X3<int>().f();
   }
 
-  // CHECK: define linkonce_odr void @_ZN8zeroinit2X3IiEC2Ev(%"struct.zeroinit::X3"* %this) unnamed_addr
-  // CHECK: call void @llvm.memset.p0i8.i64
-  // CHECK-NEXT: call void @_ZN8zeroinit2X2IiEC2Ev
-  // CHECK-NEXT: ret void
+  // More checks at EOF
 }
 
 namespace PR8726 {
@@ -207,3 +194,58 @@
 }
 
 }
+
+// rdar://problem/9355931
+namespace test6 {
+  struct A { A(); A(int); };
+
+  void test() {
+    A arr[10][20] = { 5 };
+  };
+  // CHECK:    define void @_ZN5test64testEv()
+  // CHECK:      [[ARR:%.*]] = alloca [10 x [20 x [[A:%.*]]]],
+  // CHECK-NEXT: [[IDX:%.*]] = alloca i64
+
+  // CHECK-NEXT: [[INNER:%.*]] = getelementptr inbounds [10 x [20 x [[A]]]]* [[ARR]], i64 0, i64 0
+  // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [20 x [[A]]]* [[INNER]], i64 0, i64 0
+  // CHECK-NEXT: call void @_ZN5test61AC1Ei([[A]]* [[T0]], i32 5)
+  // CHECK-NEXT: [[BEGIN:%.*]] = getelementptr inbounds [[A]]* [[T0]], i64 1
+  // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [[A]]* [[T0]], i64 20
+  // CHECK-NEXT: br label
+  // CHECK:      [[CUR:%.*]] = phi [[A]]* [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ]
+  // CHECK-NEXT: call void @_ZN5test61AC1Ev([[A]]* [[CUR]])
+  // CHECK-NEXT: [[NEXT]] = getelementptr inbounds [[A]]* [[CUR]], i64 1
+  // CHECK-NEXT: [[T0:%.*]] = icmp eq [[A]]* [[NEXT]], [[END]]
+  // CHECK-NEXT: br i1
+
+  // CHECK:      [[BEGIN:%.*]] = getelementptr inbounds [20 x [[A]]]* [[INNER]], i64 1
+  // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [20 x [[A]]]* [[INNER]], i64 10
+  // CHECK-NEXT: br label
+  // CHECK:      [[CUR:%.*]] = phi [20 x [[A]]]* [ [[BEGIN]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ]
+  // CHECK-NEXT: [[FIRST:%.*]] = bitcast [20 x [[A]]]* [[CUR]] to [[A]]*
+
+  // TODO: this loop should use phis, too, and for preference would be
+  // merged with the outer loop.
+  // CHECK-NEXT: store i64 0, i64* [[IDX]]
+  // CHECK-NEXT: br label
+  // CHECK:      [[T0:%.*]] = load i64* [[IDX]]
+  // CHECK-NEXT: [[T1:%.*]] = icmp ult i64 [[T0]], 20
+  // CHECK-NEXT: br i1 [[T1]]
+  // CHECK:      [[T0:%.*]] = load i64* [[IDX]]
+  // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[A]]* [[FIRST]], i64 [[T0]]
+  // CHECK-NEXT: call void @_ZN5test61AC1Ev([[A]]* [[T1]])
+  // CHECK-NEXT: br label
+  // CHECK:      [[T0:%.*]] = load i64* [[IDX]]
+  // CHECK-NEXT: [[T1:%.*]] = add i64 [[T0]], 1
+  // CHECK-NEXT: store i64 [[T1]], i64* [[IDX]]
+  // CHECK-NEXT: br label
+  // CHECK:      [[NEXT]] = getelementptr inbounds [20 x [[A]]]* [[CUR]], i64 1
+  // CHECK-NEXT: [[T0:%.*]] = icmp eq [20 x [[A]]]* [[NEXT]], [[END]]
+  // CHECK-NEXT: br i1 [[T0]]
+  // CHECK:      ret void
+}
+
+// CHECK: define linkonce_odr void @_ZN8zeroinit2X3IiEC2Ev(%"struct.zeroinit::X3"* %this) unnamed_addr
+// CHECK: call void @llvm.memset.p0i8.i64
+// CHECK-NEXT: call void @_ZN8zeroinit2X2IiEC2Ev
+// CHECK-NEXT: ret void

Modified: cfe/trunk/test/CodeGenObjC/arc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/arc.m?rev=134784&r1=134783&r2=134784&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/arc.m (original)
+++ cfe/trunk/test/CodeGenObjC/arc.m Fri Jul  8 20:37:26 2011
@@ -475,14 +475,12 @@
   // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 5
   // CHECK-NEXT: br label
 
-  // CHECK:      [[CUR:%.*]] = phi i8**
-  // CHECK-NEXT: [[EQ:%.*]] = icmp eq i8** [[CUR]], [[END]]
-  // CHECK-NEXT: br i1 [[EQ]],
-
-  // CHECK:      [[T0:%.*]] = load i8** [[CUR]]
+  // CHECK:      [[AFTER:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[NEXT:%.*]], {{%.*}} ]
+  // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds i8** [[AFTER]], i64 -1
+  // CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]]
   // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
-  // CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds i8** [[CUR]], i32 1
-  // CHECK-NEXT: br label
+  // CHECK-NEXT: [[EQ:%.*]] = icmp eq i8** [[CUR]], [[BEGIN]]
+  // CHECK-NEXT: br i1 [[EQ]],
 
   // CHECK:      ret void
 }
@@ -515,14 +513,12 @@
   // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[VLA]], i64 [[DIM]]
   // CHECK-NEXT: br label
 
-  // CHECK:      [[CUR:%.*]] = phi i8**
-  // CHECK-NEXT: [[EQ:%.*]] = icmp eq i8** [[CUR]], [[END]]
-  // CHECK-NEXT: br i1 [[EQ]],
-
-  // CHECK:      [[T0:%.*]] = load i8** [[CUR]]
+  // CHECK:      [[AFTER:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ]
+  // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds i8** [[AFTER]], i64 -1
+  // CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]]
   // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
-  // CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds i8** [[CUR]], i32 1
-  // CHECK-NEXT: br label
+  // CHECK-NEXT: [[EQ:%.*]] = icmp eq i8** [[CUR]], [[VLA]]
+  // CHECK-NEXT: br i1 [[EQ]],
 
   // CHECK:      [[T0:%.*]] = load i8** [[SAVED_STACK]]
   // CHECK-NEXT: call void @llvm.stackrestore(i8* [[T0]])
@@ -562,14 +558,12 @@
   // CHECK-NEXT: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 [[T1]]
   // CHECK-NEXT: br label
 
-  // CHECK:      [[CUR:%.*]] = phi i8**
-  // CHECK-NEXT: [[EQ:%.*]] = icmp eq i8** [[CUR]], [[END]]
-  // CHECK-NEXT: br i1 [[EQ]],
-
-  // CHECK:      [[T0:%.*]] = load i8** [[CUR]]
+  // CHECK:      [[AFTER:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ]
+  // CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds i8** [[AFTER]], i64 -1
+  // CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]]
   // CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
-  // CHECK-NEXT: [[NEXT:%.*]] = getelementptr inbounds i8** [[CUR]], i32 1
-  // CHECK-NEXT: br label
+  // CHECK-NEXT: [[EQ:%.*]] = icmp eq i8** [[CUR]], [[BEGIN]]
+  // CHECK-NEXT: br i1 [[EQ]],
 
   // CHECK:      [[T0:%.*]] = load i8** [[SAVED_STACK]]
   // CHECK-NEXT: call void @llvm.stackrestore(i8* [[T0]])
@@ -1120,7 +1114,7 @@
 
   // CHECK: br label
   // CHECK: call void @objc_release
-  // CHECK: br label
+  // CHECK: br i1
 
   // CHECK: call void @objc_release
   // CHECK-NEXT: ret void





More information about the cfe-commits mailing list