blob: 63bb7a37c33e77cd186acdcd3bda6ffa490bb22b [file] [log] [blame]
John McCall3382f652011-11-09 02:16:13 +00001// 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
John McCall015f33b2012-10-17 02:28:37 +00002// 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
John McCall3382f652011-11-09 02:16:13 +00003
4// This shouldn't crash.
5void test0(id (^maker)(void)) {
6 maker();
7}
8
9int (^test1(int x))(void) {
10 // CHECK: define i32 ()* @test1(
11 // CHECK: [[X:%.*]] = alloca i32,
12 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
13 // CHECK-NEXT: store i32 {{%.*}}, i32* [[X]]
14 // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to i32 ()*
15 // CHECK-NEXT: [[T1:%.*]] = bitcast i32 ()* [[T0]] to i8*
16 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) nounwind
17 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i32 ()*
18 // CHECK-NEXT: [[T4:%.*]] = bitcast i32 ()* [[T3]] to i8*
19 // CHECK-NEXT: [[T5:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T4]]) nounwind
20 // CHECK-NEXT: [[T6:%.*]] = bitcast i8* [[T5]] to i32 ()*
21 // CHECK-NEXT: ret i32 ()* [[T6]]
22 return ^{ return x; };
23}
24
25void test2(id x) {
26// CHECK: define void @test2(
27// CHECK: [[X:%.*]] = alloca i8*,
28// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
29// CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}})
30// CHECK-NEXT: store i8* [[PARM]], i8** [[X]]
John McCall1a343eb2011-11-10 08:15:53 +000031// CHECK-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
John McCall3382f652011-11-09 02:16:13 +000032// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
33// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]],
34// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
35// CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]],
36// CHECK-NEXT: bitcast
37// CHECK-NEXT: call void @test2_helper(
John McCall1a343eb2011-11-10 08:15:53 +000038// CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOTREL]]
John McCall3382f652011-11-09 02:16:13 +000039// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
40// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
41// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
42// CHECK-NEXT: ret void
43 extern void test2_helper(id (^)(void));
44 test2_helper(^{ return x; });
John McCall015f33b2012-10-17 02:28:37 +000045
46// CHECK: define internal void @__copy_helper_block_
47// CHECK: [[T0:%.*]] = load i8**
48// CHECK-NEXT: [[SRC:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]*
49// CHECK-NEXT: [[T0:%.*]] = load i8**
50// CHECK-NEXT: [[DST:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]*
51// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[SRC]], i32 0, i32 5
52// CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]]
53// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]]) nounwind
54// CHECK-NEXT: ret void
55
56// CHECK: define internal void @__destroy_helper_block_
57// CHECK: [[T0:%.*]] = load i8**
58// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]*
59// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[T1]], i32 0, i32 5
60// CHECK-NEXT: [[T3:%.*]] = load i8** [[T2]]
61// CHECK-NEXT: call void @objc_release(i8* [[T3]])
62// CHECK-NEXT: ret void
John McCall3382f652011-11-09 02:16:13 +000063}
64
65void test3(void (^sink)(id*)) {
66 __strong id strong;
67 sink(&strong);
68
69 // CHECK: define void @test3(
70 // CHECK: [[SINK:%.*]] = alloca void (i8**)*
71 // CHECK-NEXT: [[STRONG:%.*]] = alloca i8*
72 // CHECK-NEXT: [[TEMP:%.*]] = alloca i8*
73 // CHECK-NEXT: bitcast void (i8**)* {{%.*}} to i8*
74 // CHECK-NEXT: call i8* @objc_retain(
75 // CHECK-NEXT: bitcast i8*
76 // CHECK-NEXT: store void (i8**)* {{%.*}}, void (i8**)** [[SINK]]
77 // CHECK-NEXT: store i8* null, i8** [[STRONG]]
78
79 // CHECK-NEXT: load void (i8**)** [[SINK]]
80 // CHECK-NEXT: bitcast
81 // CHECK-NEXT: getelementptr
82 // CHECK-NEXT: [[BLOCK:%.*]] = bitcast
83 // CHECK-NEXT: [[T0:%.*]] = load i8** [[STRONG]]
84 // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP]]
85 // CHECK-NEXT: [[F0:%.*]] = load i8**
86 // CHECK-NEXT: [[F1:%.*]] = bitcast i8* [[F0]] to void (i8*, i8**)*
87 // CHECK-NEXT: call void [[F1]](i8* [[BLOCK]], i8** [[TEMP]])
88 // CHECK-NEXT: [[T0:%.*]] = load i8** [[TEMP]]
89 // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
90 // CHECK-NEXT: [[T2:%.*]] = load i8** [[STRONG]]
91 // CHECK-NEXT: store i8* [[T1]], i8** [[STRONG]]
92 // CHECK-NEXT: call void @objc_release(i8* [[T2]])
93
94 // CHECK-NEXT: [[T0:%.*]] = load i8** [[STRONG]]
95 // CHECK-NEXT: call void @objc_release(i8* [[T0]])
96
97 // CHECK-NEXT: load void (i8**)** [[SINK]]
98 // CHECK-NEXT: bitcast
99 // CHECK-NEXT: call void @objc_release
100 // CHECK-NEXT: ret void
101
102}
103
104void test4(void) {
105 id test4_source(void);
106 void test4_helper(void (^)(void));
107 __block id var = test4_source();
108 test4_helper(^{ var = 0; });
109
110 // CHECK: define void @test4()
111 // CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
112 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
113 // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2
Fariborz Jahanian3ca23d72012-11-14 17:15:51 +0000114 // 0x02000000 - has copy/dispose helpers strong
115 // CHECK-NEXT: store i32 838860800, i32* [[T0]]
John McCall3382f652011-11-09 02:16:13 +0000116 // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
117 // CHECK-NEXT: [[T0:%.*]] = call i8* @test4_source()
118 // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
119 // CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]]
120 // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
Fariborz Jahanianf22ae652012-11-01 18:32:55 +0000121 // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT
Fariborz Jahaniana97d2ec2012-11-10 18:30:40 +0000122 // CHECK: store i32 -1040187392,
John McCall3382f652011-11-09 02:16:13 +0000123 // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
124 // CHECK-NEXT: store i8* [[T0]], i8**
125 // CHECK: call void @test4_helper(
126 // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
127 // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
128 // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]]
129 // CHECK-NEXT: call void @objc_release(i8* [[T0]])
130 // CHECK-NEXT: ret void
131
132 // CHECK: define internal void @__Block_byref_object_copy_
133 // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
134 // CHECK-NEXT: load i8**
135 // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]*
136 // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
137 // CHECK-NEXT: [[T2:%.*]] = load i8** [[T1]]
138 // CHECK-NEXT: store i8* [[T2]], i8** [[T0]]
139 // CHECK-NEXT: store i8* null, i8** [[T1]]
140
141 // CHECK: define internal void @__Block_byref_object_dispose_
142 // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
143 // CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]]
144 // CHECK-NEXT: call void @objc_release(i8* [[T1]])
145
Fariborz Jahanian4904bf42012-06-26 16:06:38 +0000146 // CHECK: define internal void @__test4_block_invoke
John McCall3382f652011-11-09 02:16:13 +0000147 // CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6
148 // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]], align 8
149 // CHECK-NEXT: store i8* null, i8** [[SLOT]],
150 // CHECK-NEXT: call void @objc_release(i8* [[T0]])
151 // CHECK-NEXT: ret void
152
153 // CHECK: define internal void @__copy_helper_block_
154 // CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8)
155
156 // CHECK: define internal void @__destroy_helper_block_
157 // CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8)
158}
159
160void test5(void) {
161 extern id test5_source(void);
162 void test5_helper(void (^)(void));
163 __unsafe_unretained id var = test5_source();
164 test5_helper(^{ (void) var; });
165
166 // CHECK: define void @test5()
167 // CHECK: [[VAR:%.*]] = alloca i8*
168 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
169 // CHECK: [[T0:%.*]] = call i8* @test5_source()
170 // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
171 // CHECK-NEXT: store i8* [[T1]], i8** [[VAR]],
172 // CHECK-NEXT: call void @objc_release(i8* [[T1]])
Fariborz Jahanianf22ae652012-11-01 18:32:55 +0000173 // 0x40800000 - has signature but no copy/dispose, as well as BLOCK_HAS_EXTENDED_LAYOUT
Fariborz Jahaniana97d2ec2012-11-10 18:30:40 +0000174 // CHECK: store i32 -1073741824, i32*
John McCall3382f652011-11-09 02:16:13 +0000175 // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
176 // CHECK-NEXT: [[T0:%.*]] = load i8** [[VAR]]
177 // CHECK-NEXT: store i8* [[T0]], i8** [[CAPTURE]]
178 // CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to
179 // CHECK: call void @test5_helper
180 // CHECK-NEXT: ret void
181}
182
183void test6(void) {
184 id test6_source(void);
185 void test6_helper(void (^)(void));
186 __block __weak id var = test6_source();
187 test6_helper(^{ var = 0; });
188
189 // CHECK: define void @test6()
190 // CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
191 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
192 // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2
Fariborz Jahanian3ca23d72012-11-14 17:15:51 +0000193 // 0x02000000 - has copy/dispose helpers weak
194 // CHECK-NEXT: store i32 1107296256, i32* [[T0]]
John McCall3382f652011-11-09 02:16:13 +0000195 // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
196 // CHECK-NEXT: [[T0:%.*]] = call i8* @test6_source()
197 // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
198 // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T1]])
199 // CHECK-NEXT: call void @objc_release(i8* [[T1]])
200 // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
Fariborz Jahanianf22ae652012-11-01 18:32:55 +0000201 // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT
Fariborz Jahaniana97d2ec2012-11-10 18:30:40 +0000202 // CHECK: store i32 -1040187392,
John McCall3382f652011-11-09 02:16:13 +0000203 // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
204 // CHECK-NEXT: store i8* [[T0]], i8**
205 // CHECK: call void @test6_helper(
206 // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
207 // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
208 // CHECK-NEXT: call void @objc_destroyWeak(i8** [[SLOT]])
209 // CHECK-NEXT: ret void
210
211 // CHECK: define internal void @__Block_byref_object_copy_
212 // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
213 // CHECK-NEXT: load i8**
214 // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]*
215 // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
216 // CHECK-NEXT: call void @objc_moveWeak(i8** [[T0]], i8** [[T1]])
217
218 // CHECK: define internal void @__Block_byref_object_dispose_
219 // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
220 // CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]])
221
Fariborz Jahanian4904bf42012-06-26 16:06:38 +0000222 // CHECK: define internal void @__test6_block_invoke
John McCall3382f652011-11-09 02:16:13 +0000223 // CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6
224 // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[SLOT]], i8* null)
225 // CHECK-NEXT: ret void
226
227 // CHECK: define internal void @__copy_helper_block_
228 // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control)
229 // CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8)
230
231 // CHECK: define internal void @__destroy_helper_block_
232 // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control)
233 // CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8)
234}
235
236void test7(void) {
237 id test7_source(void);
238 void test7_helper(void (^)(void));
239 void test7_consume(id);
240 __weak id var = test7_source();
241 test7_helper(^{ test7_consume(var); });
242
243 // CHECK: define void @test7()
244 // CHECK: [[VAR:%.*]] = alloca i8*,
245 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
246 // CHECK: [[T0:%.*]] = call i8* @test7_source()
247 // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
248 // CHECK-NEXT: call i8* @objc_initWeak(i8** [[VAR]], i8* [[T1]])
249 // CHECK-NEXT: call void @objc_release(i8* [[T1]])
Fariborz Jahanianf22ae652012-11-01 18:32:55 +0000250 // 0x42800000 - has signature, copy/dispose helpers, as well as BLOCK_HAS_EXTENDED_LAYOUT
Fariborz Jahaniana97d2ec2012-11-10 18:30:40 +0000251 // CHECK: store i32 -1040187392,
John McCall3382f652011-11-09 02:16:13 +0000252 // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
253 // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[VAR]])
254 // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T0]])
255 // CHECK: call void @test7_helper(
John McCall1a343eb2011-11-10 08:15:53 +0000256 // CHECK-NEXT: call void @objc_destroyWeak(i8** {{%.*}})
John McCallb99785b2011-11-10 09:22:44 +0000257 // CHECK-NEXT: call void @objc_destroyWeak(i8** [[VAR]])
John McCall3382f652011-11-09 02:16:13 +0000258 // CHECK-NEXT: ret void
259
Fariborz Jahanian4904bf42012-06-26 16:06:38 +0000260 // CHECK: define internal void @__test7_block_invoke
John McCall3382f652011-11-09 02:16:13 +0000261 // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* {{%.*}}, i32 0, i32 5
262 // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[SLOT]])
263 // CHECK-NEXT: call void @test7_consume(i8* [[T0]])
264 // CHECK-NEXT: ret void
265
266 // CHECK: define internal void @__copy_helper_block_
267 // CHECK: getelementptr
268 // CHECK-NEXT: getelementptr
269 // CHECK-NEXT: call void @objc_copyWeak(
270
271 // CHECK: define internal void @__destroy_helper_block_
272 // CHECK: getelementptr
273 // CHECK-NEXT: call void @objc_destroyWeak(
274}
275
276@interface Test8 @end
277@implementation Test8
278- (void) test {
279// CHECK: define internal void @"\01-[Test8 test]"
280// CHECK: [[SELF:%.*]] = alloca [[TEST8:%.*]]*,
281// CHECK-NEXT: alloca i8*
282// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
283// CHECK: store
284// CHECK-NEXT: store
John McCall1a343eb2011-11-10 08:15:53 +0000285// CHECK: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
John McCall3382f652011-11-09 02:16:13 +0000286// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
287// CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]** [[SELF]],
288// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8*
289// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
290// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST8]]*
291// CHECK-NEXT: store [[TEST8]]* [[T4]], [[TEST8]]** [[T0]]
292// CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to
293// CHECK: call void @test8_helper(
John McCall1a343eb2011-11-10 08:15:53 +0000294// CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]** [[D0]]
John McCall3382f652011-11-09 02:16:13 +0000295// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8*
296// CHECK-NEXT: call void @objc_release(i8* [[T2]])
297// CHECK-NEXT: ret void
298
299 extern void test8_helper(void (^)(void));
300 test8_helper(^{ (void) self; });
301}
302@end
303
304id test9(void) {
305 typedef id __attribute__((ns_returns_retained)) blocktype(void);
John McCallb99785b2011-11-10 09:22:44 +0000306 extern void test9_consume_block(blocktype^);
John McCall3382f652011-11-09 02:16:13 +0000307 return ^blocktype {
308 extern id test9_produce(void);
309 return test9_produce();
310 }();
311
312// CHECK: define i8* @test9(
313// CHECK: load i8** getelementptr
314// CHECK-NEXT: bitcast i8*
315// CHECK-NEXT: call i8*
316// CHECK-NEXT: call i8* @objc_autoreleaseReturnValue
317// CHECK-NEXT: ret i8*
318
319// CHECK: call i8* @test9_produce()
320// CHECK-NEXT: call i8* @objc_retain
321// CHECK-NEXT: ret i8*
322}
323
324// rdar://problem/9814099
325// Test that we correctly initialize __block variables
326// when the initialization captures the variable.
327void test10a(void) {
328 __block void (^block)(void) = ^{ block(); };
329 // CHECK: define void @test10a()
330 // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]],
331
332 // Zero-initialization before running the initializer.
333 // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
334 // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8
335
336 // Run the initializer as an assignment.
337 // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8*
338 // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainBlock(i8* [[T0]])
339 // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()*
340 // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 1
341 // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]** [[T3]]
342 // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T4]], i32 0, i32 6
343 // CHECK-NEXT: [[T6:%.*]] = load void ()** [[T5]], align 8
344 // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8
345 // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8*
346 // CHECK-NEXT: call void @objc_release(i8* [[T7]])
347
348 // Destroy at end of function.
349 // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
350 // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8*
351 // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
352 // CHECK-NEXT: [[T1:%.*]] = load void ()** [[SLOT]]
353 // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8*
354 // CHECK-NEXT: call void @objc_release(i8* [[T2]])
355 // CHECK-NEXT: ret void
356}
357
John McCalla59e4b72011-11-09 03:17:26 +0000358// <rdar://problem/10402698>: do this copy and dispose with
359// objc_retainBlock/release instead of _Block_object_assign/destroy.
360// We can also use _Block_object_assign/destroy with
361// BLOCK_FIELD_IS_BLOCK as long as we don't pass BLOCK_BYREF_CALLER.
362
363// CHECK: define internal void @__Block_byref_object_copy
364// CHECK: [[D0:%.*]] = load i8** {{%.*}}
365// CHECK-NEXT: [[D1:%.*]] = bitcast i8* [[D0]] to [[BYREF_T]]*
366// CHECK-NEXT: [[D2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[D1]], i32 0, i32 6
367// CHECK-NEXT: [[S0:%.*]] = load i8** {{%.*}}
368// CHECK-NEXT: [[S1:%.*]] = bitcast i8* [[S0]] to [[BYREF_T]]*
369// CHECK-NEXT: [[S2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[S1]], i32 0, i32 6
370// CHECK-NEXT: [[T0:%.*]] = load void ()** [[S2]], align 8
371// CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
372// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
373// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()*
374// CHECK-NEXT: store void ()* [[T3]], void ()** [[D2]], align 8
375// CHECK-NEXT: ret void
376
377// CHECK: define internal void @__Block_byref_object_dispose
378// CHECK: [[T0:%.*]] = load i8** {{%.*}}
379// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BYREF_T]]*
380// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T1]], i32 0, i32 6
John McCall015f33b2012-10-17 02:28:37 +0000381// CHECK-NEXT: [[T3:%.*]] = load void ()** [[T2]]
John McCalla59e4b72011-11-09 03:17:26 +0000382// CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8*
383// CHECK-NEXT: call void @objc_release(i8* [[T4]])
384// CHECK-NEXT: ret void
385
John McCall3382f652011-11-09 02:16:13 +0000386// Test that we correctly assign to __block variables when the
387// assignment captures the variable.
388void test10b(void) {
389 __block void (^block)(void);
390 block = ^{ block(); };
391
392 // CHECK: define void @test10b()
393 // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]],
394
395 // Zero-initialize.
396 // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
397 // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8
398
399 // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
400
401 // The assignment.
402 // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8*
403 // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainBlock(i8* [[T0]])
404 // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()*
405 // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 1
406 // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]** [[T3]]
407 // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T4]], i32 0, i32 6
408 // CHECK-NEXT: [[T6:%.*]] = load void ()** [[T5]], align 8
409 // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8
410 // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8*
411 // CHECK-NEXT: call void @objc_release(i8* [[T7]])
412
413 // Destroy at end of function.
414 // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8*
415 // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
416 // CHECK-NEXT: [[T1:%.*]] = load void ()** [[SLOT]]
417 // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8*
418 // CHECK-NEXT: call void @objc_release(i8* [[T2]])
419 // CHECK-NEXT: ret void
420}
421
422// rdar://problem/10088932
423void test11_helper(id);
424void test11a(void) {
425 int x;
426 test11_helper(^{ (void) x; });
427
428 // CHECK: define void @test11a()
429 // CHECK: [[X:%.*]] = alloca i32, align 4
430 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8
431 // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
432 // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
433 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
434 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()*
435 // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8*
436 // CHECK-NEXT: call void @test11_helper(i8* [[T4]])
437 // CHECK-NEXT: [[T5:%.*]] = bitcast void ()* [[T3]] to i8*
438 // CHECK-NEXT: call void @objc_release(i8* [[T5]])
439 // CHECK-NEXT: ret void
440}
441void test11b(void) {
442 int x;
443 id b = ^{ (void) x; };
444
445 // CHECK: define void @test11b()
446 // CHECK: [[X:%.*]] = alloca i32, align 4
447 // CHECK-NEXT: [[B:%.*]] = alloca i8*, align 8
448 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8
449 // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
450 // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
451 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
452 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()*
453 // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8*
454 // CHECK-NEXT: store i8* [[T4]], i8** [[B]], align 8
455 // CHECK-NEXT: [[T5:%.*]] = load i8** [[B]]
456 // CHECK-NEXT: call void @objc_release(i8* [[T5]])
457 // CHECK-NEXT: ret void
458}
459
460// rdar://problem/9979150
461@interface Test12
462@property (strong) void(^ablock)(void);
463@property (nonatomic, strong) void(^nblock)(void);
464@end
465@implementation Test12
466@synthesize ablock, nblock;
467// CHECK: define internal void ()* @"\01-[Test12 ablock]"(
468// CHECK: call i8* @objc_getProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i1 zeroext true)
469
470// CHECK: define internal void @"\01-[Test12 setAblock:]"(
471// CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext true, i1 zeroext true)
472
473// CHECK: define internal void ()* @"\01-[Test12 nblock]"(
474// CHECK: call i8* @objc_getProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i1 zeroext false)
475
476// CHECK: define internal void @"\01-[Test12 setNblock:]"(
477// CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext false, i1 zeroext true)
478@end
John McCallb99785b2011-11-10 09:22:44 +0000479
480// rdar://problem/10131784
481void test13(id x) {
482 extern void test13_helper(id);
483 extern void test13_use(void(^)(void));
484
485 void (^b)(void) = (x ? ^{test13_helper(x);} : 0);
486 test13_use(b);
487
488 // CHECK: define void @test13(
489 // CHECK: [[X:%.*]] = alloca i8*, align 8
490 // CHECK-NEXT: [[B:%.*]] = alloca void ()*, align 8
491 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:.*]], align 8
492 // CHECK-NEXT: [[CLEANUP_ACTIVE:%.*]] = alloca i1
John McCallb99785b2011-11-10 09:22:44 +0000493 // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_retain(i8* {{%.*}})
494 // CHECK-NEXT: store i8* [[T0]], i8** [[X]], align 8
495 // CHECK-NEXT: [[CLEANUP_ADDR:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
496 // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]], align 8
497 // CHECK-NEXT: [[T1:%.*]] = icmp ne i8* [[T0]], null
John McCall6f103ba2011-11-10 10:43:54 +0000498 // CHECK-NEXT: store i1 false, i1* [[CLEANUP_ACTIVE]]
John McCallb99785b2011-11-10 09:22:44 +0000499 // CHECK-NEXT: br i1 [[T1]],
500
501 // CHECK-NOT: br
502 // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
503 // CHECK-NEXT: [[T0:%.*]] = load i8** [[X]], align 8
504 // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
505 // CHECK-NEXT: store i8* [[T1]], i8** [[CAPTURE]], align 8
506 // CHECK-NEXT: store i1 true, i1* [[CLEANUP_ACTIVE]]
507 // CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
508 // CHECK-NEXT: br label
509 // CHECK: br label
510 // CHECK: [[T0:%.*]] = phi void ()*
511 // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
512 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
513 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()*
514 // CHECK-NEXT: store void ()* [[T3]], void ()** [[B]], align 8
515 // CHECK-NEXT: [[T0:%.*]] = load void ()** [[B]], align 8
516 // CHECK-NEXT: call void @test13_use(void ()* [[T0]])
517 // CHECK-NEXT: [[T0:%.*]] = load void ()** [[B]]
518 // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
519 // CHECK-NEXT: call void @objc_release(i8* [[T1]])
520
521 // CHECK-NEXT: [[T0:%.*]] = load i1* [[CLEANUP_ACTIVE]]
522 // CHECK-NEXT: br i1 [[T0]]
523 // CHECK: [[T0:%.*]] = load i8** [[CLEANUP_ADDR]]
524 // CHECK-NEXT: call void @objc_release(i8* [[T0]])
525 // CHECK-NEXT: br label
526
527 // CHECK: [[T0:%.*]] = load i8** [[X]]
528 // CHECK-NEXT: call void @objc_release(i8* [[T0]])
529 // CHECK-NEXT: ret void
530}
531
Eli Friedman5c89c392012-02-23 02:25:10 +0000532// <rdar://problem/10907510>
533void test14() {
534 void (^const x[1])(void) = { ^{} };
535}
John McCall73f428c2012-04-04 01:27:53 +0000536
537// rdar://11149025
538// Don't make invalid ASTs and crash.
539void test15_helper(void (^block)(void), int x);
540void test15(int a) {
541 test15_helper(^{ (void) a; }, ({ a; }));
542}
Fariborz Jahanianddfc8a12012-06-19 20:53:26 +0000543
544// rdar://11016025
545void test16() {
546 void (^BLKVAR)(void) = ^{ BLKVAR(); };
547
548 // CHECK: define void @test16(
549 // CHECK: [[BLKVAR:%.*]] = alloca void ()*, align 8
550 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
551 // CHECK-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
552 // CHECK-NEXT: store void ()* null, void ()** [[BLKVAR]], align 8
553}
John McCall9f357de2012-09-25 06:56:03 +0000554
555// rdar://12151005
556//
557// This is an intentional exception to our conservative jump-scope
558// checking for full-expressions containing block literals with
559// non-trivial cleanups: if the block literal appears in the operand
560// of a return statement, there's no need to extend its lifetime.
561id (^test17(id self, int which))(void) {
562 switch (which) {
563 case 1: return ^{ return self; };
564 case 0: return ^{ return self; };
565 }
566 return (void*) 0;
567}
568// CHECK: define i8* ()* @test17(
569// CHECK: [[RET:%.*]] = alloca i8* ()*, align
570// CHECK-NEXT: [[SELF:%.*]] = alloca i8*,
571// CHECK: [[B0:%.*]] = alloca [[BLOCK:<.*>]], align
572// CHECK: [[B1:%.*]] = alloca [[BLOCK]], align
573// CHECK: [[T0:%.*]] = call i8* @objc_retain(i8*
574// CHECK-NEXT: store i8* [[T0]], i8** [[SELF]], align
575// CHECK-NOT: objc_retain
576// CHECK-NOT: objc_release
577// CHECK: [[DESTROY:%.*]] = getelementptr inbounds [[BLOCK]]* [[B0]], i32 0, i32 5
578// CHECK-NOT: objc_retain
579// CHECK-NOT: objc_release
580// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK]]* [[B0]], i32 0, i32 5
581// CHECK-NEXT: [[T1:%.*]] = load i8** [[SELF]], align
582// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
583// CHECK-NEXT: store i8* [[T2]], i8** [[T0]],
584// CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK]]* [[B0]] to i8* ()*
585// CHECK-NEXT: [[T1:%.*]] = bitcast i8* ()* [[T0]] to i8*
586// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
587// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i8* ()*
588// CHECK-NEXT: store i8* ()* [[T3]], i8* ()** [[RET]]
589// CHECK-NEXT: [[T0:%.*]] = load i8** [[DESTROY]]
590// CHECK-NEXT: call void @objc_release(i8* [[T0]])
591// CHECK-NEXT: store i32
592// CHECK-NEXT: br label
593// CHECK-NOT: objc_retain
594// CHECK-NOT: objc_release
595// CHECK: [[DESTROY:%.*]] = getelementptr inbounds [[BLOCK]]* [[B1]], i32 0, i32 5
596// CHECK-NOT: objc_retain
597// CHECK-NOT: objc_release
598// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK]]* [[B1]], i32 0, i32 5
599// CHECK-NEXT: [[T1:%.*]] = load i8** [[SELF]], align
600// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retain(i8* [[T1]])
601// CHECK-NEXT: store i8* [[T2]], i8** [[T0]],
602// CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK]]* [[B1]] to i8* ()*
603// CHECK-NEXT: [[T1:%.*]] = bitcast i8* ()* [[T0]] to i8*
604// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
605// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i8* ()*
606// CHECK-NEXT: store i8* ()* [[T3]], i8* ()** [[RET]]
607// CHECK-NEXT: [[T0:%.*]] = load i8** [[DESTROY]]
608// CHECK-NEXT: call void @objc_release(i8* [[T0]])
609// CHECK-NEXT: store i32
610// CHECK-NEXT: br label
John McCall015f33b2012-10-17 02:28:37 +0000611
612void test18(id x) {
613// CHECK-UNOPT: define void @test18(
614// CHECK-UNOPT: [[X:%.*]] = alloca i8*,
615// CHECK-UNOPT-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
616// CHECK-UNOPT-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}})
617// CHECK-UNOPT-NEXT: store i8* [[PARM]], i8** [[X]]
618// CHECK-UNOPT-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
619// CHECK-UNOPT: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
620// CHECK-UNOPT-NEXT: [[T0:%.*]] = load i8** [[X]],
621// CHECK-UNOPT-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
622// CHECK-UNOPT-NEXT: store i8* [[T1]], i8** [[SLOT]],
623// CHECK-UNOPT-NEXT: bitcast
624// CHECK-UNOPT-NEXT: call void @test18_helper(
625// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[SLOTREL]], i8* null) nounwind
626// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[X]], i8* null) nounwind
627// CHECK-UNOPT-NEXT: ret void
628 extern void test18_helper(id (^)(void));
629 test18_helper(^{ return x; });
630
631// CHECK-UNOPT: define internal void @__copy_helper_block_
632// CHECK-UNOPT: [[T0:%.*]] = load i8**
633// CHECK-UNOPT-NEXT: [[SRC:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]*
634// CHECK-UNOPT-NEXT: [[T0:%.*]] = load i8**
635// CHECK-UNOPT-NEXT: [[DST:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]*
636// CHECK-UNOPT-NEXT: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[SRC]], i32 0, i32 5
637// CHECK-UNOPT-NEXT: [[T1:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[DST]], i32 0, i32 5
638// CHECK-UNOPT-NEXT: [[T2:%.*]] = load i8** [[T0]]
639// CHECK-UNOPT-NEXT: store i8* null, i8** [[T1]]
640// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[T1]], i8* [[T2]]) nounwind
641// CHECK-UNOPT-NEXT: ret void
642
643// CHECK-UNOPT: define internal void @__destroy_helper_block_
644// CHECK-UNOPT: [[T0:%.*]] = load i8**
645// CHECK-UNOPT-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BLOCK_T]]*
646// CHECK-UNOPT-NEXT: [[T2:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[T1]], i32 0, i32 5
647// CHECK-UNOPT-NEXT: call void @objc_storeStrong(i8** [[T2]], i8* null)
648// CHECK-UNOPT-NEXT: ret void
649}