324 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 22; RUN: llc < %s -verify-machineinstrs -mtriple=arm64-none-linux-gnu -mattr=+neon -fp-contract=fast | FileCheck %s3 4; FIXME: We should not generate ld/st for such register spill/fill, because the5; test case seems very simple and the register pressure is not high. If the6; spill/fill algorithm is optimized, this test case may not be triggered. And7; then we can delete it.8define i32 @spill.DPairReg(ptr %arg1, i32 %arg2) {9; CHECK-LABEL: spill.DPairReg:10; CHECK: // %bb.0: // %entry11; CHECK-NEXT: ld2 { v0.2s, v1.2s }, [x0]12; CHECK-NEXT: cbz w1, .LBB0_213; CHECK-NEXT: // %bb.1: // %if.end14; CHECK-NEXT: mov w0, v0.s[1]15; CHECK-NEXT: ret16; CHECK-NEXT: .LBB0_2: // %if.then17; CHECK-NEXT: sub sp, sp, #4818; CHECK-NEXT: stp x29, x30, [sp, #32] // 16-byte Folded Spill19; CHECK-NEXT: .cfi_def_cfa_offset 4820; CHECK-NEXT: .cfi_offset w30, -821; CHECK-NEXT: .cfi_offset w29, -1622; CHECK-NEXT: mov x8, sp23; CHECK-NEXT: st1 { v0.2d, v1.2d }, [x8] // 32-byte Folded Spill24; CHECK-NEXT: bl foo25; CHECK-NEXT: mov x8, sp26; CHECK-NEXT: ldp x29, x30, [sp, #32] // 16-byte Folded Reload27; CHECK-NEXT: ld1 { v0.2d, v1.2d }, [x8] // 32-byte Folded Reload28; CHECK-NEXT: add sp, sp, #4829; CHECK-NEXT: mov w0, v0.s[1]30; CHECK-NEXT: ret31entry:32 %vld = tail call { <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld2.v2i32.p0(ptr %arg1)33 %cmp = icmp eq i32 %arg2, 034 br i1 %cmp, label %if.then, label %if.end35 36if.then:37 tail call void @foo()38 br label %if.end39 40if.end:41 %vld.extract = extractvalue { <2 x i32>, <2 x i32> } %vld, 042 %res = extractelement <2 x i32> %vld.extract, i32 143 ret i32 %res44}45 46define i16 @spill.DTripleReg(ptr %arg1, i32 %arg2) {47; CHECK-LABEL: spill.DTripleReg:48; CHECK: // %bb.0: // %entry49; CHECK-NEXT: ld3 { v0.4h, v1.4h, v2.4h }, [x0]50; CHECK-NEXT: cbz w1, .LBB1_251; CHECK-NEXT: // %bb.1: // %if.end52; CHECK-NEXT: umov w0, v0.h[1]53; CHECK-NEXT: ret54; CHECK-NEXT: .LBB1_2: // %if.then55; CHECK-NEXT: sub sp, sp, #6456; CHECK-NEXT: stp x29, x30, [sp, #48] // 16-byte Folded Spill57; CHECK-NEXT: .cfi_def_cfa_offset 6458; CHECK-NEXT: .cfi_offset w30, -859; CHECK-NEXT: .cfi_offset w29, -1660; CHECK-NEXT: mov x8, sp61; CHECK-NEXT: st1 { v0.2d, v1.2d, v2.2d }, [x8] // 48-byte Folded Spill62; CHECK-NEXT: bl foo63; CHECK-NEXT: mov x8, sp64; CHECK-NEXT: ldp x29, x30, [sp, #48] // 16-byte Folded Reload65; CHECK-NEXT: ld1 { v0.2d, v1.2d, v2.2d }, [x8] // 48-byte Folded Reload66; CHECK-NEXT: add sp, sp, #6467; CHECK-NEXT: umov w0, v0.h[1]68; CHECK-NEXT: ret69entry:70 %vld = tail call { <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld3.v4i16.p0(ptr %arg1)71 %cmp = icmp eq i32 %arg2, 072 br i1 %cmp, label %if.then, label %if.end73 74if.then:75 tail call void @foo()76 br label %if.end77 78if.end:79 %vld.extract = extractvalue { <4 x i16>, <4 x i16>, <4 x i16> } %vld, 080 %res = extractelement <4 x i16> %vld.extract, i32 181 ret i16 %res82}83 84define i16 @spill.DQuadReg(ptr %arg1, i32 %arg2) {85; CHECK-LABEL: spill.DQuadReg:86; CHECK: // %bb.0: // %entry87; CHECK-NEXT: ld4 { v0.4h, v1.4h, v2.4h, v3.4h }, [x0]88; CHECK-NEXT: cbz w1, .LBB2_289; CHECK-NEXT: // %bb.1: // %if.end90; CHECK-NEXT: umov w0, v0.h[0]91; CHECK-NEXT: ret92; CHECK-NEXT: .LBB2_2: // %if.then93; CHECK-NEXT: sub sp, sp, #8094; CHECK-NEXT: stp x29, x30, [sp, #64] // 16-byte Folded Spill95; CHECK-NEXT: .cfi_def_cfa_offset 8096; CHECK-NEXT: .cfi_offset w30, -897; CHECK-NEXT: .cfi_offset w29, -1698; CHECK-NEXT: mov x8, sp99; CHECK-NEXT: st1 { v0.2d, v1.2d, v2.2d, v3.2d }, [x8] // 64-byte Folded Spill100; CHECK-NEXT: bl foo101; CHECK-NEXT: mov x8, sp102; CHECK-NEXT: ldp x29, x30, [sp, #64] // 16-byte Folded Reload103; CHECK-NEXT: ld1 { v0.2d, v1.2d, v2.2d, v3.2d }, [x8] // 64-byte Folded Reload104; CHECK-NEXT: add sp, sp, #80105; CHECK-NEXT: umov w0, v0.h[0]106; CHECK-NEXT: ret107entry:108 %vld = tail call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld4.v4i16.p0(ptr %arg1)109 %cmp = icmp eq i32 %arg2, 0110 br i1 %cmp, label %if.then, label %if.end111 112if.then:113 tail call void @foo()114 br label %if.end115 116if.end:117 %vld.extract = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } %vld, 0118 %res = extractelement <4 x i16> %vld.extract, i32 0119 ret i16 %res120}121 122define i32 @spill.QPairReg(ptr %arg1, i32 %arg2) {123; CHECK-LABEL: spill.QPairReg:124; CHECK: // %bb.0: // %entry125; CHECK-NEXT: ld2 { v0.4s, v1.4s }, [x0]126; CHECK-NEXT: cbz w1, .LBB3_2127; CHECK-NEXT: // %bb.1: // %if.end128; CHECK-NEXT: mov w0, v0.s[1]129; CHECK-NEXT: ret130; CHECK-NEXT: .LBB3_2: // %if.then131; CHECK-NEXT: sub sp, sp, #48132; CHECK-NEXT: stp x29, x30, [sp, #32] // 16-byte Folded Spill133; CHECK-NEXT: .cfi_def_cfa_offset 48134; CHECK-NEXT: .cfi_offset w30, -8135; CHECK-NEXT: .cfi_offset w29, -16136; CHECK-NEXT: mov x8, sp137; CHECK-NEXT: st1 { v0.2d, v1.2d }, [x8] // 32-byte Folded Spill138; CHECK-NEXT: bl foo139; CHECK-NEXT: mov x8, sp140; CHECK-NEXT: ldp x29, x30, [sp, #32] // 16-byte Folded Reload141; CHECK-NEXT: ld1 { v0.2d, v1.2d }, [x8] // 32-byte Folded Reload142; CHECK-NEXT: add sp, sp, #48143; CHECK-NEXT: mov w0, v0.s[1]144; CHECK-NEXT: ret145entry:146 %vld = tail call { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0(ptr %arg1)147 %cmp = icmp eq i32 %arg2, 0148 br i1 %cmp, label %if.then, label %if.end149 150if.then:151 tail call void @foo()152 br label %if.end153 154if.end:155 %vld.extract = extractvalue { <4 x i32>, <4 x i32> } %vld, 0156 %res = extractelement <4 x i32> %vld.extract, i32 1157 ret i32 %res158}159 160define float @spill.QTripleReg(ptr %arg1, i32 %arg2) {161; CHECK-LABEL: spill.QTripleReg:162; CHECK: // %bb.0: // %entry163; CHECK-NEXT: ld3 { v0.4s, v1.4s, v2.4s }, [x0]164; CHECK-NEXT: cbz w1, .LBB4_2165; CHECK-NEXT: // %bb.1: // %if.end166; CHECK-NEXT: mov s0, v0.s[1]167; CHECK-NEXT: ret168; CHECK-NEXT: .LBB4_2: // %if.then169; CHECK-NEXT: sub sp, sp, #64170; CHECK-NEXT: stp x29, x30, [sp, #48] // 16-byte Folded Spill171; CHECK-NEXT: .cfi_def_cfa_offset 64172; CHECK-NEXT: .cfi_offset w30, -8173; CHECK-NEXT: .cfi_offset w29, -16174; CHECK-NEXT: mov x8, sp175; CHECK-NEXT: st1 { v0.2d, v1.2d, v2.2d }, [x8] // 48-byte Folded Spill176; CHECK-NEXT: bl foo177; CHECK-NEXT: mov x8, sp178; CHECK-NEXT: ldp x29, x30, [sp, #48] // 16-byte Folded Reload179; CHECK-NEXT: ld1 { v0.2d, v1.2d, v2.2d }, [x8] // 48-byte Folded Reload180; CHECK-NEXT: add sp, sp, #64181; CHECK-NEXT: mov s0, v0.s[1]182; CHECK-NEXT: ret183entry:184 %vld3 = tail call { <4 x float>, <4 x float>, <4 x float> } @llvm.aarch64.neon.ld3.v4f32.p0(ptr %arg1)185 %cmp = icmp eq i32 %arg2, 0186 br i1 %cmp, label %if.then, label %if.end187 188if.then:189 tail call void @foo()190 br label %if.end191 192if.end:193 %vld3.extract = extractvalue { <4 x float>, <4 x float>, <4 x float> } %vld3, 0194 %res = extractelement <4 x float> %vld3.extract, i32 1195 ret float %res196}197 198define i8 @spill.QQuadReg(ptr %arg1, i32 %arg2) {199; CHECK-LABEL: spill.QQuadReg:200; CHECK: // %bb.0: // %entry201; CHECK-NEXT: ld4 { v0.16b, v1.16b, v2.16b, v3.16b }, [x0]202; CHECK-NEXT: cbz w1, .LBB5_2203; CHECK-NEXT: // %bb.1: // %if.end204; CHECK-NEXT: umov w0, v0.b[1]205; CHECK-NEXT: ret206; CHECK-NEXT: .LBB5_2: // %if.then207; CHECK-NEXT: sub sp, sp, #80208; CHECK-NEXT: stp x29, x30, [sp, #64] // 16-byte Folded Spill209; CHECK-NEXT: .cfi_def_cfa_offset 80210; CHECK-NEXT: .cfi_offset w30, -8211; CHECK-NEXT: .cfi_offset w29, -16212; CHECK-NEXT: mov x8, sp213; CHECK-NEXT: st1 { v0.2d, v1.2d, v2.2d, v3.2d }, [x8] // 64-byte Folded Spill214; CHECK-NEXT: bl foo215; CHECK-NEXT: mov x8, sp216; CHECK-NEXT: ldp x29, x30, [sp, #64] // 16-byte Folded Reload217; CHECK-NEXT: ld1 { v0.2d, v1.2d, v2.2d, v3.2d }, [x8] // 64-byte Folded Reload218; CHECK-NEXT: add sp, sp, #80219; CHECK-NEXT: umov w0, v0.b[1]220; CHECK-NEXT: ret221entry:222 %vld = tail call { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } @llvm.aarch64.neon.ld4.v16i8.p0(ptr %arg1)223 %cmp = icmp eq i32 %arg2, 0224 br i1 %cmp, label %if.then, label %if.end225 226if.then:227 tail call void @foo()228 br label %if.end229 230if.end:231 %vld.extract = extractvalue { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } %vld, 0232 %res = extractelement <16 x i8> %vld.extract, i32 1233 ret i8 %res234}235 236declare { <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld2.v2i32.p0(ptr)237declare { <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld3.v4i16.p0(ptr)238declare { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld4.v4i16.p0(ptr)239declare { <4 x i32>, <4 x i32> } @llvm.aarch64.neon.ld2.v4i32.p0(ptr)240declare { <4 x float>, <4 x float>, <4 x float> } @llvm.aarch64.neon.ld3.v4f32.p0(ptr)241declare { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } @llvm.aarch64.neon.ld4.v16i8.p0(ptr)242 243declare void @foo()244 245; FIXME: We should not generate ld/st for such register spill/fill, because the246; test case seems very simple and the register pressure is not high. If the247; spill/fill algorithm is optimized, this test case may not be triggered. And248; then we can delete it.249; check the spill for Register Class QPair_with_qsub_0_in_FPR128Lo250define <8 x i16> @test_2xFPR128Lo(i64 %got, ptr %ptr, <1 x i64> %a) {251; CHECK-LABEL: test_2xFPR128Lo:252; CHECK: // %bb.0:253; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill254; CHECK-NEXT: .cfi_def_cfa_offset 16255; CHECK-NEXT: .cfi_offset w30, -16256; CHECK-NEXT: movi v0.2d, #0000000000000000257; CHECK-NEXT: mov v1.16b, v0.16b258; CHECK-NEXT: st2 { v0.d, v1.d }[0], [x1]259; CHECK-NEXT: bl foo260; CHECK-NEXT: movi v0.2d, #0000000000000000261; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload262; CHECK-NEXT: ret263 tail call void @llvm.aarch64.neon.st2lane.v1i64.p0(<1 x i64> zeroinitializer, <1 x i64> zeroinitializer, i64 0, ptr %ptr)264 tail call void @foo()265 %sv = shufflevector <1 x i64> zeroinitializer, <1 x i64> %a, <2 x i32> <i32 0, i32 1>266 %1 = bitcast <2 x i64> %sv to <8 x i16>267 %2 = shufflevector <8 x i16> %1, <8 x i16> undef, <8 x i32> <i32 2, i32 2, i32 2, i32 2, i32 2, i32 2, i32 2, i32 2>268 %3 = mul <8 x i16> %2, %2269 ret <8 x i16> %3270}271 272; check the spill for Register Class QTriple_with_qsub_0_in_FPR128Lo273define <8 x i16> @test_3xFPR128Lo(i64 %got, ptr %ptr, <1 x i64> %a) {274; CHECK-LABEL: test_3xFPR128Lo:275; CHECK: // %bb.0:276; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill277; CHECK-NEXT: .cfi_def_cfa_offset 16278; CHECK-NEXT: .cfi_offset w30, -16279; CHECK-NEXT: movi v0.2d, #0000000000000000280; CHECK-NEXT: mov v1.16b, v0.16b281; CHECK-NEXT: mov v2.16b, v0.16b282; CHECK-NEXT: st3 { v0.d, v1.d, v2.d }[0], [x1]283; CHECK-NEXT: bl foo284; CHECK-NEXT: movi v0.2d, #0000000000000000285; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload286; CHECK-NEXT: ret287 tail call void @llvm.aarch64.neon.st3lane.v1i64.p0(<1 x i64> zeroinitializer, <1 x i64> zeroinitializer, <1 x i64> zeroinitializer, i64 0, ptr %ptr)288 tail call void @foo()289 %sv = shufflevector <1 x i64> zeroinitializer, <1 x i64> %a, <2 x i32> <i32 0, i32 1>290 %1 = bitcast <2 x i64> %sv to <8 x i16>291 %2 = shufflevector <8 x i16> %1, <8 x i16> undef, <8 x i32> <i32 2, i32 2, i32 2, i32 2, i32 2, i32 2, i32 2, i32 2>292 %3 = mul <8 x i16> %2, %2293 ret <8 x i16> %3294}295 296; check the spill for Register Class QQuad_with_qsub_0_in_FPR128Lo297define <8 x i16> @test_4xFPR128Lo(i64 %got, ptr %ptr, <1 x i64> %a) {298; CHECK-LABEL: test_4xFPR128Lo:299; CHECK: // %bb.0:300; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill301; CHECK-NEXT: .cfi_def_cfa_offset 16302; CHECK-NEXT: .cfi_offset w30, -16303; CHECK-NEXT: movi v0.2d, #0000000000000000304; CHECK-NEXT: mov v1.16b, v0.16b305; CHECK-NEXT: mov v2.16b, v0.16b306; CHECK-NEXT: mov v3.16b, v0.16b307; CHECK-NEXT: st4 { v0.d, v1.d, v2.d, v3.d }[0], [x1]308; CHECK-NEXT: bl foo309; CHECK-NEXT: movi v0.2d, #0000000000000000310; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload311; CHECK-NEXT: ret312 tail call void @llvm.aarch64.neon.st4lane.v1i64.p0(<1 x i64> zeroinitializer, <1 x i64> zeroinitializer, <1 x i64> zeroinitializer, <1 x i64> zeroinitializer, i64 0, ptr %ptr)313 tail call void @foo()314 %sv = shufflevector <1 x i64> zeroinitializer, <1 x i64> %a, <2 x i32> <i32 0, i32 1>315 %1 = bitcast <2 x i64> %sv to <8 x i16>316 %2 = shufflevector <8 x i16> %1, <8 x i16> undef, <8 x i32> <i32 2, i32 2, i32 2, i32 2, i32 2, i32 2, i32 2, i32 2>317 %3 = mul <8 x i16> %2, %2318 ret <8 x i16> %3319}320 321declare void @llvm.aarch64.neon.st2lane.v1i64.p0(<1 x i64>, <1 x i64>, i64, ptr)322declare void @llvm.aarch64.neon.st3lane.v1i64.p0(<1 x i64>, <1 x i64>, <1 x i64>, i64, ptr)323declare void @llvm.aarch64.neon.st4lane.v1i64.p0(<1 x i64>, <1 x i64>, <1 x i64>, <1 x i64>, i64, ptr)324