1 | // RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -print-ivar-layout -emit-llvm -o /dev/null %s > %t-64.layout |
2 | // RUN: FileCheck -check-prefix CHECK-LP64 --input-file=%t-64.layout %s |
3 | // rdar://12184410 |
4 | // rdar://12752901 |
5 | |
6 | void x(id y) {} |
7 | void y(int a) {} |
8 | |
9 | extern id opaque_id(); |
10 | |
11 | void f() { |
12 | __weak id wid; |
13 | __block int byref_int = 0; |
14 | char ch = 'a'; |
15 | char ch1 = 'b'; |
16 | char ch2 = 'c'; |
17 | short sh = 2; |
18 | const id bar = (id) opaque_id(); |
19 | id baz = 0; |
20 | __strong id strong_void_sta; |
21 | __block id byref_bab = (id)0; |
22 | __block id bl_var1; |
23 | int i; double dob; |
24 | |
25 | // The patterns here are a sequence of bytes, each saying first how |
26 | // many sizeof(void*) chunks to skip (high nibble) and then how many |
27 | // to scan (low nibble). A zero byte says that we've reached the end |
28 | // of the pattern. |
29 | // |
30 | // All of these patterns start with 01 3x because the block header on |
31 | // LP64 consists of an isa pointer (which we're supposed to scan for |
32 | // some reason) followed by three words (2 ints, a function pointer, |
33 | // and a descriptor pointer). |
34 | |
35 | // Test 1 |
36 | // Inline instruction for block variable layout: 0x0320 (3 strong 2 byref) |
37 | // CHECK-LP64: Inline block variable layout: 0x0320, BL_STRONG:3, BL_BYREF:2, BL_OPERATOR:0 |
38 | void (^b)() = ^{ |
39 | byref_int = sh + ch+ch1+ch2 ; |
40 | x(bar); |
41 | x(baz); |
42 | x((id)strong_void_sta); |
43 | x(byref_bab); |
44 | }; |
45 | b(); |
46 | |
47 | // Test 2 |
48 | // Inline instruction for block variable layout: 0x0331 (3 strong 3 byref 1 weak) |
49 | // CHECK-LP64: Inline block variable layout: 0x0331, BL_STRONG:3, BL_BYREF:3, BL_WEAK:1, BL_OPERATOR:0 |
50 | void (^c)() = ^{ |
51 | byref_int = sh + ch+ch1+ch2 ; |
52 | x(bar); |
53 | x(baz); |
54 | x((id)strong_void_sta); |
55 | x(wid); |
56 | bl_var1 = 0; |
57 | x(byref_bab); |
58 | }; |
59 | } |
60 | |
61 | @class NSString, NSNumber; |
62 | void g() { |
63 | NSString *foo; |
64 | NSNumber *bar; |
65 | unsigned int bletch; |
66 | __weak id weak_delegate; |
67 | unsigned int i; |
68 | NSString *y; |
69 | NSString *z; |
70 | // Inline instruction for block variable layout: 0x0401 (4 strong 0 byref 1 weak) |
71 | // CHECK-LP64: Inline block variable layout: 0x0401, BL_STRONG:4, BL_WEAK:1, BL_OPERATOR:0 |
72 | void (^c)() = ^{ |
73 | int j = i + bletch; |
74 | x(foo); |
75 | x(bar); |
76 | x(weak_delegate); |
77 | x(y); |
78 | x(z); |
79 | }; |
80 | c(); |
81 | } |
82 | |
83 | // Test 5 (unions/structs and their nesting): |
84 | void h() { |
85 | struct S5 { |
86 | int i1; |
87 | __unsafe_unretained id o1; |
88 | struct V { |
89 | int i2; |
90 | __unsafe_unretained id o2; |
91 | } v1; |
92 | int i3; |
93 | union UI { |
94 | void * i1; |
95 | __unsafe_unretained id o1; |
96 | int i3; |
97 | __unsafe_unretained id o3; |
98 | }ui; |
99 | }; |
100 | |
101 | union U { |
102 | void * i1; |
103 | __unsafe_unretained id o1; |
104 | int i3; |
105 | __unsafe_unretained id o3; |
106 | }ui; |
107 | |
108 | struct S5 s2; |
109 | union U u2; |
110 | __block id block_id; |
111 | |
112 | // CHECK-LP64: Block variable layout: BL_BYREF:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_OPERATOR:0 |
113 | void (^c)() = ^{ |
114 | x(s2.ui.o1); |
115 | x(u2.o1); |
116 | block_id = 0; |
117 | }; |
118 | c(); |
119 | } |
120 | |
121 | // Test for array of stuff. |
122 | void arr1() { |
123 | struct S { |
124 | __unsafe_unretained id unsafe_unretained_var[4]; |
125 | } imported_s; |
126 | |
127 | // CHECK-LP64: Block variable layout: BL_UNRETAINED:4, BL_OPERATOR:0 |
128 | void (^c)() = ^{ |
129 | x(imported_s.unsafe_unretained_var[2]); |
130 | }; |
131 | |
132 | c(); |
133 | } |
134 | |
135 | // Test2 for array of stuff. |
136 | void arr2() { |
137 | struct S { |
138 | int a; |
139 | __unsafe_unretained id unsafe_unretained_var[4]; |
140 | } imported_s; |
141 | |
142 | // CHECK-LP64: Block variable layout: BL_NON_OBJECT_WORD:1, BL_UNRETAINED:4, BL_OPERATOR:0 |
143 | void (^c)() = ^{ |
144 | x(imported_s.unsafe_unretained_var[2]); |
145 | }; |
146 | |
147 | c(); |
148 | } |
149 | |
150 | // Test3 for array of stuff. |
151 | void arr3() { |
152 | struct S { |
153 | int a; |
154 | __unsafe_unretained id unsafe_unretained_var[0]; |
155 | } imported_s; |
156 | |
157 | // CHECK-LP64: Block variable layout: BL_OPERATOR:0 |
158 | void (^c)() = ^{ |
159 | int i = imported_s.a; |
160 | }; |
161 | |
162 | c(); |
163 | } |
164 | |
165 | |
166 | // Test4 for array of stuff. |
167 | @class B; |
168 | void arr4() { |
169 | struct S { |
170 | struct s0 { |
171 | __unsafe_unretained id s_f0; |
172 | __unsafe_unretained id s_f1; |
173 | } f0; |
174 | |
175 | __unsafe_unretained id f1; |
176 | |
177 | struct s1 { |
178 | int *f0; |
179 | __unsafe_unretained B *f1; |
180 | } f4[2][2]; |
181 | } captured_s; |
182 | |
183 | // CHECK-LP64: Block variable layout: BL_UNRETAINED:3, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_NON_OBJECT_WORD:1, BL_UNRETAINED:1, BL_OPERATOR:0 |
184 | void (^c)() = ^{ |
185 | id i = captured_s.f0.s_f1; |
186 | }; |
187 | |
188 | c(); |
189 | } |
190 | |
191 | // Test1 bitfield in cpatured aggregate. |
192 | void bf1() { |
193 | struct S { |
194 | int flag : 25; |
195 | int flag1: 7; |
196 | int flag2 :1; |
197 | int flag3: 7; |
198 | int flag4: 24; |
199 | } s; |
200 | |
201 | // CHECK-LP64: Block variable layout: BL_OPERATOR:0 |
202 | int (^c)() = ^{ |
203 | return s.flag; |
204 | }; |
205 | c(); |
206 | } |
207 | |
208 | // Test2 bitfield in cpatured aggregate. |
209 | void bf2() { |
210 | struct S { |
211 | int flag : 1; |
212 | } s; |
213 | |
214 | // CHECK-LP64: Block variable layout: BL_OPERATOR:0 |
215 | int (^c)() = ^{ |
216 | return s.flag; |
217 | }; |
218 | c(); |
219 | } |
220 | |
221 | // Test3 bitfield in cpatured aggregate. |
222 | void bf3() { |
223 | |
224 | struct { |
225 | unsigned short _reserved : 16; |
226 | |
227 | unsigned char _draggedNodesAreDeletable: 1; |
228 | unsigned char _draggedOutsideOutlineView : 1; |
229 | unsigned char _adapterRespondsTo_addRootPaths : 1; |
230 | unsigned char _adapterRespondsTo_moveDataNodes : 1; |
231 | unsigned char _adapterRespondsTo_removeRootDataNode : 1; |
232 | unsigned char _adapterRespondsTo_doubleClickDataNode : 1; |
233 | unsigned char _adapterRespondsTo_selectDataNode : 1; |
234 | unsigned char _adapterRespondsTo_textDidEndEditing : 1; |
235 | unsigned char _adapterRespondsTo_updateAndSaveRoots : 1; |
236 | unsigned char _adapterRespondsTo_askToDeleteRootNodes : 1; |
237 | unsigned char _adapterRespondsTo_contextMenuForSelectedNodes : 1; |
238 | unsigned char _adapterRespondsTo_pasteboardFilenamesForNodes : 1; |
239 | unsigned char _adapterRespondsTo_writeItemsToPasteboard : 1; |
240 | unsigned char _adapterRespondsTo_writeItemsToPasteboardXXXX : 1; |
241 | |
242 | unsigned int _filler : 32; |
243 | } _flags; |
244 | |
245 | // CHECK-LP64: Block variable layout: BL_OPERATOR:0 |
246 | unsigned char (^c)() = ^{ |
247 | return _flags._draggedNodesAreDeletable; |
248 | }; |
249 | |
250 | c(); |
251 | } |
252 | |
253 | // Test4 unnamed bitfield |
254 | void bf4() { |
255 | |
256 | struct { |
257 | unsigned short _reserved : 16; |
258 | |
259 | unsigned char _draggedNodesAreDeletable: 1; |
260 | unsigned char _draggedOutsideOutlineView : 1; |
261 | unsigned char _adapterRespondsTo_addRootPaths : 1; |
262 | unsigned char _adapterRespondsTo_moveDataNodes : 1; |
263 | unsigned char _adapterRespondsTo_removeRootDataNode : 1; |
264 | unsigned char _adapterRespondsTo_doubleClickDataNode : 1; |
265 | unsigned char _adapterRespondsTo_selectDataNode : 1; |
266 | unsigned char _adapterRespondsTo_textDidEndEditing : 1; |
267 | |
268 | unsigned long long : 64; |
269 | |
270 | unsigned char _adapterRespondsTo_updateAndSaveRoots : 1; |
271 | unsigned char _adapterRespondsTo_askToDeleteRootNodes : 1; |
272 | unsigned char _adapterRespondsTo_contextMenuForSelectedNodes : 1; |
273 | unsigned char _adapterRespondsTo_pasteboardFilenamesForNodes : 1; |
274 | unsigned char _adapterRespondsTo_writeItemsToPasteboard : 1; |
275 | unsigned char _adapterRespondsTo_writeItemsToPasteboardXXXX : 1; |
276 | |
277 | unsigned int _filler : 32; |
278 | } _flags; |
279 | |
280 | // CHECK-LP64: Block variable layout: BL_OPERATOR:0 |
281 | unsigned char (^c)() = ^{ |
282 | return _flags._draggedNodesAreDeletable; |
283 | }; |
284 | |
285 | c(); |
286 | } |
287 | |
288 | |
289 | |
290 | // Test5 unnamed bitfield. |
291 | void bf5() { |
292 | struct { |
293 | unsigned char flag : 1; |
294 | unsigned int : 32; |
295 | unsigned char flag1 : 1; |
296 | } _flags; |
297 | |
298 | // CHECK-LP64: Block variable layout: BL_OPERATOR:0 |
299 | unsigned char (^c)() = ^{ |
300 | return _flags.flag; |
301 | }; |
302 | |
303 | c(); |
304 | } |
305 | |
306 | |
307 | // Test6 0 length bitfield. |
308 | void bf6() { |
309 | struct { |
310 | unsigned char flag : 1; |
311 | unsigned int : 0; |
312 | unsigned char flag1 : 1; |
313 | } _flags; |
314 | |
315 | // CHECK-LP64: Block variable layout: BL_OPERATOR:0 |
316 | unsigned char (^c)() = ^{ |
317 | return _flags.flag; |
318 | }; |
319 | |
320 | c(); |
321 | } |
322 | |
323 | // Test7 large number of captured variables. |
324 | void Test7() { |
325 | __weak id wid; |
326 | __weak id wid1, wid2, wid3, wid4; |
327 | __weak id wid5, wid6, wid7, wid8; |
328 | __weak id wid9, wid10, wid11, wid12; |
329 | __weak id wid13, wid14, wid15, wid16; |
330 | const id bar = (id) opaque_id(); |
331 | // CHECK-LP64: Block variable layout: BL_STRONG:1, BL_WEAK:16, BL_OPERATOR:0 |
332 | void (^b)() = ^{ |
333 | x(bar); |
334 | x(wid1); |
335 | x(wid2); |
336 | x(wid3); |
337 | x(wid4); |
338 | x(wid5); |
339 | x(wid6); |
340 | x(wid7); |
341 | x(wid8); |
342 | x(wid9); |
343 | x(wid10); |
344 | x(wid11); |
345 | x(wid12); |
346 | x(wid13); |
347 | x(wid14); |
348 | x(wid15); |
349 | x(wid16); |
350 | }; |
351 | } |
352 | |
353 | |
354 | // Test 8 very large number of captured variables. |
355 | void Test8() { |
356 | __weak id wid; |
357 | __weak id wid1, wid2, wid3, wid4; |
358 | __weak id wid5, wid6, wid7, wid8; |
359 | __weak id wid9, wid10, wid11, wid12; |
360 | __weak id wid13, wid14, wid15, wid16; |
361 | __weak id w1, w2, w3, w4; |
362 | __weak id w5, w6, w7, w8; |
363 | __weak id w9, w10, w11, w12; |
364 | __weak id w13, w14, w15, w16; |
365 | const id bar = (id) opaque_id(); |
366 | // CHECK-LP64: Block variable layout: BL_STRONG:1, BL_WEAK:16, BL_WEAK:16, BL_WEAK:1, BL_OPERATOR:0 |
367 | void (^b)() = ^{ |
368 | x(bar); |
369 | x(wid1); |
370 | x(wid2); |
371 | x(wid3); |
372 | x(wid4); |
373 | x(wid5); |
374 | x(wid6); |
375 | x(wid7); |
376 | x(wid8); |
377 | x(wid9); |
378 | x(wid10); |
379 | x(wid11); |
380 | x(wid12); |
381 | x(wid13); |
382 | x(wid14); |
383 | x(wid15); |
384 | x(wid16); |
385 | x(w1); |
386 | x(w2); |
387 | x(w3); |
388 | x(w4); |
389 | x(w5); |
390 | x(w6); |
391 | x(w7); |
392 | x(w8); |
393 | x(w9); |
394 | x(w10); |
395 | x(w11); |
396 | x(w12); |
397 | x(w13); |
398 | x(w14); |
399 | x(w15); |
400 | x(w16); |
401 | x(wid); |
402 | }; |
403 | } |
404 | |