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
This commit is contained in:
John McCall 2011-08-03 22:24:24 +00:00
Родитель 6ec60e00ee
Коммит bddfd87863
2 изменённых файлов: 56 добавлений и 48 удалений

Просмотреть файл

@ -1273,33 +1273,11 @@ llvm::Value *CodeGenFunction::EmitObjCProduceObject(QualType type,
namespace { namespace {
struct CallObjCRelease : EHScopeStack::Cleanup { struct CallObjCRelease : EHScopeStack::Cleanup {
CallObjCRelease(QualType type, llvm::Value *ptr, llvm::Value *condition) CallObjCRelease(llvm::Value *object) : object(object) {}
: type(type), ptr(ptr), condition(condition) {} llvm::Value *object;
QualType type;
llvm::Value *ptr;
llvm::Value *condition;
void Emit(CodeGenFunction &CGF, Flags flags) { 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); CGF.EmitARCRelease(object, /*precise*/ true);
if (cont) CGF.EmitBlock(cont);
} }
}; };
} }
@ -1309,27 +1287,8 @@ namespace {
llvm::Value *CodeGenFunction::EmitObjCConsumeObject(QualType type, llvm::Value *CodeGenFunction::EmitObjCConsumeObject(QualType type,
llvm::Value *object) { llvm::Value *object) {
// If we're in a conditional branch, we need to make the cleanup // If we're in a conditional branch, we need to make the cleanup
// conditional. FIXME: this really needs to be supported by the // conditional.
// environment. pushFullExprCleanup<CallObjCRelease>(getARCCleanupKind(), object);
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);
return object; return object;
} }

Просмотреть файл

@ -578,18 +578,18 @@ void test22(_Bool cond) {
// CHECK: define void @test22( // CHECK: define void @test22(
// CHECK: [[COND:%.*]] = alloca i8, // CHECK: [[COND:%.*]] = alloca i8,
// CHECK-NEXT: [[X:%.*]] = alloca i8*, // CHECK-NEXT: [[X:%.*]] = alloca i8*,
// CHECK-NEXT: [[RELCOND:%.*]] = alloca i1
// CHECK-NEXT: [[RELVAL:%.*]] = alloca i8* // CHECK-NEXT: [[RELVAL:%.*]] = alloca i8*
// CHECK-NEXT: store i1 false, i1* [[RELCOND]] // CHECK-NEXT: [[RELCOND:%.*]] = alloca i1
// CHECK-NEXT: zext // CHECK-NEXT: zext
// CHECK-NEXT: store // CHECK-NEXT: store
// CHECK-NEXT: [[T0:%.*]] = load i8* [[COND]] // CHECK-NEXT: [[T0:%.*]] = load i8* [[COND]]
// CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1 // CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1
// CHECK-NEXT: store i1 false, i1* [[RELCOND]]
// CHECK-NEXT: br i1 [[T1]], // CHECK-NEXT: br i1 [[T1]],
// CHECK: br label // CHECK: br label
// CHECK: [[CALL:%.*]] = call i8* @test22_helper() // CHECK: [[CALL:%.*]] = call i8* @test22_helper()
// CHECK-NEXT: store i1 true, i1* [[RELCOND]]
// CHECK-NEXT: store i8* [[CALL]], i8** [[RELVAL]] // CHECK-NEXT: store i8* [[CALL]], i8** [[RELVAL]]
// CHECK-NEXT: store i1 true, i1* [[RELCOND]]
// CHECK-NEXT: br label // CHECK-NEXT: br label
// CHECK: [[T0:%.*]] = phi i8* [ null, {{%.*}} ], [ [[CALL]], {{%.*}} ] // CHECK: [[T0:%.*]] = phi i8* [ null, {{%.*}} ], [ [[CALL]], {{%.*}} ]
// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) nounwind // 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: call void @objc_release(i8* [[T0]])
// CHECK-NEXT: ret void // 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
}