aboutsummaryrefslogtreecommitdiff
path: root/test/CodeGenObjC/arc-blocks.m
diff options
context:
space:
mode:
Diffstat (limited to 'test/CodeGenObjC/arc-blocks.m')
-rw-r--r--test/CodeGenObjC/arc-blocks.m133
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
+}