Switch delete[] IR-generation over to the destroy framework,

which implicitly makes it EH-safe as well.

llvm-svn: 135025
This commit is contained in:
John McCall 2011-07-13 01:41:37 +00:00
parent 21e9051922
commit ca2c56f20b
3 changed files with 68 additions and 107 deletions

View File

@ -1351,90 +1351,50 @@ namespace {
/// Emit the code for deleting an array of objects.
static void EmitArrayDelete(CodeGenFunction &CGF,
const CXXDeleteExpr *E,
llvm::Value *Ptr,
QualType ElementType) {
llvm::Value *NumElements = 0;
llvm::Value *AllocatedPtr = 0;
CharUnits CookieSize;
CGF.CGM.getCXXABI().ReadArrayCookie(CGF, Ptr, E, ElementType,
NumElements, AllocatedPtr, CookieSize);
llvm::Value *deletedPtr,
QualType elementType) {
llvm::Value *numElements = 0;
llvm::Value *allocatedPtr = 0;
CharUnits cookieSize;
CGF.CGM.getCXXABI().ReadArrayCookie(CGF, deletedPtr, E, elementType,
numElements, allocatedPtr, cookieSize);
assert(AllocatedPtr && "ReadArrayCookie didn't set AllocatedPtr");
assert(allocatedPtr && "ReadArrayCookie didn't set allocated pointer");
// Make sure that we call delete even if one of the dtors throws.
const FunctionDecl *OperatorDelete = E->getOperatorDelete();
const FunctionDecl *operatorDelete = E->getOperatorDelete();
CGF.EHStack.pushCleanup<CallArrayDelete>(NormalAndEHCleanup,
AllocatedPtr, OperatorDelete,
NumElements, ElementType,
CookieSize);
allocatedPtr, operatorDelete,
numElements, elementType,
cookieSize);
if (const CXXRecordDecl *RD = ElementType->getAsCXXRecordDecl()) {
if (!RD->hasTrivialDestructor()) {
assert(NumElements && "ReadArrayCookie didn't find element count"
" for a class with destructor");
CGF.EmitCXXAggrDestructorCall(RD->getDestructor(), NumElements, Ptr);
}
} else if (CGF.getLangOptions().ObjCAutoRefCount &&
ElementType->isObjCLifetimeType() &&
(ElementType.getObjCLifetime() == Qualifiers::OCL_Strong ||
ElementType.getObjCLifetime() == Qualifiers::OCL_Weak)) {
bool IsStrong = ElementType.getObjCLifetime() == Qualifiers::OCL_Strong;
const llvm::Type *SizeLTy = CGF.ConvertType(CGF.getContext().getSizeType());
llvm::Value *One = llvm::ConstantInt::get(SizeLTy, 1);
// Create a temporary for the loop index and initialize it with count of
// array elements.
llvm::Value *IndexPtr = CGF.CreateTempAlloca(SizeLTy, "loop.index");
// Store the number of elements in the index pointer.
CGF.Builder.CreateStore(NumElements, IndexPtr);
// Start the loop with a block that tests the condition.
llvm::BasicBlock *CondBlock = CGF.createBasicBlock("for.cond");
llvm::BasicBlock *AfterFor = CGF.createBasicBlock("for.end");
CGF.EmitBlock(CondBlock);
llvm::BasicBlock *ForBody = CGF.createBasicBlock("for.body");
// Generate: if (loop-index != 0 fall to the loop body,
// otherwise, go to the block after the for-loop.
llvm::Value* zeroConstant = llvm::Constant::getNullValue(SizeLTy);
llvm::Value *Counter = CGF.Builder.CreateLoad(IndexPtr);
llvm::Value *IsNE = CGF.Builder.CreateICmpNE(Counter, zeroConstant,
"isne");
// If the condition is true, execute the body.
CGF.Builder.CreateCondBr(IsNE, ForBody, AfterFor);
CGF.EmitBlock(ForBody);
llvm::BasicBlock *ContinueBlock = CGF.createBasicBlock("for.inc");
// Inside the loop body, emit the constructor call on the array element.
Counter = CGF.Builder.CreateLoad(IndexPtr);
Counter = CGF.Builder.CreateSub(Counter, One);
llvm::Value *Address = CGF.Builder.CreateInBoundsGEP(Ptr, Counter,
"arrayidx");
if (IsStrong)
CGF.EmitARCRelease(CGF.Builder.CreateLoad(Address,
ElementType.isVolatileQualified()),
/*precise*/ true);
else
CGF.EmitARCDestroyWeak(Address);
CGF.EmitBlock(ContinueBlock);
// Emit the decrement of the loop counter.
Counter = CGF.Builder.CreateLoad(IndexPtr);
Counter = CGF.Builder.CreateSub(Counter, One, "dec");
CGF.Builder.CreateStore(Counter, IndexPtr);
// Finally, branch back up to the condition for the next iteration.
CGF.EmitBranch(CondBlock);
// Emit the fall-through block.
CGF.EmitBlock(AfterFor, true);
// Destroy the elements.
if (QualType::DestructionKind dtorKind = elementType.isDestructedType()) {
assert(numElements && "no element count for a type with a destructor!");
// It's legal to allocate a zero-length array, but emitArrayDestroy
// won't handle that correctly, so we need to check that here.
llvm::Value *iszero =
CGF.Builder.CreateIsNull(numElements, "delete.isempty");
// We'll patch the 'true' successor of this to lead to the end of
// the emitArrayDestroy loop.
llvm::BasicBlock *destroyBB = CGF.createBasicBlock("delete.destroy");
llvm::BranchInst *br =
CGF.Builder.CreateCondBr(iszero, destroyBB, destroyBB);
CGF.EmitBlock(destroyBB);
llvm::Value *arrayEnd =
CGF.Builder.CreateInBoundsGEP(deletedPtr, numElements, "delete.end");
CGF.emitArrayDestroy(deletedPtr, arrayEnd, elementType,
CGF.getDestroyer(dtorKind),
CGF.needsEHCleanup(dtorKind));
assert(CGF.Builder.GetInsertBlock()->empty());
br->setSuccessor(0, CGF.Builder.GetInsertBlock());
}
// Pop the cleanup block.
CGF.PopCleanupBlock();
}

View File

@ -67,31 +67,23 @@ namespace test1 {
// CHECK: define void @_ZN5test14testEPA10_A20_NS_1AE(
void test(A (*arr)[10][20]) {
delete [] arr;
// CHECK: icmp eq [10 x [20 x [[S:%.*]]]]* [[PTR:%.*]], null
// CHECK: icmp eq [10 x [20 x [[A:%.*]]]]* [[PTR:%.*]], null
// CHECK-NEXT: br i1
// CHECK: [[ARR:%.*]] = getelementptr inbounds [10 x [20 x [[S]]]]* [[PTR]], i32 0, i32 0, i32 0
// CHECK-NEXT: bitcast {{.*}} to i8*
// CHECK-NEXT: [[ALLOC:%.*]] = getelementptr inbounds {{.*}}, i64 -8
// CHECK-NEXT: bitcast i8* [[ALLOC]] to i64*
// CHECK-NEXT: load
// CHECK-NEXT: store i64 {{.*}}, i64* [[IDX:%.*]]
// CHECK: load i64* [[IDX]]
// CHECK-NEXT: icmp ne {{.*}}, 0
// CHECK-NEXT: br i1
// CHECK: load i64* [[IDX]]
// CHECK-NEXT: [[I:%.*]] = sub i64 {{.*}}, 1
// CHECK-NEXT: getelementptr inbounds [[S]]* [[ARR]], i64 [[I]]
// CHECK-NEXT: call void @_ZN5test11AD1Ev(
// CHECK: [[BEGIN:%.*]] = getelementptr inbounds [10 x [20 x [[A]]]]* [[PTR]], i32 0, i32 0, i32 0
// CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[BEGIN]] to i8*
// CHECK-NEXT: [[ALLOC:%.*]] = getelementptr inbounds i8* [[T0]], i64 -8
// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[ALLOC]] to i64*
// CHECK-NEXT: [[COUNT:%.*]] = load i64* [[T1]]
// CHECK-NEXT: [[ISZERO:%.*]] = icmp eq i64 [[COUNT]], 0
// CHECK-NEXT: br i1 [[ISZERO]],
// CHECK: [[END:%.*]] = getelementptr inbounds [[A]]* [[BEGIN]], i64 [[COUNT]]
// CHECK-NEXT: br label
// CHECK: load i64* [[IDX]]
// CHECK-NEXT: sub
// CHECK-NEXT: store {{.*}}, i64* [[IDX]]
// CHECK-NEXT: br label
// CHECK: [[PAST:%.*]] = phi [[A]]* [ [[END]], {{%.*}} ], [ [[CUR:%.*]], {{%.*}} ]
// CHECK-NEXT: [[CUR:%.*]] = getelementptr inbounds [[A]]* [[PAST]], i64 -1
// CHECK-NEXT: call void @_ZN5test11AD1Ev([[A]]* [[CUR]])
// CHECK-NEXT: [[ISDONE:%.*]] = icmp eq [[A]]* [[CUR]], [[BEGIN]]
// CHECK-NEXT: br i1 [[ISDONE]]
// CHECK: call void @_ZdaPv(i8* [[ALLOC]])
}
}

View File

@ -70,17 +70,26 @@ void test_delete(__strong id *sptr, __weak id *wptr) {
// CHECK: define void @_Z17test_array_deletePU8__strongP11objc_objectPU6__weakS0_
void test_array_delete(__strong id *sptr, __weak id *wptr) {
// CHECK: load i64*
// CHECK: {{icmp ne i64.*, 0}}
// CHECK: call void @objc_release
// CHECK: br label
// CHECK: icmp eq i8** [[BEGIN:%.*]], null
// CHECK: [[LEN:%.*]] = load i64* {{%.*}}
// CHECK: icmp eq i64 [[LEN]], 0
// CHECK: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 [[LEN]]
// CHECK: [[PAST:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]],
// CHECK-NEXT: [[CUR]] = getelementptr inbounds i8** [[PAST]], i64 -1
// CHECK-NEXT: [[T0:%.*]] = load i8** [[CUR]]
// CHECK-NEXT: call void @objc_release(i8* [[T0]])
// CHECK-NEXT: icmp eq i8** [[CUR]], [[BEGIN]]
// CHECK: call void @_ZdaPv
delete [] sptr;
// CHECK: load i64*
// CHECK: {{icmp ne i64.*, 0}}
// CHECK: call void @objc_destroyWeak
// CHECK: br label
// CHECK: icmp eq i8** [[BEGIN:%.*]], null
// CHECK: [[LEN:%.*]] = load i64* {{%.*}}
// CHECK: icmp eq i64 [[LEN]], 0
// CHECK: [[END:%.*]] = getelementptr inbounds i8** [[BEGIN]], i64 [[LEN]]
// CHECK: [[PAST:%.*]] = phi i8** [ [[END]], {{%.*}} ], [ [[CUR:%.*]],
// CHECK-NEXT: [[CUR]] = getelementptr inbounds i8** [[PAST]], i64 -1
// CHECK-NEXT: call void @objc_destroyWeak(i8** [[CUR]])
// CHECK-NEXT: icmp eq i8** [[CUR]], [[BEGIN]]
// CHECK: call void @_ZdaPv
delete [] wptr;
}