1 | // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -O2 -disable-llvm-passes -o - %s | FileCheck -check-prefix=CHECK -check-prefix=CHECK-COMMON %s |
2 | // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -fblocks -fobjc-arc -fobjc-runtime-has-weak -o - %s | FileCheck -check-prefix=CHECK-UNOPT -check-prefix=CHECK-COMMON %s |
3 | |
4 | // CHECK-COMMON: %[[STRUCT_BLOCK_DESCRIPTOR:.*]] = type { i64, i64 } |
5 | // CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP44:.*]] = linkonce_odr hidden unnamed_addr constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8 |
6 | // CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP9:.*]] = linkonce_odr hidden unnamed_addr constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32r to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32r to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i64 16 }, align 8 |
7 | // CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP46:.*]] = linkonce_odr hidden unnamed_addr constant { i64, i64, i8*, i8*, i8*, i8* } { i64 0, i64 48, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32s to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @{{.*}}, i32 0, i32 0), i8* getelementptr inbounds ([3 x i8], [3 x i8]* @{{.*}}, i32 0, i32 0) }, align 8 |
8 | // CHECK-COMMON: @[[BLOCK_DESCRIPTOR_TMP48:.*]] = linkonce_odr hidden unnamed_addr constant { i64, i64, i8*, i8*, i8*, i64 } { i64 0, i64 40, i8* bitcast (void (i8*, i8*)* @__copy_helper_block_8_32b to i8*), i8* bitcast (void (i8*)* @__destroy_helper_block_8_32s to i8*), i8* getelementptr inbounds ([9 x i8], [9 x i8]* @{{.*}}, i32 0, i32 0), i64 256 }, align 8 |
9 | |
10 | // This shouldn't crash. |
11 | void test0(id (^maker)(void)) { |
12 | maker(); |
13 | } |
14 | |
15 | int (^test1(int x))(void) { |
16 | // CHECK-LABEL: define i32 ()* @test1( |
17 | // CHECK: [[X:%.*]] = alloca i32, |
18 | // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], |
19 | // CHECK-NEXT: store i32 {{%.*}}, i32* [[X]] |
20 | // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to i32 ()* |
21 | // CHECK-NEXT: [[T1:%.*]] = bitcast i32 ()* [[T0]] to i8* |
22 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.retainBlock(i8* [[T1]]) [[NUW:#[0-9]+]] |
23 | // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i32 ()* |
24 | // CHECK-NEXT: [[T4:%.*]] = bitcast i32 ()* [[T3]] to i8* |
25 | // CHECK-NEXT: [[T5:%.*]] = tail call i8* @llvm.objc.autoreleaseReturnValue(i8* [[T4]]) [[NUW]] |
26 | // CHECK-NEXT: [[T6:%.*]] = bitcast i8* [[T5]] to i32 ()* |
27 | // CHECK-NEXT: ret i32 ()* [[T6]] |
28 | return ^{ return x; }; |
29 | } |
30 | |
31 | void test2(id x) { |
32 | // CHECK-LABEL: define void @test2( |
33 | // CHECK: [[X:%.*]] = alloca i8*, |
34 | // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], |
35 | // CHECK-NEXT: [[PARM:%.*]] = call i8* @llvm.objc.retain(i8* {{%.*}}) |
36 | // CHECK-NEXT: store i8* [[PARM]], i8** [[X]] |
37 | // CHECK-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 |
38 | // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 |
39 | // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[X]], |
40 | // CHECK-NEXT: [[T1:%.*]] = call i8* @llvm.objc.retain(i8* [[T0]]) |
41 | // CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]], |
42 | // CHECK-NEXT: bitcast |
43 | // CHECK-NEXT: call void @test2_helper( |
44 | // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[SLOTREL]] |
45 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T0]]) [[NUW]], !clang.imprecise_release |
46 | // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[X]] |
47 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T0]]) [[NUW]], !clang.imprecise_release |
48 | // CHECK-NEXT: ret void |
49 | extern void test2_helper(id (^)(void)); |
50 | test2_helper(^{ return x; }); |
51 | |
52 | // CHECK: define linkonce_odr hidden void @__copy_helper_block_8_32s(i8*, i8*) unnamed_addr #{{[0-9]+}} { |
53 | // CHECK: [[T0:%.*]] = load i8*, i8** |
54 | // CHECK-NEXT: [[SRC:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* |
55 | // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** |
56 | // CHECK-NEXT: [[DST:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* |
57 | // CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[SRC]], i32 0, i32 5 |
58 | // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]] |
59 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.retain(i8* [[T1]]) [[NUW]] |
60 | // CHECK-NEXT: ret void |
61 | |
62 | |
63 | // CHECK: define linkonce_odr hidden void @__destroy_helper_block_8_32s(i8*) unnamed_addr #{{[0-9]+}} { |
64 | // CHECK: [[T0:%.*]] = load i8*, i8** |
65 | // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]* |
66 | // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[T1]], i32 0, i32 5 |
67 | // CHECK-NEXT: [[T3:%.*]] = load i8*, i8** [[T2]] |
68 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T3]]) |
69 | // CHECK-NEXT: ret void |
70 | } |
71 | |
72 | void test3(void (^sink)(id*)) { |
73 | __strong id strong; |
74 | sink(&strong); |
75 | |
76 | // CHECK-LABEL: define void @test3( |
77 | // CHECK: [[SINK:%.*]] = alloca void (i8**)* |
78 | // CHECK-NEXT: [[STRONG:%.*]] = alloca i8* |
79 | // CHECK-NEXT: [[TEMP:%.*]] = alloca i8* |
80 | // CHECK-NEXT: bitcast void (i8**)* {{%.*}} to i8* |
81 | // CHECK-NEXT: call i8* @llvm.objc.retain( |
82 | // CHECK-NEXT: bitcast i8* |
83 | // CHECK-NEXT: store void (i8**)* {{%.*}}, void (i8**)** [[SINK]] |
84 | // CHECK-NEXT: [[STRONGPTR1:%.*]] = bitcast i8** [[STRONG]] to i8* |
85 | // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[STRONGPTR1]]) |
86 | // CHECK-NEXT: store i8* null, i8** [[STRONG]] |
87 | |
88 | // CHECK-NEXT: load void (i8**)*, void (i8**)** [[SINK]] |
89 | // CHECK-NEXT: bitcast |
90 | // CHECK-NEXT: getelementptr |
91 | // CHECK-NEXT: [[BLOCK:%.*]] = bitcast |
92 | // CHECK-NEXT: [[V:%.*]] = load i8*, i8** [[STRONG]] |
93 | // CHECK-NEXT: store i8* [[V]], i8** [[TEMP]] |
94 | // CHECK-NEXT: [[F0:%.*]] = load i8*, i8** |
95 | // CHECK-NEXT: [[F1:%.*]] = bitcast i8* [[F0]] to void (i8*, i8**)* |
96 | // CHECK-NEXT: call void [[F1]](i8* [[BLOCK]], i8** [[TEMP]]) |
97 | // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[TEMP]] |
98 | // CHECK-NEXT: [[T1:%.*]] = call i8* @llvm.objc.retain(i8* [[T0]]) |
99 | // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(i8* [[V]]) [[NUW]] |
100 | // CHECK-NEXT: [[T2:%.*]] = load i8*, i8** [[STRONG]] |
101 | // CHECK-NEXT: store i8* [[T1]], i8** [[STRONG]] |
102 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T2]]) |
103 | |
104 | // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[STRONG]] |
105 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T0]]) |
106 | // CHECK-NEXT: [[STRONGPTR2:%.*]] = bitcast i8** [[STRONG]] to i8* |
107 | // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[STRONGPTR2]]) |
108 | |
109 | // CHECK-NEXT: load void (i8**)*, void (i8**)** [[SINK]] |
110 | // CHECK-NEXT: bitcast |
111 | // CHECK-NEXT: call void @llvm.objc.release |
112 | // CHECK-NEXT: ret void |
113 | |
114 | } |
115 | |
116 | void test4(void) { |
117 | id test4_source(void); |
118 | void test4_helper(void (^)(void)); |
119 | __block id var = test4_source(); |
120 | test4_helper(^{ var = 0; }); |
121 | |
122 | // CHECK-LABEL: define void @test4() |
123 | // CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]], |
124 | // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], |
125 | // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[VAR]], i32 0, i32 2 |
126 | // 0x02000000 - has copy/dispose helpers strong |
127 | // CHECK-NEXT: store i32 838860800, i32* [[T0]] |
128 | // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[VAR]], i32 0, i32 6 |
129 | // CHECK-NEXT: [[T0:%.*]] = call i8* @test4_source() |
130 | // CHECK-NEXT: [[T1:%.*]] = notail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* [[T0]]) |
131 | // CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]] |
132 | // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[VAR]], i32 0, i32 6 |
133 | // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT |
134 | // CHECK: store i32 -1040187392, |
135 | // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* |
136 | // CHECK-NEXT: store i8* [[T0]], i8** |
137 | // CHECK: call void @test4_helper( |
138 | // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* |
139 | // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) |
140 | // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[SLOT]] |
141 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T0]]) |
142 | // CHECK: ret void |
143 | |
144 | // CHECK-LABEL: define internal void @__Block_byref_object_copy_(i8*, i8*) #{{[0-9]+}} { |
145 | // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* {{%.*}}, i32 0, i32 6 |
146 | // CHECK-NEXT: load i8*, i8** |
147 | // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]* |
148 | // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* {{%.*}}, i32 0, i32 6 |
149 | // CHECK-NEXT: [[T2:%.*]] = load i8*, i8** [[T1]] |
150 | // CHECK-NEXT: store i8* [[T2]], i8** [[T0]] |
151 | // CHECK-NEXT: store i8* null, i8** [[T1]] |
152 | |
153 | // CHECK-LABEL: define internal void @__Block_byref_object_dispose_(i8*) #{{[0-9]+}} { |
154 | // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* {{%.*}}, i32 0, i32 6 |
155 | // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[T0]] |
156 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T1]]) |
157 | |
158 | // CHECK-LABEL: define internal void @__test4_block_invoke |
159 | // CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6 |
160 | // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[SLOT]], align 8 |
161 | // CHECK-NEXT: store i8* null, i8** [[SLOT]], |
162 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T0]]) |
163 | // CHECK-NEXT: ret void |
164 | |
165 | // CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_8_32r(i8*, i8*) unnamed_addr #{{[0-9]+}} { |
166 | // CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8) |
167 | |
168 | // CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_8_32r(i8*) unnamed_addr #{{[0-9]+}} { |
169 | // CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8) |
170 | } |
171 | |
172 | void test5(void) { |
173 | extern id test5_source(void); |
174 | void test5_helper(void (^)(void)); |
175 | __unsafe_unretained id var = test5_source(); |
176 | test5_helper(^{ (void) var; }); |
177 | |
178 | // CHECK-LABEL: define void @test5() |
179 | // CHECK: [[VAR:%.*]] = alloca i8* |
180 | // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], |
181 | // CHECK-NEXT: [[VARPTR1:%.*]] = bitcast i8** [[VAR]] to i8* |
182 | // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[VARPTR1]]) |
183 | // CHECK: [[T0:%.*]] = call i8* @test5_source() |
184 | // CHECK-NEXT: [[T1:%.*]] = notail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* [[T0]]) |
185 | // CHECK-NEXT: store i8* [[T1]], i8** [[VAR]], |
186 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T1]]) |
187 | // 0x40800000 - has signature but no copy/dispose, as well as BLOCK_HAS_EXTENDED_LAYOUT |
188 | // CHECK: store i32 -1073741824, i32* |
189 | // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 |
190 | // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[VAR]] |
191 | // CHECK-NEXT: store i8* [[T0]], i8** [[CAPTURE]] |
192 | // CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to |
193 | // CHECK: call void @test5_helper |
194 | // CHECK-NEXT: [[VARPTR2:%.*]] = bitcast i8** [[VAR]] to i8* |
195 | // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[VARPTR2]]) |
196 | // CHECK-NEXT: ret void |
197 | } |
198 | |
199 | void test6(void) { |
200 | id test6_source(void); |
201 | void test6_helper(void (^)(void)); |
202 | __block __weak id var = test6_source(); |
203 | test6_helper(^{ var = 0; }); |
204 | |
205 | // CHECK-LABEL: define void @test6() |
206 | // CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]], |
207 | // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], |
208 | // CHECK-NEXT: [[VARPTR1:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* |
209 | // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 48, i8* [[VARPTR1]]) |
210 | // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[VAR]], i32 0, i32 2 |
211 | // 0x02000000 - has copy/dispose helpers weak |
212 | // CHECK-NEXT: store i32 1107296256, i32* [[T0]] |
213 | // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[VAR]], i32 0, i32 6 |
214 | // CHECK-NEXT: [[T0:%.*]] = call i8* @test6_source() |
215 | // CHECK-NEXT: [[T1:%.*]] = notail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* [[T0]]) |
216 | // CHECK-NEXT: call i8* @llvm.objc.initWeak(i8** [[SLOT]], i8* [[T1]]) |
217 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T1]]) |
218 | // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[VAR]], i32 0, i32 6 |
219 | // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT |
220 | // CHECK: store i32 -1040187392, |
221 | // CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* %{{.*}}, i32 0, i32 4 |
222 | // CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i8*, i8*, i64 }* @[[BLOCK_DESCRIPTOR_TMP9]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8 |
223 | // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* |
224 | // CHECK-NEXT: store i8* [[T0]], i8** |
225 | // CHECK: call void @test6_helper( |
226 | // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* |
227 | // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) |
228 | // CHECK-NEXT: call void @llvm.objc.destroyWeak(i8** [[SLOT]]) |
229 | // CHECK-NEXT: [[VARPTR2:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8* |
230 | // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 48, i8* [[VARPTR2]]) |
231 | // CHECK-NEXT: ret void |
232 | |
233 | // CHECK-LABEL: define internal void @__Block_byref_object_copy_.{{[0-9]+}}(i8*, i8*) #{{[0-9]+}} { |
234 | // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* {{%.*}}, i32 0, i32 6 |
235 | // CHECK-NEXT: load i8*, i8** |
236 | // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]* |
237 | // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* {{%.*}}, i32 0, i32 6 |
238 | // CHECK-NEXT: call void @llvm.objc.moveWeak(i8** [[T0]], i8** [[T1]]) |
239 | |
240 | // CHECK-LABEL: define internal void @__Block_byref_object_dispose_.{{[0-9]+}}(i8*) #{{[0-9]+}} { |
241 | // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* {{%.*}}, i32 0, i32 6 |
242 | // CHECK-NEXT: call void @llvm.objc.destroyWeak(i8** [[T0]]) |
243 | |
244 | // CHECK-LABEL: define internal void @__test6_block_invoke |
245 | // CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6 |
246 | // CHECK-NEXT: call i8* @llvm.objc.storeWeak(i8** [[SLOT]], i8* null) |
247 | // CHECK-NEXT: ret void |
248 | } |
249 | |
250 | void test7(void) { |
251 | id test7_source(void); |
252 | void test7_helper(void (^)(void)); |
253 | void test7_consume(id); |
254 | __weak id var = test7_source(); |
255 | test7_helper(^{ test7_consume(var); }); |
256 | |
257 | // CHECK-LABEL: define void @test7() |
258 | // CHECK: [[VAR:%.*]] = alloca i8*, |
259 | // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], |
260 | // CHECK: [[T0:%.*]] = call i8* @test7_source() |
261 | // CHECK-NEXT: [[T1:%.*]] = notail call i8* @llvm.objc.retainAutoreleasedReturnValue(i8* [[T0]]) |
262 | // CHECK-NEXT: call i8* @llvm.objc.initWeak(i8** [[VAR]], i8* [[T1]]) |
263 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T1]]) |
264 | // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT |
265 | // CHECK: store i32 -1040187392, |
266 | // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 |
267 | // CHECK-NEXT: call void @llvm.objc.copyWeak(i8** [[SLOT]], i8** [[VAR]]) |
268 | // CHECK: call void @test7_helper( |
269 | // CHECK-NEXT: call void @llvm.objc.destroyWeak(i8** {{%.*}}) |
270 | // CHECK-NEXT: call void @llvm.objc.destroyWeak(i8** [[VAR]]) |
271 | // CHECK: ret void |
272 | |
273 | // CHECK-LABEL: define internal void @__test7_block_invoke |
274 | // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* {{%.*}}, i32 0, i32 5 |
275 | // CHECK-NEXT: [[T0:%.*]] = call i8* @llvm.objc.loadWeakRetained(i8** [[SLOT]]) |
276 | // CHECK-NEXT: call void @test7_consume(i8* [[T0]]) |
277 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T0]]) |
278 | // CHECK: ret void |
279 | |
280 | // CHECK-LABEL: define linkonce_odr hidden void @__copy_helper_block_8_32w(i8*, i8*) unnamed_addr #{{[0-9]+}} { |
281 | // CHECK: getelementptr |
282 | // CHECK-NEXT: getelementptr |
283 | // CHECK-NEXT: call void @llvm.objc.copyWeak( |
284 | |
285 | // CHECK-LABEL: define linkonce_odr hidden void @__destroy_helper_block_8_32w(i8*) unnamed_addr #{{[0-9]+}} { |
286 | // CHECK: getelementptr |
287 | // CHECK-NEXT: call void @llvm.objc.destroyWeak( |
288 | } |
289 | |
290 | @interface Test8 @end |
291 | @implementation Test8 |
292 | - (void) test { |
293 | // CHECK: define internal void @"\01-[Test8 test]" |
294 | // CHECK: [[SELF:%.*]] = alloca [[TEST8:%.*]]*, |
295 | // CHECK-NEXT: alloca i8* |
296 | // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], |
297 | // CHECK: store |
298 | // CHECK-NEXT: store |
299 | // CHECK: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 |
300 | // CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 |
301 | // CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]*, [[TEST8]]** [[SELF]], |
302 | // CHECK-NEXT: store %0* [[T1]], %0** [[T0]] |
303 | // CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to |
304 | // CHECK: call void @test8_helper( |
305 | // CHECK-NEXT: [[T2:%.*]] = load [[TEST8]]*, [[TEST8]]** [[D0]] |
306 | // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use([[TEST8]]* [[T2]]) |
307 | // CHECK: ret void |
308 | |
309 | extern void test8_helper(void (^)(void)); |
310 | test8_helper(^{ (void) self; }); |
311 | } |
312 | @end |
313 | |
314 | id test9(void) { |
315 | typedef id __attribute__((ns_returns_retained)) blocktype(void); |
316 | extern void test9_consume_block(blocktype^); |
317 | return ^blocktype { |
318 | extern id test9_produce(void); |
319 | return test9_produce(); |
320 | }(); |
321 | |
322 | // CHECK-LABEL: define i8* @test9( |
323 | // CHECK: load i8*, i8** getelementptr |
324 | // CHECK-NEXT: bitcast i8* |
325 | // CHECK-NEXT: call i8* |
326 | // CHECK-NEXT: tail call i8* @llvm.objc.autoreleaseReturnValue |
327 | // CHECK-NEXT: ret i8* |
328 | |
329 | // CHECK: call i8* @test9_produce() |
330 | // CHECK-NEXT: call i8* @llvm.objc.retain |
331 | // CHECK-NEXT: ret i8* |
332 | } |
333 | |
334 | // rdar://problem/9814099 |
335 | // Test that we correctly initialize __block variables |
336 | // when the initialization captures the variable. |
337 | void test10a(void) { |
338 | __block void (^block)(void) = ^{ block(); }; |
339 | // CHECK-LABEL: define void @test10a() |
340 | // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]], |
341 | // CHECK: [[BLOCK1:%.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8 |
342 | |
343 | // Zero-initialization before running the initializer. |
344 | // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[BYREF]], i32 0, i32 6 |
345 | // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8 |
346 | |
347 | // Run the initializer as an assignment. |
348 | // CHECK: [[T2:%.*]] = bitcast <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* [[BLOCK1]] to void ()* |
349 | // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[BYREF]], i32 0, i32 1 |
350 | // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]*, [[BYREF_T]]** [[T3]] |
351 | // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[T4]], i32 0, i32 6 |
352 | // CHECK-NEXT: [[T6:%.*]] = load void ()*, void ()** [[T5]], align 8 |
353 | // CHECK-NEXT: store void ()* [[T2]], void ()** [[T5]], align 8 |
354 | // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8* |
355 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T7]]) |
356 | |
357 | // Destroy at end of function. |
358 | // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[BYREF]], i32 0, i32 6 |
359 | // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8* |
360 | // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) |
361 | // CHECK-NEXT: [[T1:%.*]] = load void ()*, void ()** [[SLOT]] |
362 | // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8* |
363 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T2]]) |
364 | // CHECK: ret void |
365 | } |
366 | |
367 | // <rdar://problem/10402698>: do this copy and dispose with |
368 | // objc_retainBlock/release instead of _Block_object_assign/destroy. |
369 | // We can also use _Block_object_assign/destroy with |
370 | // BLOCK_FIELD_IS_BLOCK as long as we don't pass BLOCK_BYREF_CALLER. |
371 | |
372 | // CHECK-LABEL: define internal void @__Block_byref_object_copy_.{{[0-9]+}}(i8*, i8*) #{{[0-9]+}} { |
373 | // CHECK: [[D0:%.*]] = load i8*, i8** {{%.*}} |
374 | // CHECK-NEXT: [[D1:%.*]] = bitcast i8* [[D0]] to [[BYREF_T]]* |
375 | // CHECK-NEXT: [[D2:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[D1]], i32 0, i32 6 |
376 | // CHECK-NEXT: [[S0:%.*]] = load i8*, i8** {{%.*}} |
377 | // CHECK-NEXT: [[S1:%.*]] = bitcast i8* [[S0]] to [[BYREF_T]]* |
378 | // CHECK-NEXT: [[S2:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[S1]], i32 0, i32 6 |
379 | // CHECK-NEXT: [[T0:%.*]] = load void ()*, void ()** [[S2]], align 8 |
380 | // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* |
381 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.retainBlock(i8* [[T1]]) |
382 | // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()* |
383 | // CHECK-NEXT: store void ()* [[T3]], void ()** [[D2]], align 8 |
384 | // CHECK: ret void |
385 | |
386 | // CHECK-LABEL: define internal void @__Block_byref_object_dispose_.{{[0-9]+}}(i8*) #{{[0-9]+}} { |
387 | // CHECK: [[T0:%.*]] = load i8*, i8** {{%.*}} |
388 | // CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BYREF_T]]* |
389 | // CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[T1]], i32 0, i32 6 |
390 | // CHECK-NEXT: [[T3:%.*]] = load void ()*, void ()** [[T2]] |
391 | // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8* |
392 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T4]]) |
393 | // CHECK-NEXT: ret void |
394 | |
395 | // Test that we correctly assign to __block variables when the |
396 | // assignment captures the variable. |
397 | void test10b(void) { |
398 | __block void (^block)(void); |
399 | block = ^{ block(); }; |
400 | |
401 | // CHECK-LABEL: define void @test10b() |
402 | // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]], |
403 | // CHECK: [[BLOCK3:%.*]] = alloca <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>, align 8 |
404 | |
405 | // Zero-initialize. |
406 | // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[BYREF]], i32 0, i32 6 |
407 | // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8 |
408 | |
409 | // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[BYREF]], i32 0, i32 6 |
410 | |
411 | // The assignment. |
412 | // CHECK: [[T2:%.*]] = bitcast <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8* }>* [[BLOCK3]] to void ()* |
413 | // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[BYREF]], i32 0, i32 1 |
414 | // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]*, [[BYREF_T]]** [[T3]] |
415 | // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]], [[BYREF_T]]* [[T4]], i32 0, i32 6 |
416 | // CHECK-NEXT: [[T6:%.*]] = load void ()*, void ()** [[T5]], align 8 |
417 | // CHECK-NEXT: store void ()* [[T2]], void ()** [[T5]], align 8 |
418 | // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8* |
419 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T7]]) |
420 | |
421 | // Destroy at end of function. |
422 | // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8* |
423 | // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8) |
424 | // CHECK-NEXT: [[T1:%.*]] = load void ()*, void ()** [[SLOT]] |
425 | // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8* |
426 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T2]]) |
427 | // CHECK: ret void |
428 | } |
429 | |
430 | // rdar://problem/10088932 |
431 | void test11_helper(id); |
432 | void test11a(void) { |
433 | int x; |
434 | test11_helper(^{ (void) x; }); |
435 | |
436 | // CHECK-LABEL: define void @test11a() |
437 | // CHECK: [[X:%.*]] = alloca i32, align 4 |
438 | // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8 |
439 | // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* |
440 | // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* |
441 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.retainBlock(i8* [[T1]]) |
442 | // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()* |
443 | // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8* |
444 | // CHECK-NEXT: call void @test11_helper(i8* [[T4]]) |
445 | // CHECK-NEXT: [[T5:%.*]] = bitcast void ()* [[T3]] to i8* |
446 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T5]]) |
447 | // CHECK: ret void |
448 | } |
449 | void test11b(void) { |
450 | int x; |
451 | id b = ^{ (void) x; }; |
452 | |
453 | // CHECK-LABEL: define void @test11b() |
454 | // CHECK: [[X:%.*]] = alloca i32, align 4 |
455 | // CHECK-NEXT: [[B:%.*]] = alloca i8*, align 8 |
456 | // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8 |
457 | // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* |
458 | // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* |
459 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.retainBlock(i8* [[T1]]) |
460 | // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()* |
461 | // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8* |
462 | // CHECK-NEXT: store i8* [[T4]], i8** [[B]], align 8 |
463 | // CHECK-NEXT: [[T5:%.*]] = load i8*, i8** [[B]] |
464 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T5]]) |
465 | // CHECK: ret void |
466 | } |
467 | |
468 | // rdar://problem/9979150 |
469 | @interface Test12 |
470 | @property (strong) void(^ablock)(void); |
471 | @property (nonatomic, strong) void(^nblock)(void); |
472 | @end |
473 | @implementation Test12 |
474 | @synthesize ablock, nblock; |
475 | // CHECK: define internal void ()* @"\01-[Test12 ablock]"( |
476 | // CHECK: call i8* @objc_getProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i1 zeroext true) |
477 | |
478 | // CHECK: define internal void @"\01-[Test12 setAblock:]"( |
479 | // CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext true, i1 zeroext true) |
480 | |
481 | // CHECK: define internal void ()* @"\01-[Test12 nblock]"( |
482 | // CHECK: call i8* @objc_getProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i1 zeroext false) |
483 | |
484 | // CHECK: define internal void @"\01-[Test12 setNblock:]"( |
485 | // CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext false, i1 zeroext true) |
486 | @end |
487 | |
488 | // rdar://problem/10131784 |
489 | void test13(id x) { |
490 | extern void test13_helper(id); |
491 | extern void test13_use(void(^)(void)); |
492 | |
493 | void (^b)(void) = (x ? ^{test13_helper(x);} : 0); |
494 | test13_use(b); |
495 | |
496 | // CHECK-LABEL: define void @test13( |
497 | // CHECK: [[X:%.*]] = alloca i8*, align 8 |
498 | // CHECK-NEXT: [[B:%.*]] = alloca void ()*, align 8 |
499 | // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align 8 |
500 | // CHECK-NEXT: [[CLEANUP_ACTIVE:%.*]] = alloca i1 |
501 | // CHECK-NEXT: [[T0:%.*]] = call i8* @llvm.objc.retain(i8* {{%.*}}) |
502 | // CHECK-NEXT: store i8* [[T0]], i8** [[X]], align 8 |
503 | // CHECK-NEXT: [[BPTR1:%.*]] = bitcast void ()** [[B]] to i8* |
504 | // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[BPTR1]]) |
505 | // CHECK-NEXT: [[CLEANUP_ADDR:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 |
506 | // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[X]], align 8 |
507 | // CHECK-NEXT: [[T1:%.*]] = icmp ne i8* [[T0]], null |
508 | // CHECK-NEXT: store i1 false, i1* [[CLEANUP_ACTIVE]] |
509 | // CHECK-NEXT: br i1 [[T1]], |
510 | |
511 | // CHECK-NOT: br |
512 | // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 |
513 | // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[X]], align 8 |
514 | // CHECK-NEXT: [[T1:%.*]] = call i8* @llvm.objc.retain(i8* [[T0]]) |
515 | // CHECK-NEXT: store i8* [[T1]], i8** [[CAPTURE]], align 8 |
516 | // CHECK-NEXT: store i1 true, i1* [[CLEANUP_ACTIVE]] |
517 | // CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to void ()* |
518 | // CHECK-NEXT: br label |
519 | // CHECK: br label |
520 | // CHECK: [[T0:%.*]] = phi void ()* |
521 | // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* |
522 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.retainBlock(i8* [[T1]]) |
523 | // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()* |
524 | // CHECK-NEXT: store void ()* [[T3]], void ()** [[B]], align 8 |
525 | // CHECK-NEXT: [[T0:%.*]] = load void ()*, void ()** [[B]], align 8 |
526 | // CHECK-NEXT: call void @test13_use(void ()* [[T0]]) |
527 | // CHECK-NEXT: [[T0:%.*]] = load void ()*, void ()** [[B]] |
528 | // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* |
529 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T1]]) |
530 | |
531 | // CHECK-NEXT: [[T0:%.*]] = load i1, i1* [[CLEANUP_ACTIVE]] |
532 | // CHECK-NEXT: br i1 [[T0]] |
533 | // CHECK: [[T0:%.*]] = load i8*, i8** [[CLEANUP_ADDR]] |
534 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T0]]) |
535 | // CHECK-NEXT: br label |
536 | |
537 | // CHECK: [[BPTR2:%.*]] = bitcast void ()** [[B]] to i8* |
538 | // CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 8, i8* [[BPTR2]]) |
539 | // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[X]] |
540 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T0]]) |
541 | // CHECK-NEXT: ret void |
542 | } |
543 | |
544 | // <rdar://problem/10907510> |
545 | void test14() { |
546 | void (^const x[1])(void) = { ^{} }; |
547 | } |
548 | |
549 | // rdar://11149025 |
550 | // Don't make invalid ASTs and crash. |
551 | void test15_helper(void (^block)(void), int x); |
552 | void test15(int a) { |
553 | test15_helper(^{ (void) a; }, ({ a; })); |
554 | } |
555 | |
556 | // rdar://11016025 |
557 | void test16() { |
558 | void (^BLKVAR)(void) = ^{ BLKVAR(); }; |
559 | |
560 | // CHECK-LABEL: define void @test16( |
561 | // CHECK: [[BLKVAR:%.*]] = alloca void ()*, align 8 |
562 | // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], |
563 | // CHECK-NEXT: [[BLKVARPTR1:%.*]] = bitcast void ()** [[BLKVAR]] to i8* |
564 | // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 8, i8* [[BLKVARPTR1]]) |
565 | // CHECK-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 |
566 | // CHECK-NEXT: store void ()* null, void ()** [[BLKVAR]], align 8 |
567 | } |
568 | |
569 | // rdar://12151005 |
570 | // |
571 | // This is an intentional exception to our conservative jump-scope |
572 | // checking for full-expressions containing block literals with |
573 | // non-trivial cleanups: if the block literal appears in the operand |
574 | // of a return statement, there's no need to extend its lifetime. |
575 | id (^test17(id self, int which))(void) { |
576 | switch (which) { |
577 | case 1: return ^{ return self; }; |
578 | case 0: return ^{ return self; }; |
579 | } |
580 | return (void*) 0; |
581 | } |
582 | // CHECK-LABEL: define i8* ()* @test17( |
583 | // CHECK: [[RET:%.*]] = alloca i8* ()*, align |
584 | // CHECK-NEXT: [[SELF:%.*]] = alloca i8*, |
585 | // CHECK: [[B0:%.*]] = alloca [[BLOCK:<.*>]], align |
586 | // CHECK: [[B1:%.*]] = alloca [[BLOCK]], align |
587 | // CHECK: [[T0:%.*]] = call i8* @llvm.objc.retain(i8* |
588 | // CHECK-NEXT: store i8* [[T0]], i8** [[SELF]], align |
589 | // CHECK-NOT: objc_retain |
590 | // CHECK-NOT: objc_release |
591 | // CHECK: [[DESTROY:%.*]] = getelementptr inbounds [[BLOCK]], [[BLOCK]]* [[B0]], i32 0, i32 5 |
592 | // CHECK-NOT: objc_retain |
593 | // CHECK-NOT: objc_release |
594 | // CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK]], [[BLOCK]]* [[B0]], i32 0, i32 5 |
595 | // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[SELF]], align |
596 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.retain(i8* [[T1]]) |
597 | // CHECK-NEXT: store i8* [[T2]], i8** [[T0]], |
598 | // CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK]]* [[B0]] to i8* ()* |
599 | // CHECK-NEXT: [[T1:%.*]] = bitcast i8* ()* [[T0]] to i8* |
600 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.retainBlock(i8* [[T1]]) |
601 | // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i8* ()* |
602 | // CHECK-NEXT: store i8* ()* [[T3]], i8* ()** [[RET]] |
603 | // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[DESTROY]] |
604 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T0]]) |
605 | // CHECK-NEXT: store i32 |
606 | // CHECK-NEXT: br label |
607 | // CHECK-NOT: objc_retain |
608 | // CHECK-NOT: objc_release |
609 | // CHECK: [[DESTROY:%.*]] = getelementptr inbounds [[BLOCK]], [[BLOCK]]* [[B1]], i32 0, i32 5 |
610 | // CHECK-NOT: objc_retain |
611 | // CHECK-NOT: objc_release |
612 | // CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK]], [[BLOCK]]* [[B1]], i32 0, i32 5 |
613 | // CHECK-NEXT: [[T1:%.*]] = load i8*, i8** [[SELF]], align |
614 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.retain(i8* [[T1]]) |
615 | // CHECK-NEXT: store i8* [[T2]], i8** [[T0]], |
616 | // CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK]]* [[B1]] to i8* ()* |
617 | // CHECK-NEXT: [[T1:%.*]] = bitcast i8* ()* [[T0]] to i8* |
618 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.retainBlock(i8* [[T1]]) |
619 | // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i8* ()* |
620 | // CHECK-NEXT: store i8* ()* [[T3]], i8* ()** [[RET]] |
621 | // CHECK-NEXT: [[T0:%.*]] = load i8*, i8** [[DESTROY]] |
622 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T0]]) |
623 | // CHECK-NEXT: store i32 |
624 | // CHECK-NEXT: br label |
625 | |
626 | void test18(id x) { |
627 | // CHECK-UNOPT-LABEL: define void @test18( |
628 | // CHECK-UNOPT: [[X:%.*]] = alloca i8*, |
629 | // CHECK-UNOPT-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], |
630 | // CHECK-UNOPT-NEXT: store i8* null, i8** [[X]] |
631 | // CHECK-UNOPT-NEXT: call void @llvm.objc.storeStrong(i8** [[X]], |
632 | // CHECK-UNOPT-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 |
633 | // CHECK-UNOPT: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 4 |
634 | // CHECK-UNOPT: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i8*, i8*, i64 }* @[[BLOCK_DESCRIPTOR_TMP44]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8 |
635 | // CHECK-UNOPT: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 |
636 | // CHECK-UNOPT-NEXT: [[T0:%.*]] = load i8*, i8** [[X]], |
637 | // CHECK-UNOPT-NEXT: [[T1:%.*]] = call i8* @llvm.objc.retain(i8* [[T0]]) |
638 | // CHECK-UNOPT-NEXT: store i8* [[T1]], i8** [[SLOT]], |
639 | // CHECK-UNOPT-NEXT: bitcast |
640 | // CHECK-UNOPT-NEXT: call void @test18_helper( |
641 | // CHECK-UNOPT-NEXT: call void @llvm.objc.storeStrong(i8** [[SLOTREL]], i8* null) [[NUW:#[0-9]+]] |
642 | // CHECK-UNOPT-NEXT: call void @llvm.objc.storeStrong(i8** [[X]], i8* null) [[NUW]] |
643 | // CHECK-UNOPT-NEXT: ret void |
644 | extern void test18_helper(id (^)(void)); |
645 | test18_helper(^{ return x; }); |
646 | } |
647 | |
648 | // Ensure that we don't emit helper code in copy/dispose routines for variables |
649 | // that are const-captured. |
650 | void testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers(id x, id y) { |
651 | id __unsafe_unretained unsafeObject = x; |
652 | (^ { testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers(x, unsafeObject); })(); |
653 | } |
654 | |
655 | // CHECK-LABEL: define void @testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers |
656 | // %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8* }>, <{ i8*, i32, i32, i8*, %[[STRUCT_BLOCK_DESCRIPTOR]]*, i8*, i8* }>* %{{.*}}, i32 0, i32 4 |
657 | // CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i8*, i8*, i8* }* @[[BLOCK_DESCRIPTOR_TMP46]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8 |
658 | |
659 | // CHECK-LABEL: define internal void @__testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers_block_invoke |
660 | // CHECK-UNOPT-LABEL: define internal void @__testUnsafeUnretainedLifetimeInCopyAndDestroyHelpers_block_invoke |
661 | |
662 | // rdar://13588325 |
663 | void test19_sink(void (^)(int)); |
664 | void test19(void (^b)(void)) { |
665 | // CHECK-LABEL: define void @test19( |
666 | // Prologue. |
667 | // CHECK: [[B:%.*]] = alloca void ()*, |
668 | // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], |
669 | // CHECK-NEXT: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8* |
670 | // CHECK-NEXT: [[T1:%.*]] = call i8* @llvm.objc.retain(i8* [[T0]]) |
671 | // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()* |
672 | // CHECK-NEXT: store void ()* [[T2]], void ()** [[B]] |
673 | |
674 | // Block setup. We skip most of this. Note the bare retain. |
675 | // CHECK-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 |
676 | // CHECK: %[[BLOCK_DESCRIPTOR:.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 4 |
677 | // CHECK: store %[[STRUCT_BLOCK_DESCRIPTOR]]* bitcast ({ i64, i64, i8*, i8*, i8*, i64 }* @[[BLOCK_DESCRIPTOR_TMP48]] to %[[STRUCT_BLOCK_DESCRIPTOR]]*), %[[STRUCT_BLOCK_DESCRIPTOR]]** %[[BLOCK_DESCRIPTOR]], align 8 |
678 | // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]], [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5 |
679 | // CHECK-NEXT: [[T0:%.*]] = load void ()*, void ()** [[B]], |
680 | // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* |
681 | // CHECK-NEXT: [[T2:%.*]] = call i8* @llvm.objc.retain(i8* [[T1]]) |
682 | // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()* |
683 | // CHECK-NEXT: store void ()* [[T3]], void ()** [[SLOT]], |
684 | // Call. |
685 | // CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void (i32)* |
686 | // CHECK-NEXT: call void @test19_sink(void (i32)* [[T0]]) |
687 | |
688 | test19_sink(^(int x) { b(); }); |
689 | |
690 | // Block teardown. |
691 | // CHECK-NEXT: [[T0:%.*]] = load void ()*, void ()** [[SLOTREL]] |
692 | // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* |
693 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T1]]) |
694 | |
695 | // Local cleanup. |
696 | // CHECK-NEXT: [[T0:%.*]] = load void ()*, void ()** [[B]] |
697 | // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8* |
698 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[T1]]) |
699 | |
700 | // CHECK-NEXT: ret void |
701 | } |
702 | |
703 | // CHECK-LABEL: define void @test20( |
704 | // CHECK: [[XADDR:%.*]] = alloca i8* |
705 | // CHECK-NEXT: [[BLOCK:%.*]] = alloca <[[BLOCKTY:.*]]> |
706 | // CHECK-NEXT: [[RETAINEDX:%.*]] = call i8* @llvm.objc.retain(i8* %{{.*}}) |
707 | // CHECK-NEXT: store i8* [[RETAINEDX]], i8** [[XADDR]] |
708 | // CHECK-NEXT: [[CAPTUREFIELD:%.*]] = getelementptr inbounds <[[BLOCKTY]]>, <[[BLOCKTY]]>* [[BLOCK]], i32 0, i32 5 |
709 | // CHECK: [[BLOCKCAPTURED:%.*]] = getelementptr inbounds <[[BLOCKTY]]>, <[[BLOCKTY]]>* [[BLOCK]], i32 0, i32 5 |
710 | // CHECK: [[CAPTURED:%.*]] = load i8*, i8** [[XADDR]] |
711 | // CHECK: store i8* [[CAPTURED]], i8** [[BLOCKCAPTURED]] |
712 | // CHECK: [[CAPTURE:%.*]] = load i8*, i8** [[CAPTUREFIELD]] |
713 | // CHECK-NEXT: call void (...) @llvm.objc.clang.arc.use(i8* [[CAPTURE]]) |
714 | // CHECK-NEXT: [[X:%.*]] = load i8*, i8** [[XADDR]] |
715 | // CHECK-NEXT: call void @llvm.objc.release(i8* [[X]]) |
716 | // CHECK-NEXT: ret void |
717 | |
718 | // CHECK-UNOPT-LABEL: define void @test20( |
719 | // CHECK-UNOPT: [[XADDR:%.*]] = alloca i8* |
720 | // CHECK-UNOPT-NEXT: [[BLOCK:%.*]] = alloca <[[BLOCKTY:.*]]> |
721 | // CHECK-UNOPT: [[CAPTUREFIELD:%.*]] = getelementptr inbounds <[[BLOCKTY]]>, <[[BLOCKTY]]>* [[BLOCK]], i32 0, i32 5 |
722 | // CHECK-UNOPT: [[BLOCKCAPTURED:%.*]] = getelementptr inbounds <[[BLOCKTY]]>, <[[BLOCKTY]]>* [[BLOCK]], i32 0, i32 5 |
723 | // CHECK-UNOPT: [[CAPTURED:%.*]] = load i8*, i8** [[XADDR]] |
724 | // CHECK-UNOPT: [[RETAINED:%.*]] = call i8* @llvm.objc.retain(i8* [[CAPTURED]]) |
725 | // CHECK-UNOPT: store i8* [[RETAINED]], i8** [[BLOCKCAPTURED]] |
726 | // CHECK-UNOPT: call void @llvm.objc.storeStrong(i8** [[CAPTUREFIELD]], i8* null) |
727 | |
728 | void test20_callee(void (^)()); |
729 | void test20(const id x) { |
730 | test20_callee(^{ (void)x; }); |
731 | } |
732 | |
733 | // CHECK: attributes [[NUW]] = { nounwind } |
734 | // CHECK-UNOPT: attributes [[NUW]] = { nounwind } |
735 | |