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)
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.
19 define [ 0 x double ] @array_0() {
20 ; CHECK-LABEL: array_0:
23 ret [ 0 x double ] zeroinitializer
26 define [ 1 x double ] @array_1() {
27 ; CHECK-LABEL: array_1:
29 ; CHECK-NEXT: movi d0, #0000000000000000
31 ret [ 1 x double ] zeroinitializer
34 define [ 8 x double ] @array_8() {
35 ; CHECK-LABEL: array_8:
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
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:
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]
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:
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:
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:
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:
91 ; CHECK-NEXT: mov w0, wzr
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:
99 ; CHECK-NEXT: mov w0, wzr
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:
108 ; CHECK-NEXT: mov w0, wzr
109 ; CHECK-NEXT: mov w1, wzr
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:
120 ; CHECK-NEXT: movi d0, #0000000000000000
121 ; CHECK-NEXT: mov w0, wzr
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:
129 ; CHECK-NEXT: movi d0, #0000000000000000
130 ; CHECK-NEXT: mov w0, wzr
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:
138 ; CHECK-NEXT: movi d0, #0000000000000000
139 ; CHECK-NEXT: movi d1, #0000000000000000
140 ; CHECK-NEXT: mov w0, wzr
141 ; CHECK-NEXT: mov w1, wzr
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:
153 ; CHECK-NEXT: movi d0, #0000000000000000
154 ; CHECK-NEXT: movi d1, #0000000000000000
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:
162 ; CHECK-NEXT: movi d0, #0000000000000000
163 ; CHECK-NEXT: movi d1, #0000000000000000
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:
171 ; CHECK-NEXT: movi d0, #0000000000000000
172 ; CHECK-NEXT: movi d1, #0000000000000000
173 ; CHECK-NEXT: movi d2, #0000000000000000
174 ; CHECK-NEXT: movi d3, #0000000000000000
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:
185 ; CHECK-NEXT: mov x0, xzr
186 ; CHECK-NEXT: mov x1, xzr
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:
194 ; CHECK-NEXT: mov x0, xzr
195 ; CHECK-NEXT: mov x1, xzr
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:
203 ; CHECK-NEXT: mov x0, xzr
204 ; CHECK-NEXT: mov x1, xzr
205 ; CHECK-NEXT: mov x2, xzr
206 ; CHECK-NEXT: mov x3, xzr
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:
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
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:
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]
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:
248 ; CHECK-NEXT: movi d0, #0000000000000000
249 ; CHECK-NEXT: movi d1, #0000000000000000
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:
257 ; CHECK-NEXT: movi d0, #0000000000000000
258 ; CHECK-NEXT: movi d1, #0000000000000000
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:
266 ; CHECK-NEXT: movi d0, #0000000000000000
267 ; CHECK-NEXT: movi d1, #0000000000000000
268 ; CHECK-NEXT: movi d2, #0000000000000000
269 ; CHECK-NEXT: movi d3, #0000000000000000
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:
284 ; CHECK-NEXT: movi d0, #0000000000000000
285 ; CHECK-NEXT: movi d1, #0000000000000000
286 ; CHECK-NEXT: mov w0, wzr
287 ; CHECK-NEXT: movi d2, #0000000000000000
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:
295 ; CHECK-NEXT: movi d0, #0000000000000000
296 ; CHECK-NEXT: movi d1, #0000000000000000
297 ; CHECK-NEXT: mov w0, wzr
298 ; CHECK-NEXT: movi d2, #0000000000000000
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:
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
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 {
321 { [ 2 x { double, double } ] }
324 define %T_NESTED_STRUCT_SAMEM @struct_nested_same_field_types() {
325 ; CHECK-LABEL: struct_nested_same_field_types:
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
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:
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
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:
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]
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:
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
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:
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
393 %1 = call %T_IN_BLOCK @return_in_block()
394 store %T_IN_BLOCK %1, ptr @in_block_store
398 define void @callee_in_block(%T_IN_BLOCK %a) {
399 ; CHECK-LABEL: callee_in_block:
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]
407 store %T_IN_BLOCK %a, ptr @in_block_store
411 define void @argument_in_block() {
412 ; CHECK-LABEL: argument_in_block:
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
425 %1 = load %T_IN_BLOCK, ptr @in_block_store
426 call void @callee_in_block(%T_IN_BLOCK %1)
430 %T_IN_MEMORY = type [ 3 x { double, { double, double } } ]
432 define %T_IN_MEMORY @return_in_memory() {
433 ; CHECK-LABEL: return_in_memory:
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]
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:
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
467 %1 = call %T_IN_MEMORY @return_in_memory()
468 store %T_IN_MEMORY %1, ptr @in_memory_store
472 define void @callee_in_memory(%T_IN_MEMORY %a) {
473 ; CHECK-LABEL: callee_in_memory:
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]
486 store %T_IN_MEMORY %a, ptr @in_memory_store
490 define void @argument_in_memory() {
491 ; CHECK-LABEL: argument_in_memory:
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
509 %1 = load %T_IN_MEMORY, ptr @in_memory_store
510 call void @callee_in_memory(%T_IN_MEMORY %1)
514 %T_NO_BLOCK = type [ 2 x { double, { i32 } } ]
516 define %T_NO_BLOCK @return_no_block() {
517 ; CHECK-LABEL: return_no_block:
519 ; CHECK-NEXT: movi d0, #0000000000000000
520 ; CHECK-NEXT: movi d1, #0000000000000000
521 ; CHECK-NEXT: mov w0, wzr
522 ; CHECK-NEXT: mov w1, wzr
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:
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
544 %1 = call %T_NO_BLOCK @return_no_block()
545 store %T_NO_BLOCK %1, ptr @no_block_store
549 define void @callee_no_block(%T_NO_BLOCK %a) {
550 ; CHECK-LABEL: callee_no_block:
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]
559 store %T_NO_BLOCK %a, ptr @no_block_store
563 define void @argument_no_block() {
564 ; CHECK-LABEL: argument_no_block:
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
578 %1 = load %T_NO_BLOCK, ptr @no_block_store
579 call void @callee_no_block(%T_NO_BLOCK %1)