1 | // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fobjc-runtime=macosx-10.10 -emit-llvm -fblocks -fobjc-weak -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-MODERN |
2 | // RUN: %clang_cc1 -triple i386-apple-darwin10 -fobjc-runtime=macosx-fragile-10.10 -emit-llvm -fblocks -fobjc-weak -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-FRAGILE |
3 | |
4 | @interface Object |
5 | - (instancetype) retain; |
6 | - (void) run; |
7 | @end |
8 | |
9 | // CHECK-MODERN: @OBJC_CLASS_NAME_{{.*}} = {{.*}} c"\01\00" |
10 | // CHECK-MODERN: @"\01l_OBJC_CLASS_RO_$_Foo" = {{.*}} { i32 772 |
11 | // 772 == 0x304 |
12 | // ^ HasMRCWeakIvars |
13 | // ^ HasCXXDestructorOnly |
14 | // ^ HasCXXStructors |
15 | |
16 | // CHECK-FRAGILE: @OBJC_CLASS_NAME_{{.*}} = {{.*}} c"\01\00" |
17 | // CHECK-FRAGILE: @OBJC_CLASS_Foo = {{.*}} i32 134225921, |
18 | // 134225921 == 0x08002001 |
19 | // ^ HasMRCWeakIvars |
20 | // ^ HasCXXStructors |
21 | // ^ Factory |
22 | @interface Foo : Object { |
23 | __weak id ivar; |
24 | } |
25 | @end |
26 | |
27 | @implementation Foo |
28 | // CHECK-LABEL: define internal void @"\01-[Foo .cxx_destruct]" |
29 | // CHECK: call void @llvm.objc.destroyWeak |
30 | @end |
31 | |
32 | |
33 | void test1(__weak id x) {} |
34 | // CHECK-LABEL: define void @_Z5test1P11objc_object( |
35 | // CHECK: [[X:%.*]] = alloca i8*, |
36 | // CHECK-NEXT: llvm.objc.initWeak |
37 | // CHECK-NEXT: llvm.objc.destroyWeak |
38 | // CHECK-NEXT: ret void |
39 | |
40 | void test2(id y) { |
41 | __weak id z = y; |
42 | } |
43 | // CHECK-LABEL: define void @_Z5test2P11objc_object( |
44 | // CHECK: [[Y:%.*]] = alloca i8*, |
45 | // CHECK-NEXT: [[Z:%.*]] = alloca i8*, |
46 | // CHECK-NEXT: store |
47 | // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]] |
48 | // CHECK-NEXT: call i8* @llvm.objc.initWeak(i8** [[Z]], i8* [[T0]]) |
49 | // CHECK-NEXT: call void @llvm.objc.destroyWeak(i8** [[Z]]) |
50 | // CHECK-NEXT: ret void |
51 | |
52 | void test3(id y) { |
53 | __weak id z; |
54 | z = y; |
55 | } |
56 | // CHECK-LABEL: define void @_Z5test3P11objc_object( |
57 | // CHECK: [[Y:%.*]] = alloca i8*, |
58 | // CHECK-NEXT: [[Z:%.*]] = alloca i8*, |
59 | // CHECK-NEXT: store |
60 | // CHECK-NEXT: store i8* null, i8** [[Z]] |
61 | // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[Y]] |
62 | // CHECK-NEXT: call i8* @llvm.objc.storeWeak(i8** [[Z]], i8* [[T0]]) |
63 | // CHECK-NEXT: call void @llvm.objc.destroyWeak(i8** [[Z]]) |
64 | // CHECK-NEXT: ret void |
65 | |
66 | void test4(__weak id *p) { |
67 | id y = *p; |
68 | } |
69 | // CHECK-LABEL: define void @_Z5test4PU6__weakP11objc_object( |
70 | // CHECK: [[P:%.*]] = alloca i8**, |
71 | // CHECK-NEXT: [[Y:%.*]] = alloca i8*, |
72 | // CHECK-NEXT: store |
73 | // CHECK-NEXT: [[T0:%.*]] = load i8**, i8*** [[P]] |
74 | // CHECK-NEXT: [[T1:%.*]] = call i8* @llvm.objc.loadWeak(i8** [[T0]]) |
75 | // CHECK-NEXT: store i8* [[T1]], i8** [[Y]] |
76 | // CHECK-NEXT: ret void |
77 | |
78 | void test5(__weak id *p) { |
79 | id y = [*p retain]; |
80 | } |
81 | // CHECK-LABEL: define void @_Z5test5PU6__weakP11objc_object |
82 | // CHECK: [[P:%.*]] = alloca i8**, |
83 | // CHECK-NEXT: [[Y:%.*]] = alloca i8*, |
84 | // CHECK-NEXT: store |
85 | // CHECK-NEXT: [[T0:%.*]] = load i8**, i8*** [[P]] |
86 | // CHECK-NEXT: [[T1:%.*]] = call i8* @llvm.objc.loadWeakRetained(i8** [[T0]]) |
87 | // CHECK-NEXT: store i8* [[T1]], i8** [[Y]] |
88 | // CHECK-NEXT: ret void |
89 | |
90 | void test6(__weak Foo **p) { |
91 | Foo *y = [*p retain]; |
92 | } |
93 | // CHECK-LABEL: define void @_Z5test6PU6__weakP3Foo |
94 | // CHECK: [[P:%.*]] = alloca [[FOO:%.*]]**, |
95 | // CHECK-NEXT: [[Y:%.*]] = alloca [[FOO]]*, |
96 | // CHECK-NEXT: store |
97 | // CHECK-NEXT: [[T0:%.*]] = load [[FOO]]**, [[FOO]]*** [[P]] |
98 | // CHECK-NEXT: [[T1:%.*]] = bitcast [[FOO]]** [[T0]] to i8** |
99 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.loadWeakRetained(i8** [[T1]]) |
100 | // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to [[FOO]]* |
101 | // CHECK-NEXT: store [[FOO]]* [[T3]], [[FOO]]** [[Y]] |
102 | // CHECK-NEXT: ret void |
103 | |
104 | extern "C" id get_object(void); |
105 | extern "C" void use_block(void (^)(void)); |
106 | |
107 | void test7(void) { |
108 | __weak Foo *p = get_object(); |
109 | use_block(^{ [p run ]; }); |
110 | } |
111 | // CHECK-LABEL: define void @_Z5test7v |
112 | // CHECK: [[P:%.*]] = alloca [[FOO]]*, |
113 | // CHECK: [[T0:%.*]] = call i8* @get_object() |
114 | // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[FOO]]* |
115 | // CHECK-NEXT: [[T2:%.*]] = bitcast [[FOO]]** [[P]] to i8** |
116 | // CHECK-NEXT: [[T3:%.*]] = bitcast [[FOO]]* [[T1]] to i8* |
117 | // CHECK-NEXT: call i8* @llvm.objc.initWeak(i8** [[T2]], i8* [[T3]]) |
118 | // CHECK: call void @llvm.objc.copyWeak |
119 | // CHECK: call void @use_block |
120 | // CHECK: call void @llvm.objc.destroyWeak |
121 | |
122 | // CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block |
123 | // CHECK: @llvm.objc.copyWeak |
124 | |
125 | // CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block |
126 | // CHECK: @llvm.objc.destroyWeak |
127 | |
128 | void test8(void) { |
129 | __block __weak Foo *p = get_object(); |
130 | use_block(^{ [p run ]; }); |
131 | } |
132 | // CHECK-LABEL: define void @_Z5test8v |
133 | // CHECK: call i8* @llvm.objc.initWeak |
134 | // CHECK-NOT: call void @llvm.objc.copyWeak |
135 | // CHECK: call void @use_block |
136 | // CHECK: call void @llvm.objc.destroyWeak |
137 | |
138 | // CHECK-LABEL: define internal void @__Block_byref_object_copy |
139 | // CHECK: call void @llvm.objc.moveWeak |
140 | |
141 | // CHECK-LABEL: define internal void @__Block_byref_object_dispose |
142 | // CHECK: call void @llvm.objc.destroyWeak |
143 | |
144 | // CHECK-LABEL: define void @_Z14test9_baselinev() |
145 | // CHECK: define linkonce_odr hidden void @__copy_helper |
146 | // CHECK: define linkonce_odr hidden void @__destroy_helper |
147 | void test9_baseline(void) { |
148 | Foo *p = get_object(); |
149 | use_block(^{ [p run]; }); |
150 | } |
151 | |
152 | // CHECK-LABEL: define void @_Z5test9v() |
153 | // CHECK-NOT: define internal void @__copy_helper |
154 | // CHECK-NOT: define internal void @__destroy_helper |
155 | // CHECK: define void @_Z9test9_finv() |
156 | void test9(void) { |
157 | __unsafe_unretained Foo *p = get_object(); |
158 | use_block(^{ [p run]; }); |
159 | } |
160 | void test9_fin() {} |
161 | |
162 | // CHECK-LABEL: define void @_Z6test10v() |
163 | // CHECK-NOT: define internal void @__copy_helper |
164 | // CHECK-NOT: define internal void @__destroy_helper |
165 | // CHECK: define void @_Z10test10_finv() |
166 | void test10(void) { |
167 | typedef __unsafe_unretained Foo *UnsafeFooPtr; |
168 | UnsafeFooPtr p = get_object(); |
169 | use_block(^{ [p run]; }); |
170 | } |
171 | void test10_fin() {} |
172 | |
173 | // CHECK-LABEL: define weak_odr void @_Z6test11ILj0EEvv() |
174 | // CHECK-NOT: define internal void @__copy_helper |
175 | // CHECK-NOT: define internal void @__destroy_helper |
176 | // CHECK: define void @_Z10test11_finv() |
177 | template <unsigned i> void test11(void) { |
178 | typedef __unsafe_unretained Foo *UnsafeFooPtr; |
179 | UnsafeFooPtr p = get_object(); |
180 | use_block(^{ [p run]; }); |
181 | } |
182 | template void test11<0>(); |
183 | void test11_fin() {} |
184 | |