forked from OSchip/llvm-project
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:
parent
21e9051922
commit
ca2c56f20b
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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]])
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue