diff options
author | John McCall <rjmccall@apple.com> | 2011-08-03 22:24:24 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-08-03 22:24:24 +0000 |
commit | bddfd87863bac7aa17d226cdfb228f49b30dd5f2 (patch) | |
tree | 01b5fb2c297be925eac67c8be0802082a8c18140 | |
parent | 6ec60e00eeaaed78d98c85ce962d6f328094ca14 (diff) |
Use the general conditional-cleanup framework instead of rolling our
own, incorrectly, for releasing objects at the end of a full-expression.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@136823 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/CodeGen/CGObjC.cpp | 49 | ||||
-rw-r--r-- | test/CodeGenObjC/arc.m | 55 |
2 files changed, 56 insertions, 48 deletions
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 817966ccd6..a51a8705f4 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -1273,33 +1273,11 @@ llvm::Value *CodeGenFunction::EmitObjCProduceObject(QualType type, namespace { struct CallObjCRelease : EHScopeStack::Cleanup { - CallObjCRelease(QualType type, llvm::Value *ptr, llvm::Value *condition) - : type(type), ptr(ptr), condition(condition) {} - QualType type; - llvm::Value *ptr; - llvm::Value *condition; + CallObjCRelease(llvm::Value *object) : object(object) {} + llvm::Value *object; void Emit(CodeGenFunction &CGF, Flags flags) { - llvm::Value *object; - - // If we're in a conditional branch, we had to stash away in an - // alloca the pointer to be released. - llvm::BasicBlock *cont = 0; - if (condition) { - llvm::BasicBlock *release = CGF.createBasicBlock("release.yes"); - cont = CGF.createBasicBlock("release.cont"); - - llvm::Value *cond = CGF.Builder.CreateLoad(condition); - CGF.Builder.CreateCondBr(cond, release, cont); - CGF.EmitBlock(release); - object = CGF.Builder.CreateLoad(ptr); - } else { - object = ptr; - } - CGF.EmitARCRelease(object, /*precise*/ true); - - if (cont) CGF.EmitBlock(cont); } }; } @@ -1309,27 +1287,8 @@ namespace { llvm::Value *CodeGenFunction::EmitObjCConsumeObject(QualType type, llvm::Value *object) { // If we're in a conditional branch, we need to make the cleanup - // conditional. FIXME: this really needs to be supported by the - // environment. - llvm::AllocaInst *cond; - llvm::Value *ptr; - if (isInConditionalBranch()) { - cond = CreateTempAlloca(Builder.getInt1Ty(), "release.cond"); - ptr = CreateTempAlloca(object->getType(), "release.value"); - - // The alloca is false until we get here. - // FIXME: er. doesn't this need to be set at the start of the condition? - InitTempAlloca(cond, Builder.getFalse()); - - // Then it turns true. - Builder.CreateStore(Builder.getTrue(), cond); - Builder.CreateStore(object, ptr); - } else { - cond = 0; - ptr = object; - } - - EHStack.pushCleanup<CallObjCRelease>(getARCCleanupKind(), type, ptr, cond); + // conditional. + pushFullExprCleanup<CallObjCRelease>(getARCCleanupKind(), object); return object; } diff --git a/test/CodeGenObjC/arc.m b/test/CodeGenObjC/arc.m index 4592710a3d..7883b0ebaf 100644 --- a/test/CodeGenObjC/arc.m +++ b/test/CodeGenObjC/arc.m @@ -578,18 +578,18 @@ void test22(_Bool cond) { // CHECK: define void @test22( // CHECK: [[COND:%.*]] = alloca i8, // CHECK-NEXT: [[X:%.*]] = alloca i8*, - // CHECK-NEXT: [[RELCOND:%.*]] = alloca i1 // CHECK-NEXT: [[RELVAL:%.*]] = alloca i8* - // CHECK-NEXT: store i1 false, i1* [[RELCOND]] + // CHECK-NEXT: [[RELCOND:%.*]] = alloca i1 // CHECK-NEXT: zext // CHECK-NEXT: store // CHECK-NEXT: [[T0:%.*]] = load i8* [[COND]] // CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1 + // CHECK-NEXT: store i1 false, i1* [[RELCOND]] // CHECK-NEXT: br i1 [[T1]], // CHECK: br label // CHECK: [[CALL:%.*]] = call i8* @test22_helper() - // CHECK-NEXT: store i1 true, i1* [[RELCOND]] // CHECK-NEXT: store i8* [[CALL]], i8** [[RELVAL]] + // CHECK-NEXT: store i1 true, i1* [[RELCOND]] // CHECK-NEXT: br label // CHECK: [[T0:%.*]] = phi i8* [ null, {{%.*}} ], [ [[CALL]], {{%.*}} ] // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) nounwind @@ -1790,3 +1790,52 @@ void test61(void) { // CHECK-NEXT: call void @objc_release(i8* [[T0]]) // CHECK-NEXT: ret void } + +// rdar://problem/9891815 +void test62(void) { + // CHECK: define void @test62() + // CHECK: [[I:%.*]] = alloca i32, align 4 + // CHECK-NEXT: [[CLEANUP_VALUE:%.*]] = alloca i8* + // CHECK-NEXT: [[CLEANUP_REQUIRED:%.*]] = alloca i1 + extern id test62_make(void); + extern void test62_body(void); + + // CHECK-NEXT: store i32 0, i32* [[I]], align 4 + // CHECK-NEXT: br label + + // CHECK: [[T0:%.*]] = load i32* [[I]], align 4 + // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 20 + // CHECK-NEXT: br i1 [[T1]], + + for (unsigned i = 0; i != 20; ++i) { + // CHECK: [[T0:%.*]] = load i32* [[I]], align 4 + // CHECK-NEXT: [[T1:%.*]] = icmp ne i32 [[T0]], 0 + // CHECK-NEXT: store i1 false, i1* [[CLEANUP_REQUIRED]] + // CHECK-NEXT: br i1 [[T1]], + // CHECK: [[T0:%.*]] = call i8* @test62_make() + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) + // CHECK-NEXT: store i8* [[T1]], i8** [[CLEANUP_VALUE]] + // CHECK-NEXT: store i1 true, i1* [[CLEANUP_REQUIRED]] + // CHECK-NEXT: [[T2:%.*]] = icmp ne i8* [[T1]], null + // CHECK-NEXT: br label + // CHECK: [[COND:%.*]] = phi i1 [ false, {{%.*}} ], [ [[T2]], {{%.*}} ] + // CHECK-NEXT: [[T0:%.*]] = load i1* [[CLEANUP_REQUIRED]] + // CHECK-NEXT: br i1 [[T0]], + // CHECK: [[T0:%.*]] = load i8** [[CLEANUP_VALUE]] + // CHECK-NEXT: call void @objc_release(i8* [[T0]]) + // CHECK-NEXT: br label + // CHECK: br i1 [[COND]] + // CHECK: call void @test62_body() + // CHECK-NEXT: br label + // CHECK: br label + if (i != 0 && test62_make() != 0) + test62_body(); + } + + // CHECK: [[T0:%.*]] = load i32* [[I]], align 4 + // CHECK-NEXT: [[T1:%.*]] = add i32 [[T0]], 1 + // CHECK-NEXT: store i32 [[T1]], i32* [[I]] + // CHECK-NEXT: br label + + // CHECK: ret void +} |