[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / llvm / test / CodeGen / AArch64 / argument-blocks-array-of-struct.ll
blobb944194dae8fc9c72acdfaad515ef1667e95faa5
1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2 ; RUN: llc -mtriple=aarch64-none-linux-gnu -o - %s | FileCheck %s
4 ;; Check that the llvm aarch64 backend can handle arrays of
5 ;; structs and vice versa when passed from IR.
6 ;; (this layering is something clang would normally simplify)
7 ;;
8 ;; Some of these examples are not ABI compliant and they're not
9 ;; meant to be. For instance according to the ABI an aggregate
10 ;; with more than 4 members must go in memory. This restriction
11 ;; is applied earlier in the compilation process so here we do
12 ;; see 8 member types in registers.
14 ;; When we have more than 8 members we simply run out of registers
15 ;; and that's what produces the 8 limit here.
17 ;; Plain arrays
19 define [ 0 x double ] @array_0() {
20 ; CHECK-LABEL: array_0:
21 ; CHECK:       // %bb.0:
22 ; CHECK-NEXT:    ret
23   ret [ 0 x double ] zeroinitializer
26 define [ 1 x double ] @array_1() {
27 ; CHECK-LABEL: array_1:
28 ; CHECK:       // %bb.0:
29 ; CHECK-NEXT:    movi d0, #0000000000000000
30 ; CHECK-NEXT:    ret
31   ret [ 1 x double ] zeroinitializer
34 define [ 8 x double ] @array_8() {
35 ; CHECK-LABEL: array_8:
36 ; CHECK:       // %bb.0:
37 ; CHECK-NEXT:    movi d0, #0000000000000000
38 ; CHECK-NEXT:    movi d1, #0000000000000000
39 ; CHECK-NEXT:    movi d2, #0000000000000000
40 ; CHECK-NEXT:    movi d3, #0000000000000000
41 ; CHECK-NEXT:    movi d4, #0000000000000000
42 ; CHECK-NEXT:    movi d5, #0000000000000000
43 ; CHECK-NEXT:    movi d6, #0000000000000000
44 ; CHECK-NEXT:    movi d7, #0000000000000000
45 ; CHECK-NEXT:    ret
46   ret [ 8 x double ] zeroinitializer
49 ;; > 8 items goes on the stack
51 define [ 9 x double ] @array_9() {
52 ; CHECK-LABEL: array_9:
53 ; CHECK:       // %bb.0:
54 ; CHECK-NEXT:    movi v0.2d, #0000000000000000
55 ; CHECK-NEXT:    str xzr, [x8, #64]
56 ; CHECK-NEXT:    stp q0, q0, [x8]
57 ; CHECK-NEXT:    stp q0, q0, [x8, #32]
58 ; CHECK-NEXT:    ret
59   ret [ 9 x double ] zeroinitializer
62 ;; Won't use any registers, just checking for assumptions.
63 %T_STRUCT_0M = type { }
65 define %T_STRUCT_0M @struct_zero_fields() {
66 ; CHECK-LABEL: struct_zero_fields:
67 ; CHECK:       // %bb.0:
68 ; CHECK-NEXT:    ret
69   ret %T_STRUCT_0M zeroinitializer
72 define [ 1 x %T_STRUCT_0M ] @array_of_struct_zero_fields() {
73 ; CHECK-LABEL: array_of_struct_zero_fields:
74 ; CHECK:       // %bb.0:
75 ; CHECK-NEXT:    ret
76   ret [ 1 x %T_STRUCT_0M ] zeroinitializer
79 define [ 2 x %T_STRUCT_0M ] @array_of_struct_zero_fields_in_struct() {
80 ; CHECK-LABEL: array_of_struct_zero_fields_in_struct:
81 ; CHECK:       // %bb.0:
82 ; CHECK-NEXT:    ret
83   ret [ 2 x %T_STRUCT_0M ] zeroinitializer
86 %T_STRUCT_1M = type { i32 }
88 define %T_STRUCT_1M @struct_one_field() {
89 ; CHECK-LABEL: struct_one_field:
90 ; CHECK:       // %bb.0:
91 ; CHECK-NEXT:    mov w0, wzr
92 ; CHECK-NEXT:    ret
93   ret %T_STRUCT_1M zeroinitializer
96 define [ 1 x %T_STRUCT_1M ] @array_of_struct_one_field() {
97 ; CHECK-LABEL: array_of_struct_one_field:
98 ; CHECK:       // %bb.0:
99 ; CHECK-NEXT:    mov w0, wzr
100 ; CHECK-NEXT:    ret
101   ret [ 1 x %T_STRUCT_1M ] zeroinitializer
104 ;; This one will be a reg block
105 define [ 2 x %T_STRUCT_1M ] @array_of_struct_one_field_2() {
106 ; CHECK-LABEL: array_of_struct_one_field_2:
107 ; CHECK:       // %bb.0:
108 ; CHECK-NEXT:    mov w0, wzr
109 ; CHECK-NEXT:    mov w1, wzr
110 ; CHECK-NEXT:    ret
111   ret [ 2 x %T_STRUCT_1M ] zeroinitializer
114 ;; Different types for each field, will not be put in a reg block
115 %T_STRUCT_DIFFM = type { double, i32 }
117 define %T_STRUCT_DIFFM @struct_different_field_types() {
118 ; CHECK-LABEL: struct_different_field_types:
119 ; CHECK:       // %bb.0:
120 ; CHECK-NEXT:    movi d0, #0000000000000000
121 ; CHECK-NEXT:    mov w0, wzr
122 ; CHECK-NEXT:    ret
123   ret %T_STRUCT_DIFFM zeroinitializer
126 define [ 1 x %T_STRUCT_DIFFM ] @array_of_struct_different_field_types() {
127 ; CHECK-LABEL: array_of_struct_different_field_types:
128 ; CHECK:       // %bb.0:
129 ; CHECK-NEXT:    movi d0, #0000000000000000
130 ; CHECK-NEXT:    mov w0, wzr
131 ; CHECK-NEXT:    ret
132   ret [ 1 x %T_STRUCT_DIFFM ] zeroinitializer
135 define [ 2 x %T_STRUCT_DIFFM ] @array_of_struct_different_field_types_2() {
136 ; CHECK-LABEL: array_of_struct_different_field_types_2:
137 ; CHECK:       // %bb.0:
138 ; CHECK-NEXT:    movi d0, #0000000000000000
139 ; CHECK-NEXT:    movi d1, #0000000000000000
140 ; CHECK-NEXT:    mov w0, wzr
141 ; CHECK-NEXT:    mov w1, wzr
142 ; CHECK-NEXT:    ret
143   ret [ 2 x %T_STRUCT_DIFFM ] zeroinitializer
146 ;; Each field is the same type, can be put in a reg block
147 %T_STRUCT_SAMEM = type { double, double }
149 ;; Here isn't a block as such, we just allocate two consecutive registers
150 define %T_STRUCT_SAMEM @struct_same_field_types() {
151 ; CHECK-LABEL: struct_same_field_types:
152 ; CHECK:       // %bb.0:
153 ; CHECK-NEXT:    movi d0, #0000000000000000
154 ; CHECK-NEXT:    movi d1, #0000000000000000
155 ; CHECK-NEXT:    ret
156   ret %T_STRUCT_SAMEM zeroinitializer
159 define [ 1 x %T_STRUCT_SAMEM ] @array_of_struct_same_field_types() {
160 ; CHECK-LABEL: array_of_struct_same_field_types:
161 ; CHECK:       // %bb.0:
162 ; CHECK-NEXT:    movi d0, #0000000000000000
163 ; CHECK-NEXT:    movi d1, #0000000000000000
164 ; CHECK-NEXT:    ret
165   ret [ 1 x %T_STRUCT_SAMEM ] zeroinitializer
168 define [ 2 x %T_STRUCT_SAMEM ] @array_of_struct_same_field_types_2() {
169 ; CHECK-LABEL: array_of_struct_same_field_types_2:
170 ; CHECK:       // %bb.0:
171 ; CHECK-NEXT:    movi d0, #0000000000000000
172 ; CHECK-NEXT:    movi d1, #0000000000000000
173 ; CHECK-NEXT:    movi d2, #0000000000000000
174 ; CHECK-NEXT:    movi d3, #0000000000000000
175 ; CHECK-NEXT:    ret
176   ret [ 2 x %T_STRUCT_SAMEM ] zeroinitializer
179 ;; Same field type but integer this time. Put into x registers instead.
180 %T_STRUCT_SAMEM_INT = type { i64, i64 }
182 define %T_STRUCT_SAMEM_INT @struct_same_field_types_int() {
183 ; CHECK-LABEL: struct_same_field_types_int:
184 ; CHECK:       // %bb.0:
185 ; CHECK-NEXT:    mov x0, xzr
186 ; CHECK-NEXT:    mov x1, xzr
187 ; CHECK-NEXT:    ret
188   ret %T_STRUCT_SAMEM_INT zeroinitializer
191 define [ 1 x %T_STRUCT_SAMEM_INT ] @array_of_struct_same_field_types_int() {
192 ; CHECK-LABEL: array_of_struct_same_field_types_int:
193 ; CHECK:       // %bb.0:
194 ; CHECK-NEXT:    mov x0, xzr
195 ; CHECK-NEXT:    mov x1, xzr
196 ; CHECK-NEXT:    ret
197   ret [ 1 x %T_STRUCT_SAMEM_INT ] zeroinitializer
200 define [ 2 x %T_STRUCT_SAMEM_INT ] @array_of_struct_same_field_types_int_2() {
201 ; CHECK-LABEL: array_of_struct_same_field_types_int_2:
202 ; CHECK:       // %bb.0:
203 ; CHECK-NEXT:    mov x0, xzr
204 ; CHECK-NEXT:    mov x1, xzr
205 ; CHECK-NEXT:    mov x2, xzr
206 ; CHECK-NEXT:    mov x3, xzr
207 ; CHECK-NEXT:    ret
208   ret [ 2 x %T_STRUCT_SAMEM_INT ] zeroinitializer
211 ;; An aggregate of more than 8 items must go in memory.
212 ;; 4x2 struct fields = 8 items so it goes in a block.
214 define [ 4 x %T_STRUCT_SAMEM ] @array_of_struct_8_fields() {
215 ; CHECK-LABEL: array_of_struct_8_fields:
216 ; CHECK:       // %bb.0:
217 ; CHECK-NEXT:    movi d0, #0000000000000000
218 ; CHECK-NEXT:    movi d1, #0000000000000000
219 ; CHECK-NEXT:    movi d2, #0000000000000000
220 ; CHECK-NEXT:    movi d3, #0000000000000000
221 ; CHECK-NEXT:    movi d4, #0000000000000000
222 ; CHECK-NEXT:    movi d5, #0000000000000000
223 ; CHECK-NEXT:    movi d6, #0000000000000000
224 ; CHECK-NEXT:    movi d7, #0000000000000000
225 ; CHECK-NEXT:    ret
226   ret [ 4 x %T_STRUCT_SAMEM ] zeroinitializer
229 ;; 5x2 fields = 10 so it is returned in memory.
231 define [ 5 x %T_STRUCT_SAMEM ] @array_of_struct_in_memory() {
232 ; CHECK-LABEL: array_of_struct_in_memory:
233 ; CHECK:       // %bb.0:
234 ; CHECK-NEXT:    movi v0.2d, #0000000000000000
235 ; CHECK-NEXT:    stp q0, q0, [x8, #16]
236 ; CHECK-NEXT:    stp q0, q0, [x8, #48]
237 ; CHECK-NEXT:    str q0, [x8]
238 ; CHECK-NEXT:    ret
239   ret [ 5 x %T_STRUCT_SAMEM ] zeroinitializer
242 ;; A struct whose field is an array.
243 %T_STRUCT_ARRAYM = type { [ 2 x double ]};
245 define %T_STRUCT_ARRAYM @struct_array_field() {
246 ; CHECK-LABEL: struct_array_field:
247 ; CHECK:       // %bb.0:
248 ; CHECK-NEXT:    movi d0, #0000000000000000
249 ; CHECK-NEXT:    movi d1, #0000000000000000
250 ; CHECK-NEXT:    ret
251   ret %T_STRUCT_ARRAYM zeroinitializer
254 define [ 1 x %T_STRUCT_ARRAYM ] @array_of_struct_array_field() {
255 ; CHECK-LABEL: array_of_struct_array_field:
256 ; CHECK:       // %bb.0:
257 ; CHECK-NEXT:    movi d0, #0000000000000000
258 ; CHECK-NEXT:    movi d1, #0000000000000000
259 ; CHECK-NEXT:    ret
260   ret [ 1 x %T_STRUCT_ARRAYM ] zeroinitializer
263 define [ 2 x %T_STRUCT_ARRAYM ] @array_of_struct_array_field_2() {
264 ; CHECK-LABEL: array_of_struct_array_field_2:
265 ; CHECK:       // %bb.0:
266 ; CHECK-NEXT:    movi d0, #0000000000000000
267 ; CHECK-NEXT:    movi d1, #0000000000000000
268 ; CHECK-NEXT:    movi d2, #0000000000000000
269 ; CHECK-NEXT:    movi d3, #0000000000000000
270 ; CHECK-NEXT:    ret
271   ret [ 2 x %T_STRUCT_ARRAYM ] zeroinitializer
274 ;; All non-aggregate fields must have the same type, all through the
275 ;; overall aggreagate. This is false here because of the i32.
276 %T_NESTED_STRUCT_DIFFM = type {
277   [ 1 x { { double, double } } ],
278   [ 1 x { { double, i32 } } ]
281 define %T_NESTED_STRUCT_DIFFM @struct_nested_different_field_types() {
282 ; CHECK-LABEL: struct_nested_different_field_types:
283 ; CHECK:       // %bb.0:
284 ; CHECK-NEXT:    movi d0, #0000000000000000
285 ; CHECK-NEXT:    movi d1, #0000000000000000
286 ; CHECK-NEXT:    mov w0, wzr
287 ; CHECK-NEXT:    movi d2, #0000000000000000
288 ; CHECK-NEXT:    ret
289   ret %T_NESTED_STRUCT_DIFFM zeroinitializer
292 define [ 1 x %T_NESTED_STRUCT_DIFFM ] @array_of_struct_nested_different_field_types() {
293 ; CHECK-LABEL: array_of_struct_nested_different_field_types:
294 ; CHECK:       // %bb.0:
295 ; CHECK-NEXT:    movi d0, #0000000000000000
296 ; CHECK-NEXT:    movi d1, #0000000000000000
297 ; CHECK-NEXT:    mov w0, wzr
298 ; CHECK-NEXT:    movi d2, #0000000000000000
299 ; CHECK-NEXT:    ret
300   ret [ 1 x %T_NESTED_STRUCT_DIFFM ] zeroinitializer
303 define [ 2 x %T_NESTED_STRUCT_DIFFM ] @array_of_struct_nested_different_field_types_2() {
304 ; CHECK-LABEL: array_of_struct_nested_different_field_types_2:
305 ; CHECK:       // %bb.0:
306 ; CHECK-NEXT:    movi d0, #0000000000000000
307 ; CHECK-NEXT:    movi d1, #0000000000000000
308 ; CHECK-NEXT:    mov w0, wzr
309 ; CHECK-NEXT:    movi d2, #0000000000000000
310 ; CHECK-NEXT:    movi d3, #0000000000000000
311 ; CHECK-NEXT:    mov w1, wzr
312 ; CHECK-NEXT:    movi d4, #0000000000000000
313 ; CHECK-NEXT:    movi d5, #0000000000000000
314 ; CHECK-NEXT:    ret
315   ret [ 2 x %T_NESTED_STRUCT_DIFFM ] zeroinitializer
318 ;; All fields here are the same type, more nesting to stress the recursive walk.
319 %T_NESTED_STRUCT_SAMEM = type {
320   { { double} },
321   { [ 2 x { double, double } ] }
324 define %T_NESTED_STRUCT_SAMEM @struct_nested_same_field_types() {
325 ; CHECK-LABEL: struct_nested_same_field_types:
326 ; CHECK:       // %bb.0:
327 ; CHECK-NEXT:    movi d0, #0000000000000000
328 ; CHECK-NEXT:    movi d1, #0000000000000000
329 ; CHECK-NEXT:    movi d2, #0000000000000000
330 ; CHECK-NEXT:    movi d3, #0000000000000000
331 ; CHECK-NEXT:    movi d4, #0000000000000000
332 ; CHECK-NEXT:    ret
333   ret %T_NESTED_STRUCT_SAMEM zeroinitializer
336 define [ 1 x %T_NESTED_STRUCT_SAMEM ] @array_of_struct_nested_same_field_types() {
337 ; CHECK-LABEL: array_of_struct_nested_same_field_types:
338 ; CHECK:       // %bb.0:
339 ; CHECK-NEXT:    movi d0, #0000000000000000
340 ; CHECK-NEXT:    movi d1, #0000000000000000
341 ; CHECK-NEXT:    movi d2, #0000000000000000
342 ; CHECK-NEXT:    movi d3, #0000000000000000
343 ; CHECK-NEXT:    movi d4, #0000000000000000
344 ; CHECK-NEXT:    ret
345   ret [ 1 x %T_NESTED_STRUCT_SAMEM ] zeroinitializer
348 ;; 2 x (1 + (2 x 2)) = 10 so this is returned in memory
349 define [ 2 x %T_NESTED_STRUCT_SAMEM ] @array_of_struct_nested_same_field_types_2() {
350 ; CHECK-LABEL: array_of_struct_nested_same_field_types_2:
351 ; CHECK:       // %bb.0:
352 ; CHECK-NEXT:    movi v0.2d, #0000000000000000
353 ; CHECK-NEXT:    stp q0, q0, [x8, #16]
354 ; CHECK-NEXT:    stp q0, q0, [x8, #48]
355 ; CHECK-NEXT:    str q0, [x8]
356 ; CHECK-NEXT:    ret
357   ret [ 2 x %T_NESTED_STRUCT_SAMEM ] zeroinitializer
360 ;; Check combinations of call, return and argument passing
362 %T_IN_BLOCK = type [ 2 x { double, { double, double } } ]
364 define %T_IN_BLOCK @return_in_block() {
365 ; CHECK-LABEL: return_in_block:
366 ; CHECK:       // %bb.0:
367 ; CHECK-NEXT:    movi d0, #0000000000000000
368 ; CHECK-NEXT:    movi d1, #0000000000000000
369 ; CHECK-NEXT:    movi d2, #0000000000000000
370 ; CHECK-NEXT:    movi d3, #0000000000000000
371 ; CHECK-NEXT:    movi d4, #0000000000000000
372 ; CHECK-NEXT:    movi d5, #0000000000000000
373 ; CHECK-NEXT:    ret
374   ret %T_IN_BLOCK zeroinitializer
377 @in_block_store = dso_local global %T_IN_BLOCK zeroinitializer, align 8
379 define void @caller_in_block() {
380 ; CHECK-LABEL: caller_in_block:
381 ; CHECK:       // %bb.0:
382 ; CHECK-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
383 ; CHECK-NEXT:    .cfi_def_cfa_offset 16
384 ; CHECK-NEXT:    .cfi_offset w30, -16
385 ; CHECK-NEXT:    bl return_in_block
386 ; CHECK-NEXT:    adrp x8, in_block_store
387 ; CHECK-NEXT:    add x8, x8, :lo12:in_block_store
388 ; CHECK-NEXT:    stp d0, d1, [x8]
389 ; CHECK-NEXT:    stp d2, d3, [x8, #16]
390 ; CHECK-NEXT:    stp d4, d5, [x8, #32]
391 ; CHECK-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
392 ; CHECK-NEXT:    ret
393   %1 = call %T_IN_BLOCK @return_in_block()
394   store %T_IN_BLOCK %1, ptr @in_block_store
395   ret void
398 define void @callee_in_block(%T_IN_BLOCK %a) {
399 ; CHECK-LABEL: callee_in_block:
400 ; CHECK:       // %bb.0:
401 ; CHECK-NEXT:    adrp x8, in_block_store
402 ; CHECK-NEXT:    add x8, x8, :lo12:in_block_store
403 ; CHECK-NEXT:    stp d4, d5, [x8, #32]
404 ; CHECK-NEXT:    stp d2, d3, [x8, #16]
405 ; CHECK-NEXT:    stp d0, d1, [x8]
406 ; CHECK-NEXT:    ret
407   store %T_IN_BLOCK %a, ptr @in_block_store
408   ret void
411 define void @argument_in_block() {
412 ; CHECK-LABEL: argument_in_block:
413 ; CHECK:       // %bb.0:
414 ; CHECK-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
415 ; CHECK-NEXT:    .cfi_def_cfa_offset 16
416 ; CHECK-NEXT:    .cfi_offset w30, -16
417 ; CHECK-NEXT:    adrp x8, in_block_store
418 ; CHECK-NEXT:    add x8, x8, :lo12:in_block_store
419 ; CHECK-NEXT:    ldp d4, d5, [x8, #32]
420 ; CHECK-NEXT:    ldp d2, d3, [x8, #16]
421 ; CHECK-NEXT:    ldp d0, d1, [x8]
422 ; CHECK-NEXT:    bl callee_in_block
423 ; CHECK-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
424 ; CHECK-NEXT:    ret
425   %1 = load %T_IN_BLOCK, ptr @in_block_store
426   call void @callee_in_block(%T_IN_BLOCK %1)
427   ret void
430 %T_IN_MEMORY = type [ 3 x { double, { double, double } } ]
432 define %T_IN_MEMORY @return_in_memory() {
433 ; CHECK-LABEL: return_in_memory:
434 ; CHECK:       // %bb.0:
435 ; CHECK-NEXT:    movi v0.2d, #0000000000000000
436 ; CHECK-NEXT:    str xzr, [x8, #64]
437 ; CHECK-NEXT:    stp q0, q0, [x8]
438 ; CHECK-NEXT:    stp q0, q0, [x8, #32]
439 ; CHECK-NEXT:    ret
440   ret %T_IN_MEMORY zeroinitializer
443 @in_memory_store = dso_local global %T_IN_MEMORY zeroinitializer, align 8
445 define void @caller_in_memory() {
446 ; CHECK-LABEL: caller_in_memory:
447 ; CHECK:       // %bb.0:
448 ; CHECK-NEXT:    sub sp, sp, #96
449 ; CHECK-NEXT:    str x30, [sp, #80] // 8-byte Folded Spill
450 ; CHECK-NEXT:    .cfi_def_cfa_offset 96
451 ; CHECK-NEXT:    .cfi_offset w30, -16
452 ; CHECK-NEXT:    add x8, sp, #8
453 ; CHECK-NEXT:    bl return_in_memory
454 ; CHECK-NEXT:    ldur q0, [sp, #24]
455 ; CHECK-NEXT:    ldur q1, [sp, #8]
456 ; CHECK-NEXT:    adrp x8, in_memory_store
457 ; CHECK-NEXT:    add x8, x8, :lo12:in_memory_store
458 ; CHECK-NEXT:    ldr d2, [sp, #72]
459 ; CHECK-NEXT:    ldur q3, [sp, #56]
460 ; CHECK-NEXT:    ldur q4, [sp, #40]
461 ; CHECK-NEXT:    ldr x30, [sp, #80] // 8-byte Folded Reload
462 ; CHECK-NEXT:    stp q1, q0, [x8]
463 ; CHECK-NEXT:    str d2, [x8, #64]
464 ; CHECK-NEXT:    stp q4, q3, [x8, #32]
465 ; CHECK-NEXT:    add sp, sp, #96
466 ; CHECK-NEXT:    ret
467   %1 = call %T_IN_MEMORY @return_in_memory()
468   store %T_IN_MEMORY %1, ptr @in_memory_store
469   ret void
472 define void @callee_in_memory(%T_IN_MEMORY %a) {
473 ; CHECK-LABEL: callee_in_memory:
474 ; CHECK:       // %bb.0:
475 ; CHECK-NEXT:    ldp q1, q2, [sp, #32]
476 ; CHECK-NEXT:    adrp x8, in_memory_store
477 ; CHECK-NEXT:    add x8, x8, :lo12:in_memory_store
478 ; CHECK-NEXT:    ldr d0, [sp, #64]
479 ; CHECK-NEXT:    str d0, [x8, #64]
480 ; CHECK-NEXT:    ldr q0, [sp, #16]
481 ; CHECK-NEXT:    str q2, [x8, #48]
482 ; CHECK-NEXT:    ldr q2, [sp]
483 ; CHECK-NEXT:    stp q0, q1, [x8, #16]
484 ; CHECK-NEXT:    str q2, [x8]
485 ; CHECK-NEXT:    ret
486   store %T_IN_MEMORY %a, ptr @in_memory_store
487   ret void
490 define void @argument_in_memory() {
491 ; CHECK-LABEL: argument_in_memory:
492 ; CHECK:       // %bb.0:
493 ; CHECK-NEXT:    sub sp, sp, #96
494 ; CHECK-NEXT:    str x30, [sp, #80] // 8-byte Folded Spill
495 ; CHECK-NEXT:    .cfi_def_cfa_offset 96
496 ; CHECK-NEXT:    .cfi_offset w30, -16
497 ; CHECK-NEXT:    adrp x8, in_memory_store
498 ; CHECK-NEXT:    add x8, x8, :lo12:in_memory_store
499 ; CHECK-NEXT:    ldp q0, q1, [x8]
500 ; CHECK-NEXT:    ldr d4, [x8, #64]
501 ; CHECK-NEXT:    ldp q2, q3, [x8, #32]
502 ; CHECK-NEXT:    str d4, [sp, #64]
503 ; CHECK-NEXT:    stp q0, q1, [sp]
504 ; CHECK-NEXT:    stp q2, q3, [sp, #32]
505 ; CHECK-NEXT:    bl callee_in_memory
506 ; CHECK-NEXT:    ldr x30, [sp, #80] // 8-byte Folded Reload
507 ; CHECK-NEXT:    add sp, sp, #96
508 ; CHECK-NEXT:    ret
509   %1 = load %T_IN_MEMORY, ptr @in_memory_store
510   call void @callee_in_memory(%T_IN_MEMORY %1)
511   ret void
514 %T_NO_BLOCK = type [ 2 x { double, { i32 } } ]
516 define %T_NO_BLOCK @return_no_block() {
517 ; CHECK-LABEL: return_no_block:
518 ; CHECK:       // %bb.0:
519 ; CHECK-NEXT:    movi d0, #0000000000000000
520 ; CHECK-NEXT:    movi d1, #0000000000000000
521 ; CHECK-NEXT:    mov w0, wzr
522 ; CHECK-NEXT:    mov w1, wzr
523 ; CHECK-NEXT:    ret
524   ret %T_NO_BLOCK zeroinitializer
527 @no_block_store = dso_local global %T_NO_BLOCK zeroinitializer, align 8
529 define void @caller_no_block() {
530 ; CHECK-LABEL: caller_no_block:
531 ; CHECK:       // %bb.0:
532 ; CHECK-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
533 ; CHECK-NEXT:    .cfi_def_cfa_offset 16
534 ; CHECK-NEXT:    .cfi_offset w30, -16
535 ; CHECK-NEXT:    bl return_no_block
536 ; CHECK-NEXT:    adrp x8, no_block_store
537 ; CHECK-NEXT:    add x8, x8, :lo12:no_block_store
538 ; CHECK-NEXT:    str d0, [x8]
539 ; CHECK-NEXT:    str w0, [x8, #8]
540 ; CHECK-NEXT:    str d1, [x8, #16]
541 ; CHECK-NEXT:    str w1, [x8, #24]
542 ; CHECK-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
543 ; CHECK-NEXT:    ret
544   %1 = call %T_NO_BLOCK @return_no_block()
545   store %T_NO_BLOCK %1, ptr @no_block_store
546   ret void
549 define void @callee_no_block(%T_NO_BLOCK %a) {
550 ; CHECK-LABEL: callee_no_block:
551 ; CHECK:       // %bb.0:
552 ; CHECK-NEXT:    adrp x8, no_block_store
553 ; CHECK-NEXT:    add x8, x8, :lo12:no_block_store
554 ; CHECK-NEXT:    str w1, [x8, #24]
555 ; CHECK-NEXT:    str d1, [x8, #16]
556 ; CHECK-NEXT:    str w0, [x8, #8]
557 ; CHECK-NEXT:    str d0, [x8]
558 ; CHECK-NEXT:    ret
559   store %T_NO_BLOCK %a, ptr @no_block_store
560   ret void
563 define void @argument_no_block() {
564 ; CHECK-LABEL: argument_no_block:
565 ; CHECK:       // %bb.0:
566 ; CHECK-NEXT:    str x30, [sp, #-16]! // 8-byte Folded Spill
567 ; CHECK-NEXT:    .cfi_def_cfa_offset 16
568 ; CHECK-NEXT:    .cfi_offset w30, -16
569 ; CHECK-NEXT:    adrp x8, no_block_store
570 ; CHECK-NEXT:    add x8, x8, :lo12:no_block_store
571 ; CHECK-NEXT:    ldr w1, [x8, #24]
572 ; CHECK-NEXT:    ldr d1, [x8, #16]
573 ; CHECK-NEXT:    ldr w0, [x8, #8]
574 ; CHECK-NEXT:    ldr d0, [x8]
575 ; CHECK-NEXT:    bl callee_no_block
576 ; CHECK-NEXT:    ldr x30, [sp], #16 // 8-byte Folded Reload
577 ; CHECK-NEXT:    ret
578   %1 = load %T_NO_BLOCK, ptr @no_block_store
579   call void @callee_no_block(%T_NO_BLOCK %1)
580   ret void