770 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py2; RUN: llc -mtriple=aarch64-none-linux-gnu -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SD3; RUN: llc -mtriple=aarch64-none-linux-gnu -o - -global-isel %s | FileCheck %s --check-prefixes=CHECK,CHECK-GI4 5;; Check that the llvm aarch64 backend can handle arrays of6;; structs and vice versa when passed from IR.7;; (this layering is something clang would normally simplify)8;;9;; Some of these examples are not ABI compliant and they're not10;; meant to be. For instance according to the ABI an aggregate11;; with more than 4 members must go in memory. This restriction12;; is applied earlier in the compilation process so here we do13;; see 8 member types in registers.14;;15;; When we have more than 8 members we simply run out of registers16;; and that's what produces the 8 limit here.17 18;; Plain arrays19 20define [ 0 x double ] @array_0() {21; CHECK-LABEL: array_0:22; CHECK: // %bb.0:23; CHECK-NEXT: ret24 ret [ 0 x double ] zeroinitializer25}26 27define [ 1 x double ] @array_1() {28; CHECK-LABEL: array_1:29; CHECK: // %bb.0:30; CHECK-NEXT: movi d0, #000000000000000031; CHECK-NEXT: ret32 ret [ 1 x double ] zeroinitializer33}34 35define [ 8 x double ] @array_8() {36; CHECK-LABEL: array_8:37; CHECK: // %bb.0:38; CHECK-NEXT: movi d0, #000000000000000039; CHECK-NEXT: movi d1, #000000000000000040; CHECK-NEXT: movi d2, #000000000000000041; CHECK-NEXT: movi d3, #000000000000000042; CHECK-NEXT: movi d4, #000000000000000043; CHECK-NEXT: movi d5, #000000000000000044; CHECK-NEXT: movi d6, #000000000000000045; CHECK-NEXT: movi d7, #000000000000000046; CHECK-NEXT: ret47 ret [ 8 x double ] zeroinitializer48}49 50;; > 8 items goes on the stack51 52define [ 9 x double ] @array_9() {53; CHECK-SD-LABEL: array_9:54; CHECK-SD: // %bb.0:55; CHECK-SD-NEXT: movi v0.2d, #000000000000000056; CHECK-SD-NEXT: str xzr, [x8, #64]57; CHECK-SD-NEXT: stp q0, q0, [x8]58; CHECK-SD-NEXT: stp q0, q0, [x8, #32]59; CHECK-SD-NEXT: ret60;61; CHECK-GI-LABEL: array_9:62; CHECK-GI: // %bb.0:63; CHECK-GI-NEXT: stp xzr, xzr, [x8]64; CHECK-GI-NEXT: stp xzr, xzr, [x8, #16]65; CHECK-GI-NEXT: stp xzr, xzr, [x8, #32]66; CHECK-GI-NEXT: stp xzr, xzr, [x8, #48]67; CHECK-GI-NEXT: str xzr, [x8, #64]68; CHECK-GI-NEXT: ret69 ret [ 9 x double ] zeroinitializer70}71 72;; Won't use any registers, just checking for assumptions.73%T_STRUCT_0M = type { }74 75define %T_STRUCT_0M @struct_zero_fields() {76; CHECK-LABEL: struct_zero_fields:77; CHECK: // %bb.0:78; CHECK-NEXT: ret79 ret %T_STRUCT_0M zeroinitializer80}81 82define [ 1 x %T_STRUCT_0M ] @array_of_struct_zero_fields() {83; CHECK-LABEL: array_of_struct_zero_fields:84; CHECK: // %bb.0:85; CHECK-NEXT: ret86 ret [ 1 x %T_STRUCT_0M ] zeroinitializer87}88 89define [ 2 x %T_STRUCT_0M ] @array_of_struct_zero_fields_in_struct() {90; CHECK-LABEL: array_of_struct_zero_fields_in_struct:91; CHECK: // %bb.0:92; CHECK-NEXT: ret93 ret [ 2 x %T_STRUCT_0M ] zeroinitializer94}95 96%T_STRUCT_1M = type { i32 }97 98define %T_STRUCT_1M @struct_one_field() {99; CHECK-LABEL: struct_one_field:100; CHECK: // %bb.0:101; CHECK-NEXT: mov w0, wzr102; CHECK-NEXT: ret103 ret %T_STRUCT_1M zeroinitializer104}105 106define [ 1 x %T_STRUCT_1M ] @array_of_struct_one_field() {107; CHECK-LABEL: array_of_struct_one_field:108; CHECK: // %bb.0:109; CHECK-NEXT: mov w0, wzr110; CHECK-NEXT: ret111 ret [ 1 x %T_STRUCT_1M ] zeroinitializer112}113 114;; This one will be a reg block115define [ 2 x %T_STRUCT_1M ] @array_of_struct_one_field_2() {116; CHECK-LABEL: array_of_struct_one_field_2:117; CHECK: // %bb.0:118; CHECK-NEXT: mov w0, wzr119; CHECK-NEXT: mov w1, wzr120; CHECK-NEXT: ret121 ret [ 2 x %T_STRUCT_1M ] zeroinitializer122}123 124;; Different types for each field, will not be put in a reg block125%T_STRUCT_DIFFM = type { double, i32 }126 127define %T_STRUCT_DIFFM @struct_different_field_types() {128; CHECK-LABEL: struct_different_field_types:129; CHECK: // %bb.0:130; CHECK-NEXT: movi d0, #0000000000000000131; CHECK-NEXT: mov w0, wzr132; CHECK-NEXT: ret133 ret %T_STRUCT_DIFFM zeroinitializer134}135 136define [ 1 x %T_STRUCT_DIFFM ] @array_of_struct_different_field_types() {137; CHECK-LABEL: array_of_struct_different_field_types:138; CHECK: // %bb.0:139; CHECK-NEXT: movi d0, #0000000000000000140; CHECK-NEXT: mov w0, wzr141; CHECK-NEXT: ret142 ret [ 1 x %T_STRUCT_DIFFM ] zeroinitializer143}144 145define [ 2 x %T_STRUCT_DIFFM ] @array_of_struct_different_field_types_2() {146; CHECK-LABEL: array_of_struct_different_field_types_2:147; CHECK: // %bb.0:148; CHECK-NEXT: movi d0, #0000000000000000149; CHECK-NEXT: movi d1, #0000000000000000150; CHECK-NEXT: mov w0, wzr151; CHECK-NEXT: mov w1, wzr152; CHECK-NEXT: ret153 ret [ 2 x %T_STRUCT_DIFFM ] zeroinitializer154}155 156;; Each field is the same type, can be put in a reg block157%T_STRUCT_SAMEM = type { double, double }158 159;; Here isn't a block as such, we just allocate two consecutive registers160define %T_STRUCT_SAMEM @struct_same_field_types() {161; CHECK-LABEL: struct_same_field_types:162; CHECK: // %bb.0:163; CHECK-NEXT: movi d0, #0000000000000000164; CHECK-NEXT: movi d1, #0000000000000000165; CHECK-NEXT: ret166 ret %T_STRUCT_SAMEM zeroinitializer167}168 169define [ 1 x %T_STRUCT_SAMEM ] @array_of_struct_same_field_types() {170; CHECK-LABEL: array_of_struct_same_field_types:171; CHECK: // %bb.0:172; CHECK-NEXT: movi d0, #0000000000000000173; CHECK-NEXT: movi d1, #0000000000000000174; CHECK-NEXT: ret175 ret [ 1 x %T_STRUCT_SAMEM ] zeroinitializer176}177 178define [ 2 x %T_STRUCT_SAMEM ] @array_of_struct_same_field_types_2() {179; CHECK-LABEL: array_of_struct_same_field_types_2:180; CHECK: // %bb.0:181; CHECK-NEXT: movi d0, #0000000000000000182; CHECK-NEXT: movi d1, #0000000000000000183; CHECK-NEXT: movi d2, #0000000000000000184; CHECK-NEXT: movi d3, #0000000000000000185; CHECK-NEXT: ret186 ret [ 2 x %T_STRUCT_SAMEM ] zeroinitializer187}188 189;; Same field type but integer this time. Put into x registers instead.190%T_STRUCT_SAMEM_INT = type { i64, i64 }191 192define %T_STRUCT_SAMEM_INT @struct_same_field_types_int() {193; CHECK-LABEL: struct_same_field_types_int:194; CHECK: // %bb.0:195; CHECK-NEXT: mov x0, xzr196; CHECK-NEXT: mov x1, xzr197; CHECK-NEXT: ret198 ret %T_STRUCT_SAMEM_INT zeroinitializer199}200 201define [ 1 x %T_STRUCT_SAMEM_INT ] @array_of_struct_same_field_types_int() {202; CHECK-LABEL: array_of_struct_same_field_types_int:203; CHECK: // %bb.0:204; CHECK-NEXT: mov x0, xzr205; CHECK-NEXT: mov x1, xzr206; CHECK-NEXT: ret207 ret [ 1 x %T_STRUCT_SAMEM_INT ] zeroinitializer208}209 210define [ 2 x %T_STRUCT_SAMEM_INT ] @array_of_struct_same_field_types_int_2() {211; CHECK-LABEL: array_of_struct_same_field_types_int_2:212; CHECK: // %bb.0:213; CHECK-NEXT: mov x0, xzr214; CHECK-NEXT: mov x1, xzr215; CHECK-NEXT: mov x2, xzr216; CHECK-NEXT: mov x3, xzr217; CHECK-NEXT: ret218 ret [ 2 x %T_STRUCT_SAMEM_INT ] zeroinitializer219}220 221;; An aggregate of more than 8 items must go in memory.222;; 4x2 struct fields = 8 items so it goes in a block.223 224define [ 4 x %T_STRUCT_SAMEM ] @array_of_struct_8_fields() {225; CHECK-LABEL: array_of_struct_8_fields:226; CHECK: // %bb.0:227; CHECK-NEXT: movi d0, #0000000000000000228; CHECK-NEXT: movi d1, #0000000000000000229; CHECK-NEXT: movi d2, #0000000000000000230; CHECK-NEXT: movi d3, #0000000000000000231; CHECK-NEXT: movi d4, #0000000000000000232; CHECK-NEXT: movi d5, #0000000000000000233; CHECK-NEXT: movi d6, #0000000000000000234; CHECK-NEXT: movi d7, #0000000000000000235; CHECK-NEXT: ret236 ret [ 4 x %T_STRUCT_SAMEM ] zeroinitializer237}238 239;; 5x2 fields = 10 so it is returned in memory.240 241define [ 5 x %T_STRUCT_SAMEM ] @array_of_struct_in_memory() {242; CHECK-SD-LABEL: array_of_struct_in_memory:243; CHECK-SD: // %bb.0:244; CHECK-SD-NEXT: movi v0.2d, #0000000000000000245; CHECK-SD-NEXT: stp q0, q0, [x8, #16]246; CHECK-SD-NEXT: stp q0, q0, [x8, #48]247; CHECK-SD-NEXT: str q0, [x8]248; CHECK-SD-NEXT: ret249;250; CHECK-GI-LABEL: array_of_struct_in_memory:251; CHECK-GI: // %bb.0:252; CHECK-GI-NEXT: stp xzr, xzr, [x8]253; CHECK-GI-NEXT: stp xzr, xzr, [x8, #16]254; CHECK-GI-NEXT: stp xzr, xzr, [x8, #32]255; CHECK-GI-NEXT: stp xzr, xzr, [x8, #48]256; CHECK-GI-NEXT: stp xzr, xzr, [x8, #64]257; CHECK-GI-NEXT: ret258 ret [ 5 x %T_STRUCT_SAMEM ] zeroinitializer259}260 261;; A struct whose field is an array.262%T_STRUCT_ARRAYM = type { [ 2 x double ]};263 264define %T_STRUCT_ARRAYM @struct_array_field() {265; CHECK-LABEL: struct_array_field:266; CHECK: // %bb.0:267; CHECK-NEXT: movi d0, #0000000000000000268; CHECK-NEXT: movi d1, #0000000000000000269; CHECK-NEXT: ret270 ret %T_STRUCT_ARRAYM zeroinitializer271}272 273define [ 1 x %T_STRUCT_ARRAYM ] @array_of_struct_array_field() {274; CHECK-LABEL: array_of_struct_array_field:275; CHECK: // %bb.0:276; CHECK-NEXT: movi d0, #0000000000000000277; CHECK-NEXT: movi d1, #0000000000000000278; CHECK-NEXT: ret279 ret [ 1 x %T_STRUCT_ARRAYM ] zeroinitializer280}281 282define [ 2 x %T_STRUCT_ARRAYM ] @array_of_struct_array_field_2() {283; CHECK-LABEL: array_of_struct_array_field_2:284; CHECK: // %bb.0:285; CHECK-NEXT: movi d0, #0000000000000000286; CHECK-NEXT: movi d1, #0000000000000000287; CHECK-NEXT: movi d2, #0000000000000000288; CHECK-NEXT: movi d3, #0000000000000000289; CHECK-NEXT: ret290 ret [ 2 x %T_STRUCT_ARRAYM ] zeroinitializer291}292 293;; All non-aggregate fields must have the same type, all through the294;; overall aggreagate. This is false here because of the i32.295%T_NESTED_STRUCT_DIFFM = type {296 [ 1 x { { double, double } } ],297 [ 1 x { { double, i32 } } ]298};299 300define %T_NESTED_STRUCT_DIFFM @struct_nested_different_field_types() {301; CHECK-LABEL: struct_nested_different_field_types:302; CHECK: // %bb.0:303; CHECK-NEXT: movi d0, #0000000000000000304; CHECK-NEXT: movi d1, #0000000000000000305; CHECK-NEXT: mov w0, wzr306; CHECK-NEXT: movi d2, #0000000000000000307; CHECK-NEXT: ret308 ret %T_NESTED_STRUCT_DIFFM zeroinitializer309}310 311define [ 1 x %T_NESTED_STRUCT_DIFFM ] @array_of_struct_nested_different_field_types() {312; CHECK-LABEL: array_of_struct_nested_different_field_types:313; CHECK: // %bb.0:314; CHECK-NEXT: movi d0, #0000000000000000315; CHECK-NEXT: movi d1, #0000000000000000316; CHECK-NEXT: mov w0, wzr317; CHECK-NEXT: movi d2, #0000000000000000318; CHECK-NEXT: ret319 ret [ 1 x %T_NESTED_STRUCT_DIFFM ] zeroinitializer320}321 322define [ 2 x %T_NESTED_STRUCT_DIFFM ] @array_of_struct_nested_different_field_types_2() {323; CHECK-LABEL: array_of_struct_nested_different_field_types_2:324; CHECK: // %bb.0:325; CHECK-NEXT: movi d0, #0000000000000000326; CHECK-NEXT: movi d1, #0000000000000000327; CHECK-NEXT: mov w0, wzr328; CHECK-NEXT: movi d2, #0000000000000000329; CHECK-NEXT: movi d3, #0000000000000000330; CHECK-NEXT: mov w1, wzr331; CHECK-NEXT: movi d4, #0000000000000000332; CHECK-NEXT: movi d5, #0000000000000000333; CHECK-NEXT: ret334 ret [ 2 x %T_NESTED_STRUCT_DIFFM ] zeroinitializer335}336 337;; All fields here are the same type, more nesting to stress the recursive walk.338%T_NESTED_STRUCT_SAMEM = type {339 { { double} },340 { [ 2 x { double, double } ] }341};342 343define %T_NESTED_STRUCT_SAMEM @struct_nested_same_field_types() {344; CHECK-LABEL: struct_nested_same_field_types:345; CHECK: // %bb.0:346; CHECK-NEXT: movi d0, #0000000000000000347; CHECK-NEXT: movi d1, #0000000000000000348; CHECK-NEXT: movi d2, #0000000000000000349; CHECK-NEXT: movi d3, #0000000000000000350; CHECK-NEXT: movi d4, #0000000000000000351; CHECK-NEXT: ret352 ret %T_NESTED_STRUCT_SAMEM zeroinitializer353}354 355define [ 1 x %T_NESTED_STRUCT_SAMEM ] @array_of_struct_nested_same_field_types() {356; CHECK-LABEL: array_of_struct_nested_same_field_types:357; CHECK: // %bb.0:358; CHECK-NEXT: movi d0, #0000000000000000359; CHECK-NEXT: movi d1, #0000000000000000360; CHECK-NEXT: movi d2, #0000000000000000361; CHECK-NEXT: movi d3, #0000000000000000362; CHECK-NEXT: movi d4, #0000000000000000363; CHECK-NEXT: ret364 ret [ 1 x %T_NESTED_STRUCT_SAMEM ] zeroinitializer365}366 367;; 2 x (1 + (2 x 2)) = 10 so this is returned in memory368define [ 2 x %T_NESTED_STRUCT_SAMEM ] @array_of_struct_nested_same_field_types_2() {369; CHECK-SD-LABEL: array_of_struct_nested_same_field_types_2:370; CHECK-SD: // %bb.0:371; CHECK-SD-NEXT: movi v0.2d, #0000000000000000372; CHECK-SD-NEXT: stp q0, q0, [x8, #16]373; CHECK-SD-NEXT: stp q0, q0, [x8, #48]374; CHECK-SD-NEXT: str q0, [x8]375; CHECK-SD-NEXT: ret376;377; CHECK-GI-LABEL: array_of_struct_nested_same_field_types_2:378; CHECK-GI: // %bb.0:379; CHECK-GI-NEXT: stp xzr, xzr, [x8]380; CHECK-GI-NEXT: stp xzr, xzr, [x8, #16]381; CHECK-GI-NEXT: stp xzr, xzr, [x8, #32]382; CHECK-GI-NEXT: stp xzr, xzr, [x8, #48]383; CHECK-GI-NEXT: stp xzr, xzr, [x8, #64]384; CHECK-GI-NEXT: ret385 ret [ 2 x %T_NESTED_STRUCT_SAMEM ] zeroinitializer386}387 388;; Check combinations of call, return and argument passing389 390%T_IN_BLOCK = type [ 2 x { double, { double, double } } ]391 392define %T_IN_BLOCK @return_in_block() {393; CHECK-LABEL: return_in_block:394; CHECK: // %bb.0:395; CHECK-NEXT: movi d0, #0000000000000000396; CHECK-NEXT: movi d1, #0000000000000000397; CHECK-NEXT: movi d2, #0000000000000000398; CHECK-NEXT: movi d3, #0000000000000000399; CHECK-NEXT: movi d4, #0000000000000000400; CHECK-NEXT: movi d5, #0000000000000000401; CHECK-NEXT: ret402 ret %T_IN_BLOCK zeroinitializer403}404 405@in_block_store = dso_local global %T_IN_BLOCK zeroinitializer, align 8406 407define void @caller_in_block() {408; CHECK-SD-LABEL: caller_in_block:409; CHECK-SD: // %bb.0:410; CHECK-SD-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill411; CHECK-SD-NEXT: .cfi_def_cfa_offset 16412; CHECK-SD-NEXT: .cfi_offset w30, -16413; CHECK-SD-NEXT: bl return_in_block414; CHECK-SD-NEXT: adrp x8, in_block_store415; CHECK-SD-NEXT: add x8, x8, :lo12:in_block_store416; CHECK-SD-NEXT: stp d0, d1, [x8]417; CHECK-SD-NEXT: stp d2, d3, [x8, #16]418; CHECK-SD-NEXT: stp d4, d5, [x8, #32]419; CHECK-SD-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload420; CHECK-SD-NEXT: ret421;422; CHECK-GI-LABEL: caller_in_block:423; CHECK-GI: // %bb.0:424; CHECK-GI-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill425; CHECK-GI-NEXT: .cfi_def_cfa_offset 16426; CHECK-GI-NEXT: .cfi_offset w30, -16427; CHECK-GI-NEXT: bl return_in_block428; CHECK-GI-NEXT: adrp x8, in_block_store429; CHECK-GI-NEXT: str d0, [x8, :lo12:in_block_store]430; CHECK-GI-NEXT: adrp x8, in_block_store431; CHECK-GI-NEXT: add x8, x8, :lo12:in_block_store432; CHECK-GI-NEXT: stp d1, d2, [x8, #8]433; CHECK-GI-NEXT: stp d3, d4, [x8, #24]434; CHECK-GI-NEXT: str d5, [x8, #40]435; CHECK-GI-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload436; CHECK-GI-NEXT: ret437 %1 = call %T_IN_BLOCK @return_in_block()438 store %T_IN_BLOCK %1, ptr @in_block_store439 ret void440}441 442define void @callee_in_block(%T_IN_BLOCK %a) {443; CHECK-SD-LABEL: callee_in_block:444; CHECK-SD: // %bb.0:445; CHECK-SD-NEXT: adrp x8, in_block_store446; CHECK-SD-NEXT: add x8, x8, :lo12:in_block_store447; CHECK-SD-NEXT: stp d4, d5, [x8, #32]448; CHECK-SD-NEXT: stp d2, d3, [x8, #16]449; CHECK-SD-NEXT: stp d0, d1, [x8]450; CHECK-SD-NEXT: ret451;452; CHECK-GI-LABEL: callee_in_block:453; CHECK-GI: // %bb.0:454; CHECK-GI-NEXT: adrp x8, in_block_store455; CHECK-GI-NEXT: str d0, [x8, :lo12:in_block_store]456; CHECK-GI-NEXT: adrp x8, in_block_store457; CHECK-GI-NEXT: add x8, x8, :lo12:in_block_store458; CHECK-GI-NEXT: stp d1, d2, [x8, #8]459; CHECK-GI-NEXT: stp d3, d4, [x8, #24]460; CHECK-GI-NEXT: str d5, [x8, #40]461; CHECK-GI-NEXT: ret462 store %T_IN_BLOCK %a, ptr @in_block_store463 ret void464}465 466define void @argument_in_block() {467; CHECK-SD-LABEL: argument_in_block:468; CHECK-SD: // %bb.0:469; CHECK-SD-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill470; CHECK-SD-NEXT: .cfi_def_cfa_offset 16471; CHECK-SD-NEXT: .cfi_offset w30, -16472; CHECK-SD-NEXT: adrp x8, in_block_store473; CHECK-SD-NEXT: add x8, x8, :lo12:in_block_store474; CHECK-SD-NEXT: ldp d4, d5, [x8, #32]475; CHECK-SD-NEXT: ldp d2, d3, [x8, #16]476; CHECK-SD-NEXT: ldp d0, d1, [x8]477; CHECK-SD-NEXT: bl callee_in_block478; CHECK-SD-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload479; CHECK-SD-NEXT: ret480;481; CHECK-GI-LABEL: argument_in_block:482; CHECK-GI: // %bb.0:483; CHECK-GI-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill484; CHECK-GI-NEXT: .cfi_def_cfa_offset 16485; CHECK-GI-NEXT: .cfi_offset w30, -16486; CHECK-GI-NEXT: adrp x9, in_block_store487; CHECK-GI-NEXT: add x9, x9, :lo12:in_block_store488; CHECK-GI-NEXT: adrp x8, in_block_store489; CHECK-GI-NEXT: ldp d1, d2, [x9, #8]490; CHECK-GI-NEXT: ldr d0, [x8, :lo12:in_block_store]491; CHECK-GI-NEXT: ldp d3, d4, [x9, #24]492; CHECK-GI-NEXT: ldr d5, [x9, #40]493; CHECK-GI-NEXT: bl callee_in_block494; CHECK-GI-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload495; CHECK-GI-NEXT: ret496 %1 = load %T_IN_BLOCK, ptr @in_block_store497 call void @callee_in_block(%T_IN_BLOCK %1)498 ret void499}500 501%T_IN_MEMORY = type [ 3 x { double, { double, double } } ]502 503define %T_IN_MEMORY @return_in_memory() {504; CHECK-SD-LABEL: return_in_memory:505; CHECK-SD: // %bb.0:506; CHECK-SD-NEXT: movi v0.2d, #0000000000000000507; CHECK-SD-NEXT: str xzr, [x8, #64]508; CHECK-SD-NEXT: stp q0, q0, [x8]509; CHECK-SD-NEXT: stp q0, q0, [x8, #32]510; CHECK-SD-NEXT: ret511;512; CHECK-GI-LABEL: return_in_memory:513; CHECK-GI: // %bb.0:514; CHECK-GI-NEXT: stp xzr, xzr, [x8]515; CHECK-GI-NEXT: stp xzr, xzr, [x8, #16]516; CHECK-GI-NEXT: stp xzr, xzr, [x8, #32]517; CHECK-GI-NEXT: stp xzr, xzr, [x8, #48]518; CHECK-GI-NEXT: str xzr, [x8, #64]519; CHECK-GI-NEXT: ret520 ret %T_IN_MEMORY zeroinitializer521}522 523@in_memory_store = dso_local global %T_IN_MEMORY zeroinitializer, align 8524 525define void @caller_in_memory() {526; CHECK-SD-LABEL: caller_in_memory:527; CHECK-SD: // %bb.0:528; CHECK-SD-NEXT: sub sp, sp, #96529; CHECK-SD-NEXT: str x30, [sp, #80] // 8-byte Spill530; CHECK-SD-NEXT: .cfi_def_cfa_offset 96531; CHECK-SD-NEXT: .cfi_offset w30, -16532; CHECK-SD-NEXT: add x8, sp, #8533; CHECK-SD-NEXT: bl return_in_memory534; CHECK-SD-NEXT: ldur q0, [sp, #24]535; CHECK-SD-NEXT: ldur q1, [sp, #8]536; CHECK-SD-NEXT: adrp x8, in_memory_store537; CHECK-SD-NEXT: add x8, x8, :lo12:in_memory_store538; CHECK-SD-NEXT: ldr d2, [sp, #72]539; CHECK-SD-NEXT: ldur q3, [sp, #56]540; CHECK-SD-NEXT: ldur q4, [sp, #40]541; CHECK-SD-NEXT: ldr x30, [sp, #80] // 8-byte Reload542; CHECK-SD-NEXT: stp q1, q0, [x8]543; CHECK-SD-NEXT: str d2, [x8, #64]544; CHECK-SD-NEXT: stp q4, q3, [x8, #32]545; CHECK-SD-NEXT: add sp, sp, #96546; CHECK-SD-NEXT: ret547;548; CHECK-GI-LABEL: caller_in_memory:549; CHECK-GI: // %bb.0:550; CHECK-GI-NEXT: sub sp, sp, #96551; CHECK-GI-NEXT: str x30, [sp, #80] // 8-byte Spill552; CHECK-GI-NEXT: .cfi_def_cfa_offset 96553; CHECK-GI-NEXT: .cfi_offset w30, -16554; CHECK-GI-NEXT: add x8, sp, #8555; CHECK-GI-NEXT: bl return_in_memory556; CHECK-GI-NEXT: ldp x8, x9, [sp, #8]557; CHECK-GI-NEXT: adrp x10, in_memory_store558; CHECK-GI-NEXT: ldp x11, x12, [sp, #24]559; CHECK-GI-NEXT: ldp x13, x14, [sp, #40]560; CHECK-GI-NEXT: ldp x15, x16, [sp, #56]561; CHECK-GI-NEXT: ldp x17, x30, [sp, #72] // 8-byte Folded Reload562; CHECK-GI-NEXT: str x8, [x10, :lo12:in_memory_store]563; CHECK-GI-NEXT: adrp x8, in_memory_store564; CHECK-GI-NEXT: add x8, x8, :lo12:in_memory_store565; CHECK-GI-NEXT: stp x9, x11, [x8, #8]566; CHECK-GI-NEXT: stp x12, x13, [x8, #24]567; CHECK-GI-NEXT: stp x14, x15, [x8, #40]568; CHECK-GI-NEXT: stp x16, x17, [x8, #56]569; CHECK-GI-NEXT: add sp, sp, #96570; CHECK-GI-NEXT: ret571 %1 = call %T_IN_MEMORY @return_in_memory()572 store %T_IN_MEMORY %1, ptr @in_memory_store573 ret void574}575 576define void @callee_in_memory(%T_IN_MEMORY %a) {577; CHECK-SD-LABEL: callee_in_memory:578; CHECK-SD: // %bb.0:579; CHECK-SD-NEXT: ldp q1, q2, [sp, #32]580; CHECK-SD-NEXT: adrp x8, in_memory_store581; CHECK-SD-NEXT: add x8, x8, :lo12:in_memory_store582; CHECK-SD-NEXT: ldr d0, [sp, #64]583; CHECK-SD-NEXT: str d0, [x8, #64]584; CHECK-SD-NEXT: str q2, [x8, #48]585; CHECK-SD-NEXT: ldp q2, q0, [sp]586; CHECK-SD-NEXT: stp q0, q1, [x8, #16]587; CHECK-SD-NEXT: str q2, [x8]588; CHECK-SD-NEXT: ret589;590; CHECK-GI-LABEL: callee_in_memory:591; CHECK-GI: // %bb.0:592; CHECK-GI-NEXT: ldp x8, x9, [sp]593; CHECK-GI-NEXT: adrp x10, in_memory_store594; CHECK-GI-NEXT: ldp x11, x12, [sp, #16]595; CHECK-GI-NEXT: str x8, [x10, :lo12:in_memory_store]596; CHECK-GI-NEXT: adrp x8, in_memory_store597; CHECK-GI-NEXT: add x8, x8, :lo12:in_memory_store598; CHECK-GI-NEXT: stp x9, x11, [x8, #8]599; CHECK-GI-NEXT: ldp x9, x10, [sp, #32]600; CHECK-GI-NEXT: stp x12, x9, [x8, #24]601; CHECK-GI-NEXT: ldp x9, x11, [sp, #48]602; CHECK-GI-NEXT: str x10, [x8, #40]603; CHECK-GI-NEXT: ldr x10, [sp, #64]604; CHECK-GI-NEXT: stp x9, x11, [x8, #48]605; CHECK-GI-NEXT: str x10, [x8, #64]606; CHECK-GI-NEXT: ret607 store %T_IN_MEMORY %a, ptr @in_memory_store608 ret void609}610 611define void @argument_in_memory() {612; CHECK-SD-LABEL: argument_in_memory:613; CHECK-SD: // %bb.0:614; CHECK-SD-NEXT: sub sp, sp, #96615; CHECK-SD-NEXT: str x30, [sp, #80] // 8-byte Spill616; CHECK-SD-NEXT: .cfi_def_cfa_offset 96617; CHECK-SD-NEXT: .cfi_offset w30, -16618; CHECK-SD-NEXT: adrp x8, in_memory_store619; CHECK-SD-NEXT: add x8, x8, :lo12:in_memory_store620; CHECK-SD-NEXT: ldp q0, q1, [x8]621; CHECK-SD-NEXT: ldr d4, [x8, #64]622; CHECK-SD-NEXT: ldp q2, q3, [x8, #32]623; CHECK-SD-NEXT: str d4, [sp, #64]624; CHECK-SD-NEXT: stp q0, q1, [sp]625; CHECK-SD-NEXT: stp q2, q3, [sp, #32]626; CHECK-SD-NEXT: bl callee_in_memory627; CHECK-SD-NEXT: ldr x30, [sp, #80] // 8-byte Reload628; CHECK-SD-NEXT: add sp, sp, #96629; CHECK-SD-NEXT: ret630;631; CHECK-GI-LABEL: argument_in_memory:632; CHECK-GI: // %bb.0:633; CHECK-GI-NEXT: sub sp, sp, #96634; CHECK-GI-NEXT: str x30, [sp, #80] // 8-byte Spill635; CHECK-GI-NEXT: .cfi_def_cfa_offset 96636; CHECK-GI-NEXT: .cfi_offset w30, -16637; CHECK-GI-NEXT: adrp x9, in_memory_store638; CHECK-GI-NEXT: add x9, x9, :lo12:in_memory_store639; CHECK-GI-NEXT: adrp x8, in_memory_store640; CHECK-GI-NEXT: ldp x10, x11, [x9, #8]641; CHECK-GI-NEXT: ldr x8, [x8, :lo12:in_memory_store]642; CHECK-GI-NEXT: ldp x12, x13, [x9, #24]643; CHECK-GI-NEXT: ldp x14, x15, [x9, #40]644; CHECK-GI-NEXT: ldp x16, x9, [x9, #56]645; CHECK-GI-NEXT: stp x8, x10, [sp]646; CHECK-GI-NEXT: stp x11, x12, [sp, #16]647; CHECK-GI-NEXT: stp x13, x14, [sp, #32]648; CHECK-GI-NEXT: stp x15, x16, [sp, #48]649; CHECK-GI-NEXT: str x9, [sp, #64]650; CHECK-GI-NEXT: bl callee_in_memory651; CHECK-GI-NEXT: ldr x30, [sp, #80] // 8-byte Reload652; CHECK-GI-NEXT: add sp, sp, #96653; CHECK-GI-NEXT: ret654 %1 = load %T_IN_MEMORY, ptr @in_memory_store655 call void @callee_in_memory(%T_IN_MEMORY %1)656 ret void657}658 659%T_NO_BLOCK = type [ 2 x { double, { i32 } } ]660 661define %T_NO_BLOCK @return_no_block() {662; CHECK-LABEL: return_no_block:663; CHECK: // %bb.0:664; CHECK-NEXT: movi d0, #0000000000000000665; CHECK-NEXT: movi d1, #0000000000000000666; CHECK-NEXT: mov w0, wzr667; CHECK-NEXT: mov w1, wzr668; CHECK-NEXT: ret669 ret %T_NO_BLOCK zeroinitializer670}671 672@no_block_store = dso_local global %T_NO_BLOCK zeroinitializer, align 8673 674define void @caller_no_block() {675; CHECK-SD-LABEL: caller_no_block:676; CHECK-SD: // %bb.0:677; CHECK-SD-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill678; CHECK-SD-NEXT: .cfi_def_cfa_offset 16679; CHECK-SD-NEXT: .cfi_offset w30, -16680; CHECK-SD-NEXT: bl return_no_block681; CHECK-SD-NEXT: adrp x8, no_block_store682; CHECK-SD-NEXT: add x8, x8, :lo12:no_block_store683; CHECK-SD-NEXT: str d0, [x8]684; CHECK-SD-NEXT: str w0, [x8, #8]685; CHECK-SD-NEXT: str d1, [x8, #16]686; CHECK-SD-NEXT: str w1, [x8, #24]687; CHECK-SD-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload688; CHECK-SD-NEXT: ret689;690; CHECK-GI-LABEL: caller_no_block:691; CHECK-GI: // %bb.0:692; CHECK-GI-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill693; CHECK-GI-NEXT: .cfi_def_cfa_offset 16694; CHECK-GI-NEXT: .cfi_offset w30, -16695; CHECK-GI-NEXT: bl return_no_block696; CHECK-GI-NEXT: adrp x8, no_block_store697; CHECK-GI-NEXT: str d0, [x8, :lo12:no_block_store]698; CHECK-GI-NEXT: adrp x8, no_block_store699; CHECK-GI-NEXT: add x8, x8, :lo12:no_block_store700; CHECK-GI-NEXT: str w0, [x8, #8]701; CHECK-GI-NEXT: str d1, [x8, #16]702; CHECK-GI-NEXT: str w1, [x8, #24]703; CHECK-GI-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload704; CHECK-GI-NEXT: ret705 %1 = call %T_NO_BLOCK @return_no_block()706 store %T_NO_BLOCK %1, ptr @no_block_store707 ret void708}709 710define void @callee_no_block(%T_NO_BLOCK %a) {711; CHECK-SD-LABEL: callee_no_block:712; CHECK-SD: // %bb.0:713; CHECK-SD-NEXT: adrp x8, no_block_store714; CHECK-SD-NEXT: add x8, x8, :lo12:no_block_store715; CHECK-SD-NEXT: str w1, [x8, #24]716; CHECK-SD-NEXT: str d1, [x8, #16]717; CHECK-SD-NEXT: str w0, [x8, #8]718; CHECK-SD-NEXT: str d0, [x8]719; CHECK-SD-NEXT: ret720;721; CHECK-GI-LABEL: callee_no_block:722; CHECK-GI: // %bb.0:723; CHECK-GI-NEXT: adrp x8, no_block_store724; CHECK-GI-NEXT: str d0, [x8, :lo12:no_block_store]725; CHECK-GI-NEXT: adrp x8, no_block_store726; CHECK-GI-NEXT: add x8, x8, :lo12:no_block_store727; CHECK-GI-NEXT: str w0, [x8, #8]728; CHECK-GI-NEXT: str d1, [x8, #16]729; CHECK-GI-NEXT: str w1, [x8, #24]730; CHECK-GI-NEXT: ret731 store %T_NO_BLOCK %a, ptr @no_block_store732 ret void733}734 735define void @argument_no_block() {736; CHECK-SD-LABEL: argument_no_block:737; CHECK-SD: // %bb.0:738; CHECK-SD-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill739; CHECK-SD-NEXT: .cfi_def_cfa_offset 16740; CHECK-SD-NEXT: .cfi_offset w30, -16741; CHECK-SD-NEXT: adrp x8, no_block_store742; CHECK-SD-NEXT: add x8, x8, :lo12:no_block_store743; CHECK-SD-NEXT: ldr w1, [x8, #24]744; CHECK-SD-NEXT: ldr d1, [x8, #16]745; CHECK-SD-NEXT: ldr w0, [x8, #8]746; CHECK-SD-NEXT: ldr d0, [x8]747; CHECK-SD-NEXT: bl callee_no_block748; CHECK-SD-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload749; CHECK-SD-NEXT: ret750;751; CHECK-GI-LABEL: argument_no_block:752; CHECK-GI: // %bb.0:753; CHECK-GI-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill754; CHECK-GI-NEXT: .cfi_def_cfa_offset 16755; CHECK-GI-NEXT: .cfi_offset w30, -16756; CHECK-GI-NEXT: adrp x8, no_block_store757; CHECK-GI-NEXT: adrp x9, no_block_store758; CHECK-GI-NEXT: add x9, x9, :lo12:no_block_store759; CHECK-GI-NEXT: ldr d0, [x8, :lo12:no_block_store]760; CHECK-GI-NEXT: ldr w0, [x9, #8]761; CHECK-GI-NEXT: ldr d1, [x9, #16]762; CHECK-GI-NEXT: ldr w1, [x9, #24]763; CHECK-GI-NEXT: bl callee_no_block764; CHECK-GI-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload765; CHECK-GI-NEXT: ret766 %1 = load %T_NO_BLOCK, ptr @no_block_store767 call void @callee_no_block(%T_NO_BLOCK %1)768 ret void769}770