diff options
author | John McCall <rjmccall@apple.com> | 2011-11-10 09:22:44 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2011-11-10 09:22:44 +0000 |
commit | b99785bdd1cc9ce1ba4f94eeb871faba1a22e95f (patch) | |
tree | 8a0ad8ac3de7a387af04d5796cc17b8cbc6bcf74 | |
parent | c430ef4f92eedea7d3378f05a2b05982ed3713dc (diff) |
Fix a subtle bug with cleanups: when activating
a previously-inactive cleanup, not only do we need a
flag variable, but we should also force the cleanup to
query the flag variable. However, we only need to do
this when we're activating in a context that's
conditionally executed; otherwise, we may safely
assume that the cleanup is dominated by the activation
point.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@144271 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/CodeGen/CGCleanup.cpp | 23 | ||||
-rw-r--r-- | test/CodeGenCXX/blocks.cpp | 50 | ||||
-rw-r--r-- | test/CodeGenObjC/arc-blocks.m | 61 | ||||
-rw-r--r-- | test/CodeGenObjC/arc-foreach.m | 9 |
4 files changed, 121 insertions, 22 deletions
diff --git a/lib/CodeGen/CGCleanup.cpp b/lib/CodeGen/CGCleanup.cpp index b2d0786cb6..9e079c65d2 100644 --- a/lib/CodeGen/CGCleanup.cpp +++ b/lib/CodeGen/CGCleanup.cpp @@ -1003,27 +1003,32 @@ static void SetupCleanupBlockActivation(CodeGenFunction &CGF, ForActivation_t Kind) { EHCleanupScope &Scope = cast<EHCleanupScope>(*CGF.EHStack.find(C)); - // We always need the flag if we're activating the cleanup, because - // we have to assume that the current location doesn't necessarily - // dominate all future uses of the cleanup. - bool NeedFlag = (Kind == ForActivation); + // We always need the flag if we're activating the cleanup in a + // conditional context, because we have to assume that the current + // location doesn't necessarily dominate the cleanup's code. + bool isActivatedInConditional = + (Kind == ForActivation && CGF.isInConditionalBranch()); + + bool needFlag = false; // Calculate whether the cleanup was used: // - as a normal cleanup - if (Scope.isNormalCleanup() && IsUsedAsNormalCleanup(CGF.EHStack, C)) { + if (Scope.isNormalCleanup() && + (isActivatedInConditional || IsUsedAsNormalCleanup(CGF.EHStack, C))) { Scope.setTestFlagInNormalCleanup(); - NeedFlag = true; + needFlag = true; } // - as an EH cleanup - if (Scope.isEHCleanup() && IsUsedAsEHCleanup(CGF.EHStack, C)) { + if (Scope.isEHCleanup() && + (isActivatedInConditional || IsUsedAsEHCleanup(CGF.EHStack, C))) { Scope.setTestFlagInEHCleanup(); - NeedFlag = true; + needFlag = true; } // If it hasn't yet been used as either, we're done. - if (!NeedFlag) return; + if (!needFlag) return; llvm::AllocaInst *Var = Scope.getActiveFlag(); if (!Var) { diff --git a/test/CodeGenCXX/blocks.cpp b/test/CodeGenCXX/blocks.cpp index cc56525e1d..e3160a0394 100644 --- a/test/CodeGenCXX/blocks.cpp +++ b/test/CodeGenCXX/blocks.cpp @@ -128,3 +128,53 @@ namespace test4 { // CHECK-NEXT: ret void } +namespace test5 { + struct A { + unsigned afield; + A(); + A(const A&); + ~A(); + void foo() const; + }; + + void doWithBlock(void(^)()); + + void test(bool cond) { + A x; + void (^b)() = (cond ? ^{ x.foo(); } : (void(^)()) 0); + doWithBlock(b); + } + + // CHECK: define void @_ZN5test54testEb( + // CHECK: [[COND:%.*]] = alloca i8 + // CHECK-NEXT: [[X:%.*]] = alloca [[A:%.*]], align 4 + // CHECK-NEXT: [[B:%.*]] = alloca void ()*, align 8 + // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align 8 + // CHECK-NEXT: [[CLEANUP_ACTIVE:%.*]] = alloca i1 + // CHECK-NEXT: store i1 false, i1* [[CLEANUP_ACTIVE]] + // CHECK-NEXT: [[T0:%.*]] = zext i1 + // CHECK-NEXT: store i8 [[T0]], i8* [[COND]], align 1 + // CHECK-NEXT: call void @_ZN5test51AC1Ev([[A]]* [[X]]) + // CHECK-NEXT: [[CLEANUP_ADDR:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 + // CHECK-NEXT: [[T0:%.*]] = load i8* [[COND]], align 1 + // CHECK-NEXT: [[T1:%.*]] = trunc i8 [[T0]] to i1 + // CHECK-NEXT: br i1 [[T1]], + + // CHECK-NOT: br + // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 + // CHECK-NEXT: call void @_ZN5test51AC1ERKS0_([[A]]* [[CAPTURE]], [[A]]* [[X]]) + // CHECK-NEXT: store i1 true, i1* [[CLEANUP_ACTIVE]] + // CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* + // CHECK-NEXT: br label + // CHECK: br label + // CHECK: phi + // CHECK-NEXT: store + // CHECK-NEXT: load + // CHECK-NEXT: call void @_ZN5test511doWithBlockEU13block_pointerFvvE( + // CHECK-NEXT: [[T0:%.*]] = load i1* [[CLEANUP_ACTIVE]] + // CHECK-NEXT: br i1 [[T0]] + // CHECK: call void @_ZN5test51AD1Ev([[A]]* [[CLEANUP_ADDR]]) + // CHECK-NEXT: br label + // CHECK: call void @_ZN5test51AD1Ev([[A]]* [[X]]) + // CHECK-NEXT: ret void +} diff --git a/test/CodeGenObjC/arc-blocks.m b/test/CodeGenObjC/arc-blocks.m index 6ca5c3c352..c14380cced 100644 --- a/test/CodeGenObjC/arc-blocks.m +++ b/test/CodeGenObjC/arc-blocks.m @@ -25,8 +25,6 @@ void test2(id x) { // CHECK: define void @test2( // CHECK: [[X:%.*]] = alloca i8*, // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], -// CHECK-NEXT: alloca i1 -// CHECK-NEXT: store i1 false // CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}}) // CHECK-NEXT: store i8* [[PARM]], i8** [[X]] // CHECK-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 @@ -34,7 +32,6 @@ void test2(id x) { // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]], // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) // CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]], -// CHECK-NEXT: store i1 true // CHECK-NEXT: bitcast // CHECK-NEXT: call void @test2_helper( // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOTREL]] @@ -238,7 +235,7 @@ void test7(void) { // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T0]]) // CHECK: call void @test7_helper( // CHECK-NEXT: call void @objc_destroyWeak(i8** {{%.*}}) - // CHECK: call void @objc_destroyWeak(i8** [[VAR]]) + // CHECK-NEXT: call void @objc_destroyWeak(i8** [[VAR]]) // CHECK-NEXT: ret void // CHECK: define internal void @__test7_block_invoke_ @@ -273,7 +270,6 @@ void test7(void) { // CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]]) // CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST8]]* // CHECK-NEXT: store [[TEST8]]* [[T4]], [[TEST8]]** [[T0]] -// CHECK-NEXT: store i1 true, // CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to // CHECK: call void @test8_helper( // CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]** [[D0]] @@ -288,7 +284,7 @@ void test7(void) { id test9(void) { typedef id __attribute__((ns_returns_retained)) blocktype(void); - extern test9_consume_block(blocktype^); + extern void test9_consume_block(blocktype^); return ^blocktype { extern id test9_produce(void); return test9_produce(); @@ -461,3 +457,56 @@ void test11b(void) { // CHECK: define internal void @"\01-[Test12 setNblock:]"( // CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext false, i1 zeroext true) @end + +// rdar://problem/10131784 +void test13(id x) { + extern void test13_helper(id); + extern void test13_use(void(^)(void)); + + void (^b)(void) = (x ? ^{test13_helper(x);} : 0); + test13_use(b); + + // CHECK: define void @test13( + // CHECK: [[X:%.*]] = alloca i8*, align 8 + // CHECK-NEXT: [[B:%.*]] = alloca void ()*, align 8 + // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align 8 + // CHECK-NEXT: [[CLEANUP_ACTIVE:%.*]] = alloca i1 + // CHECK-NEXT: store i1 false, i1* [[CLEANUP_ACTIVE]] + // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* {{%.*}}) + // CHECK-NEXT: store i8* [[T0]], i8** [[X]], align 8 + // CHECK-NEXT: [[CLEANUP_ADDR:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 + // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]], align 8 + // CHECK-NEXT: [[T1:%.*]] = icmp ne i8* [[T0]], null + // CHECK-NEXT: br i1 [[T1]], + + // CHECK-NOT: br + // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 + // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]], align 8 + // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) + // CHECK-NEXT: store i8* [[T1]], i8** [[CAPTURE]], align 8 + // CHECK-NEXT: store i1 true, i1* [[CLEANUP_ACTIVE]] + // CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* + // CHECK-NEXT: br label + // CHECK: br label + // CHECK: [[T0:%.*]] = phi void ()* + // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* + // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) + // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()* + // CHECK-NEXT: store void ()* [[T3]], void ()** [[B]], align 8 + // CHECK-NEXT: [[T0:%.*]] = load void ()** [[B]], align 8 + // CHECK-NEXT: call void @test13_use(void ()* [[T0]]) + // CHECK-NEXT: [[T0:%.*]] = load void ()** [[B]] + // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* + // CHECK-NEXT: call void @objc_release(i8* [[T1]]) + + // CHECK-NEXT: [[T0:%.*]] = load i1* [[CLEANUP_ACTIVE]] + // CHECK-NEXT: br i1 [[T0]] + // CHECK: [[T0:%.*]] = load i8** [[CLEANUP_ADDR]] + // CHECK-NEXT: call void @objc_release(i8* [[T0]]) + // CHECK-NEXT: br label + + // CHECK: [[T0:%.*]] = load i8** [[X]] + // CHECK-NEXT: call void @objc_release(i8* [[T0]]) + // CHECK-NEXT: ret void +} + diff --git a/test/CodeGenObjC/arc-foreach.m b/test/CodeGenObjC/arc-foreach.m index de550328f0..67fad4d9b0 100644 --- a/test/CodeGenObjC/arc-foreach.m +++ b/test/CodeGenObjC/arc-foreach.m @@ -29,9 +29,6 @@ void test0(NSArray *array) { // CHECK-LP64-NEXT: [[BUFFER:%.*]] = alloca [16 x i8*], align 8 // CHECK-LP64-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], -// CHECK-LP64-NEXT: [[CAP_ACTIVE:%.*]] = alloca i1 -// CHECK-LP64-NEXT: store i1 false, i1* [[CAP_ACTIVE]] - // Initialize 'array'. // CHECK-LP64-NEXT: [[T0:%.*]] = bitcast [[ARRAY_T:%.*]]* {{%.*}} to i8* // CHECK-LP64-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) @@ -68,7 +65,6 @@ void test0(NSArray *array) { // CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[X]] // CHECK-LP64-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) // CHECK-LP64-NEXT: store i8* [[T2]], i8** [[T0]] -// CHECK-LP64-NEXT: store i1 true, i1* [[CAP_ACTIVE]] // CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] // CHECK-LP64: call void @use_block( // CHECK-LP64-NEXT: [[T1:%.*]] = load i8** [[D0]] @@ -117,11 +113,10 @@ void test1(NSArray *array) { // CHECK-LP64: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 // CHECK-LP64-NEXT: [[T1:%.*]] = call i8* @objc_loadWeak(i8** [[X]]) // CHECK-LP64-NEXT: call i8* @objc_initWeak(i8** [[T0]], i8* [[T1]]) -// CHECK-LP64-NEXT: store i1 true, // CHECK-LP64-NEXT: [[T1:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to // CHECK-LP64: call void @use_block -// CHECK-LP64: call void @objc_destroyWeak(i8** [[D0]]) -// CHECK-LP64: call void @objc_destroyWeak(i8** [[X]]) +// CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[D0]]) +// CHECK-LP64-NEXT: call void @objc_destroyWeak(i8** [[X]]) // rdar://problem/9817306 @interface Test2 |