diff options
Diffstat (limited to 'test/CodeGenObjC/arc-blocks.m')
-rw-r--r-- | test/CodeGenObjC/arc-blocks.m | 133 |
1 files changed, 124 insertions, 9 deletions
diff --git a/test/CodeGenObjC/arc-blocks.m b/test/CodeGenObjC/arc-blocks.m index 2326bce2be25..e77651714e55 100644 --- a/test/CodeGenObjC/arc-blocks.m +++ b/test/CodeGenObjC/arc-blocks.m @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-optzns -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-UNOPT %s // This shouldn't crash. void test0(id (^maker)(void)) { @@ -41,6 +42,24 @@ void test2(id x) { // CHECK-NEXT: ret void extern void test2_helper(id (^)(void)); test2_helper(^{ return x; }); + +// CHECK: define internal void @__copy_helper_block_ +// CHECK: [[T0:%.*]] = load i8** +// CHECK-NEXT: [[SRC:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* +// CHECK-NEXT: [[T0:%.*]] = load i8** +// CHECK-NEXT: [[DST:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* +// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[SRC]], i32 0, i32 5 +// CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]] +// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) nounwind +// CHECK-NEXT: ret void + +// CHECK: define internal void @__destroy_helper_block_ +// CHECK: [[T0:%.*]] = load i8** +// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* +// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[T1]], i32 0, i32 5 +// CHECK-NEXT: [[T3:%.*]] = load i8** [[T2]] +// CHECK-NEXT: call void @objc_release(i8* [[T3]]) +// CHECK-NEXT: ret void } void test3(void (^sink)(id*)) { @@ -99,8 +118,8 @@ void test4(void) { // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) // CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]] // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6 - // 0x42000000 - has signature, copy/dispose helpers - // CHECK: store i32 1107296256, + // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT + // CHECK: store i32 -1040187392, // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* // CHECK-NEXT: store i8* [[T0]], i8** // CHECK: call void @test4_helper( @@ -151,8 +170,8 @@ void test5(void) { // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) // CHECK-NEXT: store i8* [[T1]], i8** [[VAR]], // CHECK-NEXT: call void @objc_release(i8* [[T1]]) - // 0x40000000 - has signature but no copy/dispose - // CHECK: store i32 1073741824, i32* + // 0x40800000 - has signature but no copy/dispose, as well as BLOCK_HAS_EXTENDED_LAYOUT + // CHECK: store i32 -1073741824, i32* // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 // CHECK-NEXT: [[T0:%.*]] = load i8** [[VAR]] // CHECK-NEXT: store i8* [[T0]], i8** [[CAPTURE]] @@ -179,8 +198,8 @@ void test6(void) { // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T1]]) // CHECK-NEXT: call void @objc_release(i8* [[T1]]) // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6 - // 0x42000000 - has signature, copy/dispose helpers - // CHECK: store i32 1107296256, + // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT + // CHECK: store i32 -1040187392, // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* // CHECK-NEXT: store i8* [[T0]], i8** // CHECK: call void @test6_helper( @@ -228,8 +247,8 @@ void test7(void) { // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]]) // CHECK-NEXT: call i8* @objc_initWeak(i8** [[VAR]], i8* [[T1]]) // CHECK-NEXT: call void @objc_release(i8* [[T1]]) - // 0x42000000 - has signature, copy/dispose helpers - // CHECK: store i32 1107296256, + // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT + // CHECK: store i32 -1040187392, // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[VAR]]) // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T0]]) @@ -359,7 +378,7 @@ void test10a(void) { // CHECK: [[T0:%.*]] = load i8** {{%.*}} // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BYREF_T]]* // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T1]], i32 0, i32 6 -// CHECK-NEXT: [[T3:%.*]] = load void ()** [[T2]], align 8 +// CHECK-NEXT: [[T3:%.*]] = load void ()** [[T2]] // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8* // CHECK-NEXT: call void @objc_release(i8* [[T4]]) // CHECK-NEXT: ret void @@ -532,3 +551,99 @@ void test16() { // CHECK-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 // CHECK-NEXT: store void ()* null, void ()** [[BLKVAR]], align 8 } + +// rdar://12151005 +// +// This is an intentional exception to our conservative jump-scope +// checking for full-expressions containing block literals with +// non-trivial cleanups: if the block literal appears in the operand +// of a return statement, there's no need to extend its lifetime. +id (^test17(id self, int which))(void) { + switch (which) { + case 1: return ^{ return self; }; + case 0: return ^{ return self; }; + } + return (void*) 0; +} +// CHECK: define i8* ()* @test17( +// CHECK: [[RET:%.*]] = alloca i8* ()*, align +// CHECK-NEXT: [[SELF:%.*]] = alloca i8*, +// CHECK: [[B0:%.*]] = alloca [[BLOCK:<.*>]], align +// CHECK: [[B1:%.*]] = alloca [[BLOCK]], align +// CHECK: [[T0:%.*]] = call i8* @objc_retain(i8* +// CHECK-NEXT: store i8* [[T0]], i8** [[SELF]], align +// CHECK-NOT: objc_retain +// CHECK-NOT: objc_release +// CHECK: [[DESTROY:%.*]] = getelementptr inbounds [[BLOCK]]* [[B0]], i32 0, i32 5 +// CHECK-NOT: objc_retain +// CHECK-NOT: objc_release +// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK]]* [[B0]], i32 0, i32 5 +// CHECK-NEXT: [[T1:%.*]] = load i8** [[SELF]], align +// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) +// CHECK-NEXT: store i8* [[T2]], i8** [[T0]], +// CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK]]* [[B0]] to i8* ()* +// CHECK-NEXT: [[T1:%.*]] = bitcast i8* ()* [[T0]] to i8* +// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) +// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i8* ()* +// CHECK-NEXT: store i8* ()* [[T3]], i8* ()** [[RET]] +// CHECK-NEXT: [[T0:%.*]] = load i8** [[DESTROY]] +// CHECK-NEXT: call void @objc_release(i8* [[T0]]) +// CHECK-NEXT: store i32 +// CHECK-NEXT: br label +// CHECK-NOT: objc_retain +// CHECK-NOT: objc_release +// CHECK: [[DESTROY:%.*]] = getelementptr inbounds [[BLOCK]]* [[B1]], i32 0, i32 5 +// CHECK-NOT: objc_retain +// CHECK-NOT: objc_release +// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK]]* [[B1]], i32 0, i32 5 +// CHECK-NEXT: [[T1:%.*]] = load i8** [[SELF]], align +// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) +// CHECK-NEXT: store i8* [[T2]], i8** [[T0]], +// CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK]]* [[B1]] to i8* ()* +// CHECK-NEXT: [[T1:%.*]] = bitcast i8* ()* [[T0]] to i8* +// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) +// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i8* ()* +// CHECK-NEXT: store i8* ()* [[T3]], i8* ()** [[RET]] +// CHECK-NEXT: [[T0:%.*]] = load i8** [[DESTROY]] +// CHECK-NEXT: call void @objc_release(i8* [[T0]]) +// CHECK-NEXT: store i32 +// CHECK-NEXT: br label + +void test18(id x) { +// CHECK-UNOPT: define void @test18( +// CHECK-UNOPT: [[X:%.*]] = alloca i8*, +// CHECK-UNOPT-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], +// CHECK-UNOPT-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}}) +// CHECK-UNOPT-NEXT: store i8* [[PARM]], i8** [[X]] +// CHECK-UNOPT-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 +// CHECK-UNOPT: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 +// CHECK-UNOPT-NEXT: [[T0:%.*]] = load i8** [[X]], +// CHECK-UNOPT-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]]) +// CHECK-UNOPT-NEXT: store i8* [[T1]], i8** [[SLOT]], +// CHECK-UNOPT-NEXT: bitcast +// CHECK-UNOPT-NEXT: call void @test18_helper( +// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[SLOTREL]], i8* null) nounwind +// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null) nounwind +// CHECK-UNOPT-NEXT: ret void + extern void test18_helper(id (^)(void)); + test18_helper(^{ return x; }); + +// CHECK-UNOPT: define internal void @__copy_helper_block_ +// CHECK-UNOPT: [[T0:%.*]] = load i8** +// CHECK-UNOPT-NEXT: [[SRC:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* +// CHECK-UNOPT-NEXT: [[T0:%.*]] = load i8** +// CHECK-UNOPT-NEXT: [[DST:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* +// CHECK-UNOPT-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[SRC]], i32 0, i32 5 +// CHECK-UNOPT-NEXT: [[T1:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[DST]], i32 0, i32 5 +// CHECK-UNOPT-NEXT: [[T2:%.*]] = load i8** [[T0]] +// CHECK-UNOPT-NEXT: store i8* null, i8** [[T1]] +// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[T1]], i8* [[T2]]) nounwind +// CHECK-UNOPT-NEXT: ret void + +// CHECK-UNOPT: define internal void @__destroy_helper_block_ +// CHECK-UNOPT: [[T0:%.*]] = load i8** +// CHECK-UNOPT-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* +// CHECK-UNOPT-NEXT: [[T2:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[T1]], i32 0, i32 5 +// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null) +// CHECK-UNOPT-NEXT: ret void +} |