зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
6ec60e00ee
Коммит
bddfd87863
|
@ -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;
|
||||
|
||||
void Emit(CodeGenFunction &CGF, Flags flags) {
|
||||
CallObjCRelease(llvm::Value *object) : object(object) {}
|
||||
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;
|
||||
}
|
||||
|
||||
void Emit(CodeGenFunction &CGF, Flags flags) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче