365 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py2; RUN: llc -mtriple=thumbv8.1m.main-none-none-eabi -mattr=+mve -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-LE3; RUN: llc -mtriple=thumbebv8.1m.main-none-none-eabi -mattr=+mve -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-BE4 5define void @load_load_add_store(ptr %src1, ptr %src2) {6; CHECK-LABEL: load_load_add_store:7; CHECK: @ %bb.0: @ %entry8; CHECK-NEXT: vldrw.u32 q0, [r1]9; CHECK-NEXT: vldrw.u32 q1, [r0]10; CHECK-NEXT: vadd.i32 q0, q1, q011; CHECK-NEXT: vstrw.32 q0, [r0]12; CHECK-NEXT: bx lr13entry:14 %l1 = load <4 x i32>, ptr %src1, align 415 %l2 = load <4 x i32>, ptr %src2, align 416 %a = add <4 x i32> %l1, %l217 store <4 x i32> %a, ptr %src1, align 418 ret void19}20 21define void @load_load_add_store_align1(ptr %src1, ptr %src2) {22; CHECK-LE-LABEL: load_load_add_store_align1:23; CHECK-LE: @ %bb.0: @ %entry24; CHECK-LE-NEXT: vldrb.u8 q0, [r1]25; CHECK-LE-NEXT: vldrb.u8 q1, [r0]26; CHECK-LE-NEXT: vadd.i32 q0, q1, q027; CHECK-LE-NEXT: vstrb.8 q0, [r0]28; CHECK-LE-NEXT: bx lr29;30; CHECK-BE-LABEL: load_load_add_store_align1:31; CHECK-BE: @ %bb.0: @ %entry32; CHECK-BE-NEXT: vldrb.u8 q0, [r1]33; CHECK-BE-NEXT: vldrb.u8 q1, [r0]34; CHECK-BE-NEXT: vrev32.8 q0, q035; CHECK-BE-NEXT: vrev32.8 q1, q136; CHECK-BE-NEXT: vadd.i32 q0, q1, q037; CHECK-BE-NEXT: vrev32.8 q0, q038; CHECK-BE-NEXT: vstrb.8 q0, [r0]39; CHECK-BE-NEXT: bx lr40entry:41 %l1 = load <4 x i32>, ptr %src1, align 142 %l2 = load <4 x i32>, ptr %src2, align 143 %a = add <4 x i32> %l1, %l244 store <4 x i32> %a, ptr %src1, align 145 ret void46}47 48define arm_aapcs_vfpcc void @load_arg_add_store(ptr %src1, <4 x i32> %src2) {49; CHECK-LE-LABEL: load_arg_add_store:50; CHECK-LE: @ %bb.0: @ %entry51; CHECK-LE-NEXT: vldrw.u32 q1, [r0]52; CHECK-LE-NEXT: vadd.i32 q0, q1, q053; CHECK-LE-NEXT: vstrw.32 q0, [r0]54; CHECK-LE-NEXT: bx lr55;56; CHECK-BE-LABEL: load_arg_add_store:57; CHECK-BE: @ %bb.0: @ %entry58; CHECK-BE-NEXT: vrev64.32 q1, q059; CHECK-BE-NEXT: vldrw.u32 q0, [r0]60; CHECK-BE-NEXT: vadd.i32 q0, q0, q161; CHECK-BE-NEXT: vstrw.32 q0, [r0]62; CHECK-BE-NEXT: bx lr63entry:64 %l1 = load <4 x i32>, ptr %src1, align 465 %a = add <4 x i32> %l1, %src266 store <4 x i32> %a, ptr %src1, align 467 ret void68}69 70define <4 x i32> @add_soft(<4 x i32> %src1, <4 x i32> %src2) {71; CHECK-LE-LABEL: add_soft:72; CHECK-LE: @ %bb.0: @ %entry73; CHECK-LE-NEXT: vmov d0, r0, r174; CHECK-LE-NEXT: mov r0, sp75; CHECK-LE-NEXT: vldrw.u32 q1, [r0]76; CHECK-LE-NEXT: vmov d1, r2, r377; CHECK-LE-NEXT: vadd.i32 q0, q0, q178; CHECK-LE-NEXT: vmov r0, r1, d079; CHECK-LE-NEXT: vmov r2, r3, d180; CHECK-LE-NEXT: bx lr81;82; CHECK-BE-LABEL: add_soft:83; CHECK-BE: @ %bb.0: @ %entry84; CHECK-BE-NEXT: vmov d0, r1, r085; CHECK-BE-NEXT: mov r0, sp86; CHECK-BE-NEXT: vmov d1, r3, r287; CHECK-BE-NEXT: vrev64.32 q1, q088; CHECK-BE-NEXT: vldrw.u32 q0, [r0]89; CHECK-BE-NEXT: vadd.i32 q0, q1, q090; CHECK-BE-NEXT: vrev64.32 q1, q091; CHECK-BE-NEXT: vmov r1, r0, d292; CHECK-BE-NEXT: vmov r3, r2, d393; CHECK-BE-NEXT: bx lr94entry:95 %0 = add <4 x i32> %src1, %src296 ret <4 x i32> %097}98 99define arm_aapcs_vfpcc <4 x i32> @add_hard(<4 x i32> %src1, <4 x i32> %src2) {100; CHECK-LE-LABEL: add_hard:101; CHECK-LE: @ %bb.0: @ %entry102; CHECK-LE-NEXT: vadd.i32 q0, q0, q1103; CHECK-LE-NEXT: bx lr104;105; CHECK-BE-LABEL: add_hard:106; CHECK-BE: @ %bb.0: @ %entry107; CHECK-BE-NEXT: vrev64.32 q2, q1108; CHECK-BE-NEXT: vrev64.32 q1, q0109; CHECK-BE-NEXT: vadd.i32 q1, q1, q2110; CHECK-BE-NEXT: vrev64.32 q0, q1111; CHECK-BE-NEXT: bx lr112entry:113 %0 = add <4 x i32> %src1, %src2114 ret <4 x i32> %0115}116 117define <4 x i32> @call_soft(<4 x i32> %src1, <4 x i32> %src2) {118; CHECK-LE-LABEL: call_soft:119; CHECK-LE: @ %bb.0: @ %entry120; CHECK-LE-NEXT: .save {r7, lr}121; CHECK-LE-NEXT: push {r7, lr}122; CHECK-LE-NEXT: .pad #16123; CHECK-LE-NEXT: sub sp, #16124; CHECK-LE-NEXT: add.w r12, sp, #24125; CHECK-LE-NEXT: vldrw.u32 q0, [r12]126; CHECK-LE-NEXT: vstrw.32 q0, [sp]127; CHECK-LE-NEXT: vmov d1, r2, r3128; CHECK-LE-NEXT: vmov d0, r0, r1129; CHECK-LE-NEXT: vshr.u32 q0, q0, #1130; CHECK-LE-NEXT: vmov r0, r1, d0131; CHECK-LE-NEXT: vmov r2, r3, d1132; CHECK-LE-NEXT: bl add_soft133; CHECK-LE-NEXT: vmov d1, r2, r3134; CHECK-LE-NEXT: vmov d0, r0, r1135; CHECK-LE-NEXT: vshr.u32 q0, q0, #1136; CHECK-LE-NEXT: vmov r0, r1, d0137; CHECK-LE-NEXT: vmov r2, r3, d1138; CHECK-LE-NEXT: add sp, #16139; CHECK-LE-NEXT: pop {r7, pc}140;141; CHECK-BE-LABEL: call_soft:142; CHECK-BE: @ %bb.0: @ %entry143; CHECK-BE-NEXT: .save {r7, lr}144; CHECK-BE-NEXT: push {r7, lr}145; CHECK-BE-NEXT: .pad #16146; CHECK-BE-NEXT: sub sp, #16147; CHECK-BE-NEXT: add.w r12, sp, #24148; CHECK-BE-NEXT: vldrw.u32 q0, [r12]149; CHECK-BE-NEXT: vstrw.32 q0, [sp]150; CHECK-BE-NEXT: vmov d1, r3, r2151; CHECK-BE-NEXT: vmov d0, r1, r0152; CHECK-BE-NEXT: vrev64.32 q1, q0153; CHECK-BE-NEXT: vshr.u32 q0, q1, #1154; CHECK-BE-NEXT: vrev64.32 q1, q0155; CHECK-BE-NEXT: vmov r1, r0, d2156; CHECK-BE-NEXT: vmov r3, r2, d3157; CHECK-BE-NEXT: bl add_soft158; CHECK-BE-NEXT: vmov d1, r3, r2159; CHECK-BE-NEXT: vmov d0, r1, r0160; CHECK-BE-NEXT: vrev64.32 q1, q0161; CHECK-BE-NEXT: vshr.u32 q0, q1, #1162; CHECK-BE-NEXT: vrev64.32 q1, q0163; CHECK-BE-NEXT: vmov r1, r0, d2164; CHECK-BE-NEXT: vmov r3, r2, d3165; CHECK-BE-NEXT: add sp, #16166; CHECK-BE-NEXT: pop {r7, pc}167entry:168 %0 = lshr <4 x i32> %src1, <i32 1, i32 1, i32 1, i32 1>169 %1 = call <4 x i32> @add_soft(<4 x i32> %0, <4 x i32> %src2)170 %2 = lshr <4 x i32> %1, <i32 1, i32 1, i32 1, i32 1>171 ret <4 x i32> %2172}173 174define arm_aapcs_vfpcc <4 x i32> @call_hard(<4 x i32> %src1, <4 x i32> %src2) {175; CHECK-LE-LABEL: call_hard:176; CHECK-LE: @ %bb.0: @ %entry177; CHECK-LE-NEXT: .save {r7, lr}178; CHECK-LE-NEXT: push {r7, lr}179; CHECK-LE-NEXT: vshr.u32 q0, q0, #1180; CHECK-LE-NEXT: bl add_hard181; CHECK-LE-NEXT: vshr.u32 q0, q0, #1182; CHECK-LE-NEXT: pop {r7, pc}183;184; CHECK-BE-LABEL: call_hard:185; CHECK-BE: @ %bb.0: @ %entry186; CHECK-BE-NEXT: .save {r7, lr}187; CHECK-BE-NEXT: push {r7, lr}188; CHECK-BE-NEXT: vrev64.32 q2, q0189; CHECK-BE-NEXT: vshr.u32 q2, q2, #1190; CHECK-BE-NEXT: vrev64.32 q0, q2191; CHECK-BE-NEXT: bl add_hard192; CHECK-BE-NEXT: vrev64.32 q1, q0193; CHECK-BE-NEXT: vshr.u32 q1, q1, #1194; CHECK-BE-NEXT: vrev64.32 q0, q1195; CHECK-BE-NEXT: pop {r7, pc}196entry:197 %0 = lshr <4 x i32> %src1, <i32 1, i32 1, i32 1, i32 1>198 %1 = call arm_aapcs_vfpcc <4 x i32> @add_hard(<4 x i32> %0, <4 x i32> %src2)199 %2 = lshr <4 x i32> %1, <i32 1, i32 1, i32 1, i32 1>200 ret <4 x i32> %2201}202 203define arm_aapcs_vfpcc <16 x i8> @and_v4i32(<4 x i32> %src) {204; CHECK-LE-LABEL: and_v4i32:205; CHECK-LE: @ %bb.0: @ %entry206; CHECK-LE-NEXT: vmov.i32 q1, #0x1207; CHECK-LE-NEXT: vand q0, q0, q1208; CHECK-LE-NEXT: bx lr209;210; CHECK-BE-LABEL: and_v4i32:211; CHECK-BE: @ %bb.0: @ %entry212; CHECK-BE-NEXT: vrev64.32 q1, q0213; CHECK-BE-NEXT: vmov.i32 q0, #0x1214; CHECK-BE-NEXT: vand q1, q1, q0215; CHECK-BE-NEXT: vrev64.32 q0, q1216; CHECK-BE-NEXT: bx lr217entry:218 %s1 = and <4 x i32> %src, <i32 1, i32 1, i32 1, i32 1>219 %r = bitcast <4 x i32> %s1 to <16 x i8>220 ret <16 x i8> %r221}222 223; Should be the same as and_v4i32 for LE224define arm_aapcs_vfpcc <16 x i8> @and_v16i8_le(<4 x i32> %src) {225; CHECK-LE-LABEL: and_v16i8_le:226; CHECK-LE: @ %bb.0: @ %entry227; CHECK-LE-NEXT: vmov.i32 q1, #0x1228; CHECK-LE-NEXT: vand q0, q0, q1229; CHECK-LE-NEXT: bx lr230;231; CHECK-BE-LABEL: and_v16i8_le:232; CHECK-BE: @ %bb.0: @ %entry233; CHECK-BE-NEXT: vrev64.8 q1, q0234; CHECK-BE-NEXT: vmov.i32 q0, #0x1235; CHECK-BE-NEXT: vand q1, q1, q0236; CHECK-BE-NEXT: vrev64.8 q0, q1237; CHECK-BE-NEXT: bx lr238entry:239 %0 = bitcast <4 x i32> %src to <16 x i8>240 %r = and <16 x i8> %0, <i8 1, i8 0, i8 0, i8 0, i8 1, i8 0, i8 0, i8 0, i8 1, i8 0, i8 0, i8 0, i8 1, i8 0, i8 0, i8 0>241 ret <16 x i8> %r242}243 244; Should be the same (or at least equivalent) as and_v4i32 for BE245define arm_aapcs_vfpcc <16 x i8> @and_v16i8_be(<4 x i32> %src) {246; CHECK-LE-LABEL: and_v16i8_be:247; CHECK-LE: @ %bb.0: @ %entry248; CHECK-LE-NEXT: vmov.i32 q1, #0x1000000249; CHECK-LE-NEXT: vand q0, q0, q1250; CHECK-LE-NEXT: bx lr251;252; CHECK-BE-LABEL: and_v16i8_be:253; CHECK-BE: @ %bb.0: @ %entry254; CHECK-BE-NEXT: vrev64.8 q1, q0255; CHECK-BE-NEXT: vmov.i32 q0, #0x1000000256; CHECK-BE-NEXT: vand q1, q1, q0257; CHECK-BE-NEXT: vrev64.8 q0, q1258; CHECK-BE-NEXT: bx lr259entry:260 %0 = bitcast <4 x i32> %src to <16 x i8>261 %r = and <16 x i8> %0, <i8 0, i8 0, i8 0, i8 1, i8 0, i8 0, i8 0, i8 1, i8 0, i8 0, i8 0, i8 1, i8 0, i8 0, i8 0, i8 1>262 ret <16 x i8> %r263}264 265; FIXME: This looks wrong266define arm_aapcs_vfpcc <4 x i32> @test(ptr %data) {267; CHECK-LE-LABEL: test:268; CHECK-LE: @ %bb.0: @ %entry269; CHECK-LE-NEXT: vldrw.u32 q0, [r0, #32]270; CHECK-LE-NEXT: movs r0, #1271; CHECK-LE-NEXT: vadd.i32 q1, q0, r0272; CHECK-LE-NEXT: @APP273; CHECK-LE-NEXT: vmullb.s32 q0, q1, q1274; CHECK-LE-NEXT: @NO_APP275; CHECK-LE-NEXT: bx lr276;277; CHECK-BE-LABEL: test:278; CHECK-BE: @ %bb.0: @ %entry279; CHECK-BE-NEXT: vldrw.u32 q0, [r0, #32]280; CHECK-BE-NEXT: movs r0, #1281; CHECK-BE-NEXT: vadd.i32 q0, q0, r0282; CHECK-BE-NEXT: vrev32.8 q0, q0283; CHECK-BE-NEXT: @APP284; CHECK-BE-NEXT: vmullb.s32 q1, q0, q0285; CHECK-BE-NEXT: @NO_APP286; CHECK-BE-NEXT: vrev64.8 q0, q1287; CHECK-BE-NEXT: bx lr288entry:289 %add.ptr = getelementptr inbounds i32, ptr %data, i32 8290 %0 = load <4 x i32>, ptr %add.ptr, align 4291 %1 = add <4 x i32> %0, <i32 1, i32 1, i32 1, i32 1>292 %2 = tail call <4 x i32> asm sideeffect " VMULLB.s32 $0, $1, $1", "=&w,w"(<4 x i32> %1) #2293 ret <4 x i32> %2294}295 296; Test case demonstrating that 'bitcast' reinterprets the memory format of a297; vector, as if stored and then loaded. So if it has to go between two298; operations treating a register as having different lane sizes, then in299; big-endian mode, it has to emit a vrev32.16, which is equivalent to the300; effect that vstrw.32 followed by vldrh.16 would have.301define arm_aapcs_vfpcc void @test_bitcast(ptr readonly %in, ptr %out) {302; CHECK-LE-LABEL: test_bitcast:303; CHECK-LE: @ %bb.0: @ %entry304; CHECK-LE-NEXT: vldrw.u32 q0, [r0]305; CHECK-LE-NEXT: vmul.i32 q0, q0, q0306; CHECK-LE-NEXT: vmul.i16 q0, q0, q0307; CHECK-LE-NEXT: vstrw.32 q0, [r1]308; CHECK-LE-NEXT: bx lr309;310; CHECK-BE-LABEL: test_bitcast:311; CHECK-BE: @ %bb.0: @ %entry312; CHECK-BE-NEXT: vldrw.u32 q0, [r0]313; CHECK-BE-NEXT: vmul.i32 q0, q0, q0314; CHECK-BE-NEXT: vrev32.16 q0, q0315; CHECK-BE-NEXT: vmul.i16 q0, q0, q0316; CHECK-BE-NEXT: vstrh.16 q0, [r1]317; CHECK-BE-NEXT: bx lr318entry:319 %vin = load <4 x i32>, ptr %in, align 8320 %vdbl = mul <4 x i32> %vin, %vin321 %cast = bitcast <4 x i32> %vdbl to <8 x i16>322 %cdbl = mul <8 x i16> %cast, %cast323 store <8 x i16> %cdbl, ptr %out, align 8324 ret void325}326 327; Similar test case but using the arm.mve.vreinterpretq intrinsic instead,328; which is defined to reinterpret the in-register format, so it generates no329; instruction in either endianness.330define arm_aapcs_vfpcc void @test_vreinterpretq(ptr readonly %in, ptr %out) {331; CHECK-LE-LABEL: test_vreinterpretq:332; CHECK-LE: @ %bb.0: @ %entry333; CHECK-LE-NEXT: vldrw.u32 q0, [r0]334; CHECK-LE-NEXT: vmul.i32 q0, q0, q0335; CHECK-LE-NEXT: vmul.i16 q0, q0, q0336; CHECK-LE-NEXT: vstrw.32 q0, [r1]337; CHECK-LE-NEXT: bx lr338;339; CHECK-BE-LABEL: test_vreinterpretq:340; CHECK-BE: @ %bb.0: @ %entry341; CHECK-BE-NEXT: vldrw.u32 q0, [r0]342; CHECK-BE-NEXT: vmul.i32 q0, q0, q0343; CHECK-BE-NEXT: vmul.i16 q0, q0, q0344; CHECK-BE-NEXT: vstrh.16 q0, [r1]345; CHECK-BE-NEXT: bx lr346entry:347 %vin = load <4 x i32>, ptr %in, align 8348 %vdbl = mul <4 x i32> %vin, %vin349 %cast = call <8 x i16> @llvm.arm.mve.vreinterpretq.v8i16.v4i32(<4 x i32> %vdbl)350 %cdbl = mul <8 x i16> %cast, %cast351 store <8 x i16> %cdbl, ptr %out, align 8352 ret void353}354 355define arm_aapcs_vfpcc <8 x half> @undef_one() {356; CHECK-LABEL: undef_one:357; CHECK: @ %bb.0:358; CHECK-NEXT: bx lr359 %c = call <8 x half> @llvm.arm.mve.vreinterpretq.v8f16.v4f32(<4 x float> undef)360 ret <8 x half> %c361}362 363declare <8 x half> @llvm.arm.mve.vreinterpretq.v8f16.v4f32(<4 x float>)364declare <8 x i16> @llvm.arm.mve.vreinterpretq.v8i16.v4i32(<4 x i32>)365