blob: 6ca5c3c352d3ce2ef9a3bf89ee4d9b3f37973962 [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
2
3// This shouldn't crash.
4void test0(id (^maker)(void)) {
5 maker();
6}
7
8int (^test1(int x))(void) {
9 // CHECK: define i32 ()* @test1(
10 // CHECK: [[X:%.*]] = alloca i32,
11 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
12 // CHECK-NEXT: store i32 {{%.*}}, i32* [[X]]
13 // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to i32 ()*
14 // CHECK-NEXT: [[T1:%.*]] = bitcast i32 ()* [[T0]] to i8*
15 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]]) nounwind
16 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to i32 ()*
17 // CHECK-NEXT: [[T4:%.*]] = bitcast i32 ()* [[T3]] to i8*
18 // CHECK-NEXT: [[T5:%.*]] = call i8* @objc_autoreleaseReturnValue(i8* [[T4]]) nounwind
19 // CHECK-NEXT: [[T6:%.*]] = bitcast i8* [[T5]] to i32 ()*
20 // CHECK-NEXT: ret i32 ()* [[T6]]
21 return ^{ return x; };
22}
23
24void test2(id x) {
25// CHECK: define void @test2(
26// CHECK: [[X:%.*]] = alloca i8*,
27// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
John McCall1a343eb2011-11-10 08:15:53 +000028// CHECK-NEXT: alloca i1
29// CHECK-NEXT: store i1 false
John McCall3382f652011-11-09 02:16:13 +000030// CHECK-NEXT: [[PARM:%.*]] = call i8* @objc_retain(i8* {{%.*}})
31// CHECK-NEXT: store i8* [[PARM]], i8** [[X]]
John McCall1a343eb2011-11-10 08:15:53 +000032// CHECK-NEXT: [[SLOTREL:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
John McCall3382f652011-11-09 02:16:13 +000033// CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
34// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]],
35// CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
36// CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]],
John McCall1a343eb2011-11-10 08:15:53 +000037// CHECK-NEXT: store i1 true
John McCall3382f652011-11-09 02:16:13 +000038// CHECK-NEXT: bitcast
39// CHECK-NEXT: call void @test2_helper(
John McCall1a343eb2011-11-10 08:15:53 +000040// CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOTREL]]
John McCall3382f652011-11-09 02:16:13 +000041// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
42// CHECK-NEXT: [[T0:%.*]] = load i8** [[X]]
43// CHECK-NEXT: call void @objc_release(i8* [[T0]]) nounwind, !clang.imprecise_release
44// CHECK-NEXT: ret void
45 extern void test2_helper(id (^)(void));
46 test2_helper(^{ return x; });
47}
48
49void test3(void (^sink)(id*)) {
50 __strong id strong;
51 sink(&strong);
52
53 // CHECK: define void @test3(
54 // CHECK: [[SINK:%.*]] = alloca void (i8**)*
55 // CHECK-NEXT: [[STRONG:%.*]] = alloca i8*
56 // CHECK-NEXT: [[TEMP:%.*]] = alloca i8*
57 // CHECK-NEXT: bitcast void (i8**)* {{%.*}} to i8*
58 // CHECK-NEXT: call i8* @objc_retain(
59 // CHECK-NEXT: bitcast i8*
60 // CHECK-NEXT: store void (i8**)* {{%.*}}, void (i8**)** [[SINK]]
61 // CHECK-NEXT: store i8* null, i8** [[STRONG]]
62
63 // CHECK-NEXT: load void (i8**)** [[SINK]]
64 // CHECK-NEXT: bitcast
65 // CHECK-NEXT: getelementptr
66 // CHECK-NEXT: [[BLOCK:%.*]] = bitcast
67 // CHECK-NEXT: [[T0:%.*]] = load i8** [[STRONG]]
68 // CHECK-NEXT: store i8* [[T0]], i8** [[TEMP]]
69 // CHECK-NEXT: [[F0:%.*]] = load i8**
70 // CHECK-NEXT: [[F1:%.*]] = bitcast i8* [[F0]] to void (i8*, i8**)*
71 // CHECK-NEXT: call void [[F1]](i8* [[BLOCK]], i8** [[TEMP]])
72 // CHECK-NEXT: [[T0:%.*]] = load i8** [[TEMP]]
73 // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retain(i8* [[T0]])
74 // CHECK-NEXT: [[T2:%.*]] = load i8** [[STRONG]]
75 // CHECK-NEXT: store i8* [[T1]], i8** [[STRONG]]
76 // CHECK-NEXT: call void @objc_release(i8* [[T2]])
77
78 // CHECK-NEXT: [[T0:%.*]] = load i8** [[STRONG]]
79 // CHECK-NEXT: call void @objc_release(i8* [[T0]])
80
81 // CHECK-NEXT: load void (i8**)** [[SINK]]
82 // CHECK-NEXT: bitcast
83 // CHECK-NEXT: call void @objc_release
84 // CHECK-NEXT: ret void
85
86}
87
88void test4(void) {
89 id test4_source(void);
90 void test4_helper(void (^)(void));
91 __block id var = test4_source();
92 test4_helper(^{ var = 0; });
93
94 // CHECK: define void @test4()
95 // CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
96 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
97 // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2
98 // 0x02000000 - has copy/dispose helpers
99 // CHECK-NEXT: store i32 33554432, i32* [[T0]]
100 // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
101 // CHECK-NEXT: [[T0:%.*]] = call i8* @test4_source()
102 // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
103 // CHECK-NEXT: store i8* [[T1]], i8** [[SLOT]]
104 // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
105 // 0x42000000 - has signature, copy/dispose helpers
106 // CHECK: store i32 1107296256,
107 // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
108 // CHECK-NEXT: store i8* [[T0]], i8**
109 // CHECK: call void @test4_helper(
110 // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
111 // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
112 // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]]
113 // CHECK-NEXT: call void @objc_release(i8* [[T0]])
114 // CHECK-NEXT: ret void
115
116 // CHECK: define internal void @__Block_byref_object_copy_
117 // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
118 // CHECK-NEXT: load i8**
119 // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]*
120 // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
121 // CHECK-NEXT: [[T2:%.*]] = load i8** [[T1]]
122 // CHECK-NEXT: store i8* [[T2]], i8** [[T0]]
123 // CHECK-NEXT: store i8* null, i8** [[T1]]
124
125 // CHECK: define internal void @__Block_byref_object_dispose_
126 // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
127 // CHECK-NEXT: [[T1:%.*]] = load i8** [[T0]]
128 // CHECK-NEXT: call void @objc_release(i8* [[T1]])
129
130 // CHECK: define internal void @__test4_block_invoke_
131 // CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6
132 // CHECK-NEXT: [[T0:%.*]] = load i8** [[SLOT]], align 8
133 // CHECK-NEXT: store i8* null, i8** [[SLOT]],
134 // CHECK-NEXT: call void @objc_release(i8* [[T0]])
135 // CHECK-NEXT: ret void
136
137 // CHECK: define internal void @__copy_helper_block_
138 // CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8)
139
140 // CHECK: define internal void @__destroy_helper_block_
141 // CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8)
142}
143
144void test5(void) {
145 extern id test5_source(void);
146 void test5_helper(void (^)(void));
147 __unsafe_unretained id var = test5_source();
148 test5_helper(^{ (void) var; });
149
150 // CHECK: define void @test5()
151 // CHECK: [[VAR:%.*]] = alloca i8*
152 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
153 // CHECK: [[T0:%.*]] = call i8* @test5_source()
154 // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
155 // CHECK-NEXT: store i8* [[T1]], i8** [[VAR]],
156 // CHECK-NEXT: call void @objc_release(i8* [[T1]])
157 // 0x40000000 - has signature but no copy/dispose
158 // CHECK: store i32 1073741824, i32*
159 // CHECK: [[CAPTURE:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
160 // CHECK-NEXT: [[T0:%.*]] = load i8** [[VAR]]
161 // CHECK-NEXT: store i8* [[T0]], i8** [[CAPTURE]]
162 // CHECK-NEXT: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to
163 // CHECK: call void @test5_helper
164 // CHECK-NEXT: ret void
165}
166
167void test6(void) {
168 id test6_source(void);
169 void test6_helper(void (^)(void));
170 __block __weak id var = test6_source();
171 test6_helper(^{ var = 0; });
172
173 // CHECK: define void @test6()
174 // CHECK: [[VAR:%.*]] = alloca [[BYREF_T:%.*]],
175 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
176 // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 2
177 // 0x02000000 - has copy/dispose helpers
178 // CHECK-NEXT: store i32 33554432, i32* [[T0]]
179 // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
180 // CHECK-NEXT: [[T0:%.*]] = call i8* @test6_source()
181 // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
182 // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T1]])
183 // CHECK-NEXT: call void @objc_release(i8* [[T1]])
184 // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[VAR]], i32 0, i32 6
185 // 0x42000000 - has signature, copy/dispose helpers
186 // CHECK: store i32 1107296256,
187 // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
188 // CHECK-NEXT: store i8* [[T0]], i8**
189 // CHECK: call void @test6_helper(
190 // CHECK: [[T0:%.*]] = bitcast [[BYREF_T]]* [[VAR]] to i8*
191 // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
192 // CHECK-NEXT: call void @objc_destroyWeak(i8** [[SLOT]])
193 // CHECK-NEXT: ret void
194
195 // CHECK: define internal void @__Block_byref_object_copy_
196 // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
197 // CHECK-NEXT: load i8**
198 // CHECK-NEXT: bitcast i8* {{%.*}} to [[BYREF_T]]*
199 // CHECK-NEXT: [[T1:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
200 // CHECK-NEXT: call void @objc_moveWeak(i8** [[T0]], i8** [[T1]])
201
202 // CHECK: define internal void @__Block_byref_object_dispose_
203 // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* {{%.*}}, i32 0, i32 6
204 // CHECK-NEXT: call void @objc_destroyWeak(i8** [[T0]])
205
206 // CHECK: define internal void @__test6_block_invoke_
207 // CHECK: [[SLOT:%.*]] = getelementptr inbounds {{.*}}, i32 0, i32 6
208 // CHECK-NEXT: call i8* @objc_storeWeak(i8** [[SLOT]], i8* null)
209 // CHECK-NEXT: ret void
210
211 // CHECK: define internal void @__copy_helper_block_
212 // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control)
213 // CHECK: call void @_Block_object_assign(i8* {{%.*}}, i8* {{%.*}}, i32 8)
214
215 // CHECK: define internal void @__destroy_helper_block_
216 // 0x8 - FIELD_IS_BYREF (no FIELD_IS_WEAK because clang in control)
217 // CHECK: call void @_Block_object_dispose(i8* {{%.*}}, i32 8)
218}
219
220void test7(void) {
221 id test7_source(void);
222 void test7_helper(void (^)(void));
223 void test7_consume(id);
224 __weak id var = test7_source();
225 test7_helper(^{ test7_consume(var); });
226
227 // CHECK: define void @test7()
228 // CHECK: [[VAR:%.*]] = alloca i8*,
229 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
230 // CHECK: [[T0:%.*]] = call i8* @test7_source()
231 // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainAutoreleasedReturnValue(i8* [[T0]])
232 // CHECK-NEXT: call i8* @objc_initWeak(i8** [[VAR]], i8* [[T1]])
233 // CHECK-NEXT: call void @objc_release(i8* [[T1]])
234 // 0x42000000 - has signature, copy/dispose helpers
235 // CHECK: store i32 1107296256,
236 // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
237 // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[VAR]])
238 // CHECK-NEXT: call i8* @objc_initWeak(i8** [[SLOT]], i8* [[T0]])
239 // CHECK: call void @test7_helper(
John McCall1a343eb2011-11-10 08:15:53 +0000240 // CHECK-NEXT: call void @objc_destroyWeak(i8** {{%.*}})
241 // CHECK: call void @objc_destroyWeak(i8** [[VAR]])
John McCall3382f652011-11-09 02:16:13 +0000242 // CHECK-NEXT: ret void
243
244 // CHECK: define internal void @__test7_block_invoke_
245 // CHECK: [[SLOT:%.*]] = getelementptr inbounds [[BLOCK_T]]* {{%.*}}, i32 0, i32 5
246 // CHECK-NEXT: [[T0:%.*]] = call i8* @objc_loadWeak(i8** [[SLOT]])
247 // CHECK-NEXT: call void @test7_consume(i8* [[T0]])
248 // CHECK-NEXT: ret void
249
250 // CHECK: define internal void @__copy_helper_block_
251 // CHECK: getelementptr
252 // CHECK-NEXT: getelementptr
253 // CHECK-NEXT: call void @objc_copyWeak(
254
255 // CHECK: define internal void @__destroy_helper_block_
256 // CHECK: getelementptr
257 // CHECK-NEXT: call void @objc_destroyWeak(
258}
259
260@interface Test8 @end
261@implementation Test8
262- (void) test {
263// CHECK: define internal void @"\01-[Test8 test]"
264// CHECK: [[SELF:%.*]] = alloca [[TEST8:%.*]]*,
265// CHECK-NEXT: alloca i8*
266// CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]],
267// CHECK: store
268// CHECK-NEXT: store
John McCall1a343eb2011-11-10 08:15:53 +0000269// CHECK: [[D0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
John McCall3382f652011-11-09 02:16:13 +0000270// CHECK: [[T0:%.*]] = getelementptr inbounds [[BLOCK_T]]* [[BLOCK]], i32 0, i32 5
271// CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]** [[SELF]],
272// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8*
273// CHECK-NEXT: [[T3:%.*]] = call i8* @objc_retain(i8* [[T2]])
274// CHECK-NEXT: [[T4:%.*]] = bitcast i8* [[T3]] to [[TEST8]]*
275// CHECK-NEXT: store [[TEST8]]* [[T4]], [[TEST8]]** [[T0]]
John McCall1a343eb2011-11-10 08:15:53 +0000276// CHECK-NEXT: store i1 true,
John McCall3382f652011-11-09 02:16:13 +0000277// CHECK-NEXT: bitcast [[BLOCK_T]]* [[BLOCK]] to
278// CHECK: call void @test8_helper(
John McCall1a343eb2011-11-10 08:15:53 +0000279// CHECK-NEXT: [[T1:%.*]] = load [[TEST8]]** [[D0]]
John McCall3382f652011-11-09 02:16:13 +0000280// CHECK-NEXT: [[T2:%.*]] = bitcast [[TEST8]]* [[T1]] to i8*
281// CHECK-NEXT: call void @objc_release(i8* [[T2]])
282// CHECK-NEXT: ret void
283
284 extern void test8_helper(void (^)(void));
285 test8_helper(^{ (void) self; });
286}
287@end
288
289id test9(void) {
290 typedef id __attribute__((ns_returns_retained)) blocktype(void);
291 extern test9_consume_block(blocktype^);
292 return ^blocktype {
293 extern id test9_produce(void);
294 return test9_produce();
295 }();
296
297// CHECK: define i8* @test9(
298// CHECK: load i8** getelementptr
299// CHECK-NEXT: bitcast i8*
300// CHECK-NEXT: call i8*
301// CHECK-NEXT: call i8* @objc_autoreleaseReturnValue
302// CHECK-NEXT: ret i8*
303
304// CHECK: call i8* @test9_produce()
305// CHECK-NEXT: call i8* @objc_retain
306// CHECK-NEXT: ret i8*
307}
308
309// rdar://problem/9814099
310// Test that we correctly initialize __block variables
311// when the initialization captures the variable.
312void test10a(void) {
313 __block void (^block)(void) = ^{ block(); };
314 // CHECK: define void @test10a()
315 // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]],
316
317 // Zero-initialization before running the initializer.
318 // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
319 // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8
320
321 // Run the initializer as an assignment.
322 // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8*
323 // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainBlock(i8* [[T0]])
324 // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()*
325 // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 1
326 // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]** [[T3]]
327 // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T4]], i32 0, i32 6
328 // CHECK-NEXT: [[T6:%.*]] = load void ()** [[T5]], align 8
329 // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8
330 // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8*
331 // CHECK-NEXT: call void @objc_release(i8* [[T7]])
332
333 // Destroy at end of function.
334 // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
335 // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8*
336 // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
337 // CHECK-NEXT: [[T1:%.*]] = load void ()** [[SLOT]]
338 // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8*
339 // CHECK-NEXT: call void @objc_release(i8* [[T2]])
340 // CHECK-NEXT: ret void
341}
342
John McCalla59e4b72011-11-09 03:17:26 +0000343// <rdar://problem/10402698>: do this copy and dispose with
344// objc_retainBlock/release instead of _Block_object_assign/destroy.
345// We can also use _Block_object_assign/destroy with
346// BLOCK_FIELD_IS_BLOCK as long as we don't pass BLOCK_BYREF_CALLER.
347
348// CHECK: define internal void @__Block_byref_object_copy
349// CHECK: [[D0:%.*]] = load i8** {{%.*}}
350// CHECK-NEXT: [[D1:%.*]] = bitcast i8* [[D0]] to [[BYREF_T]]*
351// CHECK-NEXT: [[D2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[D1]], i32 0, i32 6
352// CHECK-NEXT: [[S0:%.*]] = load i8** {{%.*}}
353// CHECK-NEXT: [[S1:%.*]] = bitcast i8* [[S0]] to [[BYREF_T]]*
354// CHECK-NEXT: [[S2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[S1]], i32 0, i32 6
355// CHECK-NEXT: [[T0:%.*]] = load void ()** [[S2]], align 8
356// CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
357// CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
358// CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()*
359// CHECK-NEXT: store void ()* [[T3]], void ()** [[D2]], align 8
360// CHECK-NEXT: ret void
361
362// CHECK: define internal void @__Block_byref_object_dispose
363// CHECK: [[T0:%.*]] = load i8** {{%.*}}
364// CHECK-NEXT: [[T1:%.*]] = bitcast i8* [[T0]] to [[BYREF_T]]*
365// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T1]], i32 0, i32 6
366// CHECK-NEXT: [[T3:%.*]] = load void ()** [[T2]], align 8
367// CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8*
368// CHECK-NEXT: call void @objc_release(i8* [[T4]])
369// CHECK-NEXT: ret void
370
John McCall3382f652011-11-09 02:16:13 +0000371// Test that we correctly assign to __block variables when the
372// assignment captures the variable.
373void test10b(void) {
374 __block void (^block)(void);
375 block = ^{ block(); };
376
377 // CHECK: define void @test10b()
378 // CHECK: [[BYREF:%.*]] = alloca [[BYREF_T:%.*]],
379
380 // Zero-initialize.
381 // CHECK: [[T0:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
382 // CHECK-NEXT: store void ()* null, void ()** [[T0]], align 8
383
384 // CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 6
385
386 // The assignment.
387 // CHECK: [[T0:%.*]] = bitcast void ()* {{%.*}} to i8*
388 // CHECK-NEXT: [[T1:%.*]] = call i8* @objc_retainBlock(i8* [[T0]])
389 // CHECK-NEXT: [[T2:%.*]] = bitcast i8* [[T1]] to void ()*
390 // CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds [[BYREF_T]]* [[BYREF]], i32 0, i32 1
391 // CHECK-NEXT: [[T4:%.*]] = load [[BYREF_T]]** [[T3]]
392 // CHECK-NEXT: [[T5:%.*]] = getelementptr inbounds [[BYREF_T]]* [[T4]], i32 0, i32 6
393 // CHECK-NEXT: [[T6:%.*]] = load void ()** [[T5]], align 8
394 // CHECK-NEXT: store void ()* {{%.*}}, void ()** [[T5]], align 8
395 // CHECK-NEXT: [[T7:%.*]] = bitcast void ()* [[T6]] to i8*
396 // CHECK-NEXT: call void @objc_release(i8* [[T7]])
397
398 // Destroy at end of function.
399 // CHECK-NEXT: [[T0:%.*]] = bitcast [[BYREF_T]]* [[BYREF]] to i8*
400 // CHECK-NEXT: call void @_Block_object_dispose(i8* [[T0]], i32 8)
401 // CHECK-NEXT: [[T1:%.*]] = load void ()** [[SLOT]]
402 // CHECK-NEXT: [[T2:%.*]] = bitcast void ()* [[T1]] to i8*
403 // CHECK-NEXT: call void @objc_release(i8* [[T2]])
404 // CHECK-NEXT: ret void
405}
406
407// rdar://problem/10088932
408void test11_helper(id);
409void test11a(void) {
410 int x;
411 test11_helper(^{ (void) x; });
412
413 // CHECK: define void @test11a()
414 // CHECK: [[X:%.*]] = alloca i32, align 4
415 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8
416 // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
417 // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
418 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
419 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()*
420 // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8*
421 // CHECK-NEXT: call void @test11_helper(i8* [[T4]])
422 // CHECK-NEXT: [[T5:%.*]] = bitcast void ()* [[T3]] to i8*
423 // CHECK-NEXT: call void @objc_release(i8* [[T5]])
424 // CHECK-NEXT: ret void
425}
426void test11b(void) {
427 int x;
428 id b = ^{ (void) x; };
429
430 // CHECK: define void @test11b()
431 // CHECK: [[X:%.*]] = alloca i32, align 4
432 // CHECK-NEXT: [[B:%.*]] = alloca i8*, align 8
433 // CHECK-NEXT: [[BLOCK:%.*]] = alloca [[BLOCK_T:<{.*}>]], align 8
434 // CHECK: [[T0:%.*]] = bitcast [[BLOCK_T]]* [[BLOCK]] to void ()*
435 // CHECK-NEXT: [[T1:%.*]] = bitcast void ()* [[T0]] to i8*
436 // CHECK-NEXT: [[T2:%.*]] = call i8* @objc_retainBlock(i8* [[T1]])
437 // CHECK-NEXT: [[T3:%.*]] = bitcast i8* [[T2]] to void ()*
438 // CHECK-NEXT: [[T4:%.*]] = bitcast void ()* [[T3]] to i8*
439 // CHECK-NEXT: store i8* [[T4]], i8** [[B]], align 8
440 // CHECK-NEXT: [[T5:%.*]] = load i8** [[B]]
441 // CHECK-NEXT: call void @objc_release(i8* [[T5]])
442 // CHECK-NEXT: ret void
443}
444
445// rdar://problem/9979150
446@interface Test12
447@property (strong) void(^ablock)(void);
448@property (nonatomic, strong) void(^nblock)(void);
449@end
450@implementation Test12
451@synthesize ablock, nblock;
452// CHECK: define internal void ()* @"\01-[Test12 ablock]"(
453// CHECK: call i8* @objc_getProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i1 zeroext true)
454
455// CHECK: define internal void @"\01-[Test12 setAblock:]"(
456// CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext true, i1 zeroext true)
457
458// CHECK: define internal void ()* @"\01-[Test12 nblock]"(
459// CHECK: call i8* @objc_getProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i1 zeroext false)
460
461// CHECK: define internal void @"\01-[Test12 setNblock:]"(
462// CHECK: call void @objc_setProperty(i8* {{%.*}}, i8* {{%.*}}, i64 {{%.*}}, i8* {{%.*}}, i1 zeroext false, i1 zeroext true)
463@end