[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