зеркало из 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 {
|
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
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче