[llvm] [AArch64] Remove extra fmov after half-vector Neon LD instruction (PR #216758)
Kieran B via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 25 01:51:27 PDT 2026
https://github.com/kieroxide updated https://github.com/llvm/llvm-project/pull/216758
>From 9133dc3ab8240f0f5b4db15ff25e1553575e642e Mon Sep 17 00:00:00 2001
From: Kieran Bailey <kieran.bailey at arm.com>
Date: Mon, 17 Aug 2026 15:20:01 +0000
Subject: [PATCH 1/3] [AArch64] Remove extra fmov after half-vector Neon LD
instruction
Currently, after a load instruction resulting in a half-vector tuple, llvm emits an extra fmov for explicitly zeroing the upper-half of the vector register when returning a value in the tuple as the full 128 bit vector. This is unneeded as the ld instruction already zeros the upper half of the registers in the tuple.
Add special case to existing peephole function that can recognise the tuple defining opcode and remove the extra fmov
Test before the change in this commit, next commit will contain the test checks after the change.
---
.../Target/AArch64/AArch64MIPeepholeOpt.cpp | 43 +-
.../CodeGen/AArch64/ld-tuple-dsub-fmov.ll | 434 ++++++++++++++++++
2 files changed, 475 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/CodeGen/AArch64/ld-tuple-dsub-fmov.ll
diff --git a/llvm/lib/Target/AArch64/AArch64MIPeepholeOpt.cpp b/llvm/lib/Target/AArch64/AArch64MIPeepholeOpt.cpp
index a292aee81e615..1638314e18a26 100644
--- a/llvm/lib/Target/AArch64/AArch64MIPeepholeOpt.cpp
+++ b/llvm/lib/Target/AArch64/AArch64MIPeepholeOpt.cpp
@@ -700,6 +700,37 @@ bool AArch64MIPeepholeOptImpl::visitINSviGPR(MachineInstr &MI, unsigned Opc) {
return true;
}
+static bool isZeroingDRegLoadOpcode(unsigned int Op) {
+ switch (Op) {
+ case AArch64::LD1Twov1d:
+ case AArch64::LD1Twov1d_POST:
+ case AArch64::LD1Threev1d:
+ case AArch64::LD1Threev1d_POST:
+ case AArch64::LD1Fourv1d:
+ case AArch64::LD1Fourv1d_POST:
+ case AArch64::LD2Twov8b:
+ case AArch64::LD2Twov8b_POST:
+ case AArch64::LD2Twov4h:
+ case AArch64::LD2Twov4h_POST:
+ case AArch64::LD2Twov2s:
+ case AArch64::LD2Twov2s_POST:
+ case AArch64::LD3Threev8b:
+ case AArch64::LD3Threev8b_POST:
+ case AArch64::LD3Threev4h:
+ case AArch64::LD3Threev4h_POST:
+ case AArch64::LD3Threev2s:
+ case AArch64::LD3Threev2s_POST:
+ case AArch64::LD4Fourv8b:
+ case AArch64::LD4Fourv8b_POST:
+ case AArch64::LD4Fourv4h:
+ case AArch64::LD4Fourv4h_POST:
+ case AArch64::LD4Fourv2s:
+ case AArch64::LD4Fourv2s_POST:
+ return true;
+ }
+ return false;
+}
+
// All instructions that set a FPR64 will implicitly zero the top bits of the
// register. When the def is expressed as a COPY from a GPR, turn it into an
// explicit FMOV so it cannot be elided later in further passes.
@@ -715,9 +746,17 @@ static bool is64bitDefwithZeroHigh64bit(MachineInstr *MI,
MachineOperand &SrcOp = MI->getOperand(1);
if (!SrcOp.isReg())
return false;
- if (SrcOp.getSubReg())
- return false;
Register SrcReg = SrcOp.getReg();
+ if (SrcOp.getSubReg()) {
+ // If operand is defined by a LD1/2/3/4 that define a D subreg
+ // Then upper bits are implicitly zeroed and fmov is unneeded
+ if (!SrcReg.isVirtual()) {
+ return false;
+ }
+
+ MachineInstr *SrcDef = MRI->getUniqueVRegDef(SrcReg);
+ return SrcDef && isZeroingDRegLoadOpcode(SrcDef->getOpcode());
+ }
auto IsGPR64Like = [&]() -> bool {
if (SrcReg.isVirtual())
return AArch64::GPR64allRegClass.hasSubClassEq(
diff --git a/llvm/test/CodeGen/AArch64/ld-tuple-dsub-fmov.ll b/llvm/test/CodeGen/AArch64/ld-tuple-dsub-fmov.ll
new file mode 100644
index 0000000000000..a501c1c7f51eb
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/ld-tuple-dsub-fmov.ll
@@ -0,0 +1,434 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=aarch64-linux-gnu -asm-verbose=false -O1 < %s | FileCheck %s -check-prefixes=CHECK
+
+target triple = "aarch64-unknown-linux-gnu"
+
+; Tests the codegen for the following code.
+; The D register resulting 'ld2/3/4' instruction implicitly zeroes the upper bits so we can return straight after it.
+; uint8x16_t foo(uint8_t *a) {
+; return vcombine_u8(vld2_u8(a).val[0], vdup_n_u8(0));
+; }
+
+define <16 x i8> @ld2_u8_val0(ptr %a) {
+; CHECK-LABEL: ld2_u8_val0:
+; CHECK: ld2 { v0.8b, v1.8b }, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %vld2 = call { <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld2.v8i8.p0(ptr %a)
+ %vld2.fca.0.extract = extractvalue { <8 x i8>, <8 x i8> } %vld2, 0
+ %shuffle.i = shufflevector <8 x i8> %vld2.fca.0.extract, <8 x i8> zeroinitializer, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ ret <16 x i8> %shuffle.i
+}
+
+define <16 x i8> @ld2_u8_val0_post(ptr %a) {
+; CHECK-LABEL: ld2_u8_val0_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld2 { v0.8b, v1.8b }, [x8], #16
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %a, align 8
+ %vld2 = call { <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld2.v8i8.p0(ptr %0)
+ %vld2.fca.0.extract = extractvalue { <8 x i8>, <8 x i8> } %vld2, 0
+ %shuffle.i = shufflevector <8 x i8> %vld2.fca.0.extract, <8 x i8> zeroinitializer, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 16
+ store ptr %add.ptr, ptr %a, align 8
+ ret <16 x i8> %shuffle.i
+}
+
+define <8 x i16> @ld2_u16_val0(ptr %a) {
+; CHECK-LABEL: ld2_u16_val0:
+; CHECK: ld2 { v0.4h, v1.4h }, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %vld2 = call { <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld2.v4i16.p0(ptr %a)
+ %vld2.fca.0.extract = extractvalue { <4 x i16>, <4 x i16> } %vld2, 0
+ %shuffle.i = shufflevector <4 x i16> %vld2.fca.0.extract, <4 x i16> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ ret <8 x i16> %shuffle.i
+}
+
+
+define <8 x i16> @ld2_u16_val0_post(ptr %a) {
+; CHECK-LABEL: ld2_u16_val0_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld2 { v0.4h, v1.4h }, [x8], #16
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %a, align 8
+ %vld2 = call { <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld2.v4i16.p0(ptr %0)
+ %vld2.fca.0.extract = extractvalue { <4 x i16>, <4 x i16> } %vld2, 0
+ %shuffle.i = shufflevector <4 x i16> %vld2.fca.0.extract, <4 x i16> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 16
+ store ptr %add.ptr, ptr %a, align 8
+ ret <8 x i16> %shuffle.i
+}
+
+define <4 x i32> @ld2_u32_val0(ptr %a) {
+; CHECK-LABEL: ld2_u32_val0:
+; CHECK: ld2 { v0.2s, v1.2s }, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %vld2 = call { <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld2.v2i32.p0(ptr %a)
+ %vld2.fca.0.extract = extractvalue { <2 x i32>, <2 x i32> } %vld2, 0
+ %shuffle.i = shufflevector <2 x i32> %vld2.fca.0.extract, <2 x i32> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ ret <4 x i32> %shuffle.i
+}
+
+
+define <4 x i32> @ld2_u32_val0_post(ptr %a) {
+; CHECK-LABEL: ld2_u32_val0_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld2 { v0.2s, v1.2s }, [x8], #16
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %a, align 8
+ %vld2 = call { <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld2.v2i32.p0(ptr %0)
+ %vld2.fca.0.extract = extractvalue { <2 x i32>, <2 x i32> } %vld2, 0
+ %shuffle.i = shufflevector <2 x i32> %vld2.fca.0.extract, <2 x i32> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 16
+ store ptr %add.ptr, ptr %a, align 8
+ ret <4 x i32> %shuffle.i
+}
+
+define <2 x i64> @ld2_u64_val0(ptr %a) {
+;
+; CHECK-LABEL: ld2_u64_val0:
+; CHECK: ld1 { v0.1d, v1.1d }, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %vld2 = call { <1 x i64>, <1 x i64> } @llvm.aarch64.neon.ld2.v1i64.p0(ptr %a)
+ %vld2.fca.0.extract = extractvalue { <1 x i64>, <1 x i64> } %vld2, 0
+ %shuffle.i = shufflevector <1 x i64> %vld2.fca.0.extract, <1 x i64> zeroinitializer, <2 x i32> <i32 0, i32 1>
+ ret <2 x i64> %shuffle.i
+}
+
+
+define <2 x i64> @ld2_u64_val0_post(ptr %a) {
+;
+; CHECK-LABEL: ld2_u64_val0_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld1 { v0.1d, v1.1d }, [x8], #16
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %a, align 8
+ %vld2 = call { <1 x i64>, <1 x i64> } @llvm.aarch64.neon.ld2.v1i64.p0(ptr %0)
+ %vld2.fca.0.extract = extractvalue { <1 x i64>, <1 x i64> } %vld2, 0
+ %shuffle.i = shufflevector <1 x i64> %vld2.fca.0.extract, <1 x i64> zeroinitializer, <2 x i32> <i32 0, i32 1>
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 16
+ store ptr %add.ptr, ptr %a, align 8
+ ret <2 x i64> %shuffle.i
+}
+
+define <16 x i8> @ld3_u8_val0(ptr %a) {
+; CHECK-LABEL: ld3_u8_val0:
+; CHECK: ld3 { v0.8b, v1.8b, v2.8b }, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %vld3 = call { <8 x i8>, <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld3.v8i8.p0(ptr %a)
+ %vld3.fca.0.extract = extractvalue { <8 x i8>, <8 x i8>, <8 x i8> } %vld3, 0
+ %shuffle.i = shufflevector <8 x i8> %vld3.fca.0.extract, <8 x i8> zeroinitializer, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ ret <16 x i8> %shuffle.i
+}
+
+
+define <16 x i8> @ld3_u8_val0_post(ptr %a) {
+;
+; CHECK-LABEL: ld3_u8_val0_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld3 { v0.8b, v1.8b, v2.8b }, [x8], #24
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %a, align 8
+ %vld3 = call { <8 x i8>, <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld3.v8i8.p0(ptr %0)
+ %vld3.fca.0.extract = extractvalue { <8 x i8>, <8 x i8>, <8 x i8> } %vld3, 0
+ %shuffle.i = shufflevector <8 x i8> %vld3.fca.0.extract, <8 x i8> zeroinitializer, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 24
+ store ptr %add.ptr, ptr %a, align 8
+ ret <16 x i8> %shuffle.i
+}
+
+define <8 x i16> @ld3_u16_val0(ptr %a) {
+; CHECK-LABEL: ld3_u16_val0:
+; CHECK: ld3 { v0.4h, v1.4h, v2.4h }, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %vld3 = call { <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld3.v4i16.p0(ptr %a)
+ %vld3.fca.0.extract = extractvalue { <4 x i16>, <4 x i16>, <4 x i16> } %vld3, 0
+ %shuffle.i = shufflevector <4 x i16> %vld3.fca.0.extract, <4 x i16> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ ret <8 x i16> %shuffle.i
+}
+
+
+define <8 x i16> @ld3_u16_val0_post(ptr %a) {
+;
+; CHECK-LABEL: ld3_u16_val0_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld3 { v0.4h, v1.4h, v2.4h }, [x8], #24
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %a, align 8
+ %vld3 = call { <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld3.v4i16.p0(ptr %0)
+ %vld3.fca.0.extract = extractvalue { <4 x i16>, <4 x i16>, <4 x i16> } %vld3, 0
+ %shuffle.i = shufflevector <4 x i16> %vld3.fca.0.extract, <4 x i16> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 24
+ store ptr %add.ptr, ptr %a, align 8
+ ret <8 x i16> %shuffle.i
+}
+
+define <4 x i32> @ld3_u32_val0(ptr %a) {
+; CHECK-LABEL: ld3_u32_val0:
+; CHECK: ld3 { v0.2s, v1.2s, v2.2s }, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %vld3 = call { <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld3.v2i32.p0(ptr %a)
+ %vld3.fca.0.extract = extractvalue { <2 x i32>, <2 x i32>, <2 x i32> } %vld3, 0
+ %shuffle.i = shufflevector <2 x i32> %vld3.fca.0.extract, <2 x i32> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ ret <4 x i32> %shuffle.i
+}
+
+
+define <4 x i32> @ld3_u32_val0_post(ptr %a) {
+;
+; CHECK-LABEL: ld3_u32_val0_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld3 { v0.2s, v1.2s, v2.2s }, [x8], #24
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %a, align 8
+ %vld3 = call { <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld3.v2i32.p0(ptr %0)
+ %vld3.fca.0.extract = extractvalue { <2 x i32>, <2 x i32>, <2 x i32> } %vld3, 0
+ %shuffle.i = shufflevector <2 x i32> %vld3.fca.0.extract, <2 x i32> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 24
+ store ptr %add.ptr, ptr %a, align 8
+ ret <4 x i32> %shuffle.i
+}
+
+define <2 x i64> @ld3_u64_val0(ptr %a) {
+;
+; CHECK-LABEL: ld3_u64_val0:
+; CHECK: ld1 { v0.1d, v1.1d, v2.1d }, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %vld3 = call { <1 x i64>, <1 x i64>, <1 x i64> } @llvm.aarch64.neon.ld3.v1i64.p0(ptr %a)
+ %vld3.fca.0.extract = extractvalue { <1 x i64>, <1 x i64>, <1 x i64> } %vld3, 0
+ %shuffle.i = shufflevector <1 x i64> %vld3.fca.0.extract, <1 x i64> zeroinitializer, <2 x i32> <i32 0, i32 1>
+ ret <2 x i64> %shuffle.i
+}
+
+
+define <2 x i64> @ld3_u64_val0_post(ptr %a) {
+;
+; CHECK-LABEL: ld3_u64_val0_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld1 { v0.1d, v1.1d, v2.1d }, [x8], #24
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %a, align 8
+ %vld3 = call { <1 x i64>, <1 x i64>, <1 x i64> } @llvm.aarch64.neon.ld3.v1i64.p0(ptr %0)
+ %vld3.fca.0.extract = extractvalue { <1 x i64>, <1 x i64>, <1 x i64> } %vld3, 0
+ %shuffle.i = shufflevector <1 x i64> %vld3.fca.0.extract, <1 x i64> zeroinitializer, <2 x i32> <i32 0, i32 1>
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 24
+ store ptr %add.ptr, ptr %a, align 8
+ ret <2 x i64> %shuffle.i
+}
+
+define <16 x i8> @ld4_u8_val0(ptr %a) {
+; CHECK-LABEL: ld4_u8_val0:
+; CHECK: ld4 { v0.8b, v1.8b, v2.8b, v3.8b }, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %vld4 = call { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld4.v8i8.p0(ptr %a)
+ %vld4.fca.0.extract = extractvalue { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } %vld4, 0
+ %shuffle.i = shufflevector <8 x i8> %vld4.fca.0.extract, <8 x i8> zeroinitializer, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ ret <16 x i8> %shuffle.i
+}
+
+
+define <16 x i8> @ld4_u8_val0_post(ptr %a) {
+;
+; CHECK-LABEL: ld4_u8_val0_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld4 { v0.8b, v1.8b, v2.8b, v3.8b }, [x8], #32
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %a, align 8
+ %vld4 = call { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld4.v8i8.p0(ptr %0)
+ %vld4.fca.0.extract = extractvalue { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } %vld4, 0
+ %shuffle.i = shufflevector <8 x i8> %vld4.fca.0.extract, <8 x i8> zeroinitializer, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 32
+ store ptr %add.ptr, ptr %a, align 8
+ ret <16 x i8> %shuffle.i
+}
+
+define <8 x i16> @ld4_u16_val0(ptr %a) {
+; CHECK-LABEL: ld4_u16_val0:
+; CHECK: ld4 { v0.4h, v1.4h, v2.4h, v3.4h }, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %vld4 = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld4.v4i16.p0(ptr %a)
+ %vld4.fca.0.extract = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } %vld4, 0
+ %shuffle.i = shufflevector <4 x i16> %vld4.fca.0.extract, <4 x i16> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ ret <8 x i16> %shuffle.i
+}
+
+
+define <8 x i16> @ld4_u16_val0_post(ptr %a) {
+;
+; CHECK-LABEL: ld4_u16_val0_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld4 { v0.4h, v1.4h, v2.4h, v3.4h }, [x8], #32
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %a, align 8
+ %vld4 = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld4.v4i16.p0(ptr %0)
+ %vld4.fca.0.extract = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } %vld4, 0
+ %shuffle.i = shufflevector <4 x i16> %vld4.fca.0.extract, <4 x i16> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 32
+ store ptr %add.ptr, ptr %a, align 8
+ ret <8 x i16> %shuffle.i
+}
+
+define <4 x i32> @ld4_u32_val0(ptr %a) {
+; CHECK-LABEL: ld4_u32_val0:
+; CHECK: ld4 { v0.2s, v1.2s, v2.2s, v3.2s }, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %vld4 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld4.v2i32.p0(ptr %a)
+ %vld4.fca.0.extract = extractvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } %vld4, 0
+ %shuffle.i = shufflevector <2 x i32> %vld4.fca.0.extract, <2 x i32> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ ret <4 x i32> %shuffle.i
+}
+
+
+define <4 x i32> @ld4_u32_val0_post(ptr %a) {
+;
+; CHECK-LABEL: ld4_u32_val0_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld4 { v0.2s, v1.2s, v2.2s, v3.2s }, [x8], #32
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %a, align 8
+ %vld4 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld4.v2i32.p0(ptr %0)
+ %vld4.fca.0.extract = extractvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } %vld4, 0
+ %shuffle.i = shufflevector <2 x i32> %vld4.fca.0.extract, <2 x i32> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 32
+ store ptr %add.ptr, ptr %a, align 8
+ ret <4 x i32> %shuffle.i
+}
+
+define <2 x i64> @ld4_u64_val0(ptr %a) {
+;
+; CHECK-LABEL: ld4_u64_val0:
+; CHECK: ld1 { v0.1d, v1.1d, v2.1d, v3.1d }, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %vld4 = call { <1 x i64>, <1 x i64>, <1 x i64>, <1 x i64> } @llvm.aarch64.neon.ld4.v1i64.p0(ptr %a)
+ %vld4.fca.0.extract = extractvalue { <1 x i64>, <1 x i64>, <1 x i64>, <1 x i64> } %vld4, 0
+ %shuffle.i = shufflevector <1 x i64> %vld4.fca.0.extract, <1 x i64> zeroinitializer, <2 x i32> <i32 0, i32 1>
+ ret <2 x i64> %shuffle.i
+}
+
+
+define <2 x i64> @ld4_u64_val0_post(ptr %a) {
+;
+; CHECK-LABEL: ld4_u64_val0_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld1 { v0.1d, v1.1d, v2.1d, v3.1d }, [x8], #32
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: fmov d0, d0
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %a, align 8
+ %vld4 = call { <1 x i64>, <1 x i64>, <1 x i64>, <1 x i64> } @llvm.aarch64.neon.ld4.v1i64.p0(ptr %0)
+ %vld4.fca.0.extract = extractvalue { <1 x i64>, <1 x i64>, <1 x i64>, <1 x i64> } %vld4, 0
+ %shuffle.i = shufflevector <1 x i64> %vld4.fca.0.extract, <1 x i64> zeroinitializer, <2 x i32> <i32 0, i32 1>
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 32
+ store ptr %add.ptr, ptr %a, align 8
+ ret <2 x i64> %shuffle.i
+}
+
+; Tests for non-zero dsub extracts
+
+define <4 x i32> @ld4_u32_val1(ptr %a) {
+; CHECK-LABEL: ld4_u32_val1:
+; CHECK: ld4 { v0.2s, v1.2s, v2.2s, v3.2s }, [x0]
+; CHECK-NEXT: fmov d0, d1
+; CHECK-NEXT: ret
+entry:
+ %vld4 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld4.v2i32.p0(ptr %a)
+ %vld4.fca.0.extract = extractvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } %vld4, 1
+ %shuffle.i = shufflevector <2 x i32> %vld4.fca.0.extract, <2 x i32> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ ret <4 x i32> %shuffle.i
+}
+
+define <4 x i32> @ld4_u32_val2(ptr %a) {
+; CHECK-LABEL: ld4_u32_val2:
+; CHECK: ld4 { v0.2s, v1.2s, v2.2s, v3.2s }, [x0]
+; CHECK-NEXT: fmov d0, d2
+; CHECK-NEXT: ret
+entry:
+ %vld4 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld4.v2i32.p0(ptr %a)
+ %vld4.fca.0.extract = extractvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } %vld4, 2
+ %shuffle.i = shufflevector <2 x i32> %vld4.fca.0.extract, <2 x i32> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ ret <4 x i32> %shuffle.i
+}
+
+
+define <4 x i32> @ld4_u32_val3(ptr %a) {
+; CHECK-LABEL: ld4_u32_val3:
+; CHECK: ld4 { v0.2s, v1.2s, v2.2s, v3.2s }, [x0]
+; CHECK-NEXT: fmov d0, d3
+; CHECK-NEXT: ret
+entry:
+ %vld4 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld4.v2i32.p0(ptr %a)
+ %vld4.fca.0.extract = extractvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } %vld4, 3
+ %shuffle.i = shufflevector <2 x i32> %vld4.fca.0.extract, <2 x i32> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ ret <4 x i32> %shuffle.i
+}
+
+declare { <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld2.v8i8.p0(ptr)
+declare { <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld2.v4i16.p0(ptr)
+declare { <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld2.v2i32.p0(ptr)
+declare { <1 x i64>, <1 x i64> } @llvm.aarch64.neon.ld2.v1i64.p0(ptr)
+declare { <8 x i8>, <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld3.v8i8.p0(ptr)
+declare { <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld3.v4i16.p0(ptr)
+declare { <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld3.v2i32.p0(ptr)
+declare { <1 x i64>, <1 x i64>, <1 x i64> } @llvm.aarch64.neon.ld3.v1i64.p0(ptr)
+declare { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld4.v8i8.p0(ptr)
+declare { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld4.v4i16.p0(ptr)
+declare { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld4.v2i32.p0(ptr)
+declare { <1 x i64>, <1 x i64>, <1 x i64>, <1 x i64> } @llvm.aarch64.neon.ld4.v1i64.p0(ptr)
+
>From 65b45f6f201bd6f3e22282b7e28e57a44040883c Mon Sep 17 00:00:00 2001
From: Kieran Bailey <kieran.bailey at arm.com>
Date: Mon, 17 Aug 2026 15:20:42 +0000
Subject: [PATCH 2/3] Update test checks after peephole change
---
.../CodeGen/AArch64/ld-tuple-dsub-fmov.ll | 33 ++-----------------
1 file changed, 3 insertions(+), 30 deletions(-)
diff --git a/llvm/test/CodeGen/AArch64/ld-tuple-dsub-fmov.ll b/llvm/test/CodeGen/AArch64/ld-tuple-dsub-fmov.ll
index a501c1c7f51eb..159f28e11e28d 100644
--- a/llvm/test/CodeGen/AArch64/ld-tuple-dsub-fmov.ll
+++ b/llvm/test/CodeGen/AArch64/ld-tuple-dsub-fmov.ll
@@ -12,7 +12,6 @@ target triple = "aarch64-unknown-linux-gnu"
define <16 x i8> @ld2_u8_val0(ptr %a) {
; CHECK-LABEL: ld2_u8_val0:
; CHECK: ld2 { v0.8b, v1.8b }, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%vld2 = call { <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld2.v8i8.p0(ptr %a)
@@ -26,7 +25,6 @@ define <16 x i8> @ld2_u8_val0_post(ptr %a) {
; CHECK: ldr x8, [x0]
; CHECK-NEXT: ld2 { v0.8b, v1.8b }, [x8], #16
; CHECK-NEXT: str x8, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%0 = load ptr, ptr %a, align 8
@@ -41,7 +39,6 @@ entry:
define <8 x i16> @ld2_u16_val0(ptr %a) {
; CHECK-LABEL: ld2_u16_val0:
; CHECK: ld2 { v0.4h, v1.4h }, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%vld2 = call { <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld2.v4i16.p0(ptr %a)
@@ -56,7 +53,6 @@ define <8 x i16> @ld2_u16_val0_post(ptr %a) {
; CHECK: ldr x8, [x0]
; CHECK-NEXT: ld2 { v0.4h, v1.4h }, [x8], #16
; CHECK-NEXT: str x8, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%0 = load ptr, ptr %a, align 8
@@ -71,7 +67,6 @@ entry:
define <4 x i32> @ld2_u32_val0(ptr %a) {
; CHECK-LABEL: ld2_u32_val0:
; CHECK: ld2 { v0.2s, v1.2s }, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%vld2 = call { <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld2.v2i32.p0(ptr %a)
@@ -86,7 +81,6 @@ define <4 x i32> @ld2_u32_val0_post(ptr %a) {
; CHECK: ldr x8, [x0]
; CHECK-NEXT: ld2 { v0.2s, v1.2s }, [x8], #16
; CHECK-NEXT: str x8, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%0 = load ptr, ptr %a, align 8
@@ -102,7 +96,6 @@ define <2 x i64> @ld2_u64_val0(ptr %a) {
;
; CHECK-LABEL: ld2_u64_val0:
; CHECK: ld1 { v0.1d, v1.1d }, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%vld2 = call { <1 x i64>, <1 x i64> } @llvm.aarch64.neon.ld2.v1i64.p0(ptr %a)
@@ -118,7 +111,6 @@ define <2 x i64> @ld2_u64_val0_post(ptr %a) {
; CHECK: ldr x8, [x0]
; CHECK-NEXT: ld1 { v0.1d, v1.1d }, [x8], #16
; CHECK-NEXT: str x8, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%0 = load ptr, ptr %a, align 8
@@ -133,7 +125,6 @@ entry:
define <16 x i8> @ld3_u8_val0(ptr %a) {
; CHECK-LABEL: ld3_u8_val0:
; CHECK: ld3 { v0.8b, v1.8b, v2.8b }, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%vld3 = call { <8 x i8>, <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld3.v8i8.p0(ptr %a)
@@ -149,7 +140,6 @@ define <16 x i8> @ld3_u8_val0_post(ptr %a) {
; CHECK: ldr x8, [x0]
; CHECK-NEXT: ld3 { v0.8b, v1.8b, v2.8b }, [x8], #24
; CHECK-NEXT: str x8, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%0 = load ptr, ptr %a, align 8
@@ -164,7 +154,6 @@ entry:
define <8 x i16> @ld3_u16_val0(ptr %a) {
; CHECK-LABEL: ld3_u16_val0:
; CHECK: ld3 { v0.4h, v1.4h, v2.4h }, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%vld3 = call { <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld3.v4i16.p0(ptr %a)
@@ -180,7 +169,6 @@ define <8 x i16> @ld3_u16_val0_post(ptr %a) {
; CHECK: ldr x8, [x0]
; CHECK-NEXT: ld3 { v0.4h, v1.4h, v2.4h }, [x8], #24
; CHECK-NEXT: str x8, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%0 = load ptr, ptr %a, align 8
@@ -195,7 +183,6 @@ entry:
define <4 x i32> @ld3_u32_val0(ptr %a) {
; CHECK-LABEL: ld3_u32_val0:
; CHECK: ld3 { v0.2s, v1.2s, v2.2s }, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%vld3 = call { <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld3.v2i32.p0(ptr %a)
@@ -211,7 +198,6 @@ define <4 x i32> @ld3_u32_val0_post(ptr %a) {
; CHECK: ldr x8, [x0]
; CHECK-NEXT: ld3 { v0.2s, v1.2s, v2.2s }, [x8], #24
; CHECK-NEXT: str x8, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%0 = load ptr, ptr %a, align 8
@@ -227,7 +213,6 @@ define <2 x i64> @ld3_u64_val0(ptr %a) {
;
; CHECK-LABEL: ld3_u64_val0:
; CHECK: ld1 { v0.1d, v1.1d, v2.1d }, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%vld3 = call { <1 x i64>, <1 x i64>, <1 x i64> } @llvm.aarch64.neon.ld3.v1i64.p0(ptr %a)
@@ -243,7 +228,6 @@ define <2 x i64> @ld3_u64_val0_post(ptr %a) {
; CHECK: ldr x8, [x0]
; CHECK-NEXT: ld1 { v0.1d, v1.1d, v2.1d }, [x8], #24
; CHECK-NEXT: str x8, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%0 = load ptr, ptr %a, align 8
@@ -258,7 +242,6 @@ entry:
define <16 x i8> @ld4_u8_val0(ptr %a) {
; CHECK-LABEL: ld4_u8_val0:
; CHECK: ld4 { v0.8b, v1.8b, v2.8b, v3.8b }, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%vld4 = call { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld4.v8i8.p0(ptr %a)
@@ -274,7 +257,6 @@ define <16 x i8> @ld4_u8_val0_post(ptr %a) {
; CHECK: ldr x8, [x0]
; CHECK-NEXT: ld4 { v0.8b, v1.8b, v2.8b, v3.8b }, [x8], #32
; CHECK-NEXT: str x8, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%0 = load ptr, ptr %a, align 8
@@ -289,7 +271,6 @@ entry:
define <8 x i16> @ld4_u16_val0(ptr %a) {
; CHECK-LABEL: ld4_u16_val0:
; CHECK: ld4 { v0.4h, v1.4h, v2.4h, v3.4h }, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%vld4 = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld4.v4i16.p0(ptr %a)
@@ -305,7 +286,6 @@ define <8 x i16> @ld4_u16_val0_post(ptr %a) {
; CHECK: ldr x8, [x0]
; CHECK-NEXT: ld4 { v0.4h, v1.4h, v2.4h, v3.4h }, [x8], #32
; CHECK-NEXT: str x8, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%0 = load ptr, ptr %a, align 8
@@ -320,7 +300,6 @@ entry:
define <4 x i32> @ld4_u32_val0(ptr %a) {
; CHECK-LABEL: ld4_u32_val0:
; CHECK: ld4 { v0.2s, v1.2s, v2.2s, v3.2s }, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%vld4 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld4.v2i32.p0(ptr %a)
@@ -336,7 +315,6 @@ define <4 x i32> @ld4_u32_val0_post(ptr %a) {
; CHECK: ldr x8, [x0]
; CHECK-NEXT: ld4 { v0.2s, v1.2s, v2.2s, v3.2s }, [x8], #32
; CHECK-NEXT: str x8, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%0 = load ptr, ptr %a, align 8
@@ -352,7 +330,6 @@ define <2 x i64> @ld4_u64_val0(ptr %a) {
;
; CHECK-LABEL: ld4_u64_val0:
; CHECK: ld1 { v0.1d, v1.1d, v2.1d, v3.1d }, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%vld4 = call { <1 x i64>, <1 x i64>, <1 x i64>, <1 x i64> } @llvm.aarch64.neon.ld4.v1i64.p0(ptr %a)
@@ -368,7 +345,6 @@ define <2 x i64> @ld4_u64_val0_post(ptr %a) {
; CHECK: ldr x8, [x0]
; CHECK-NEXT: ld1 { v0.1d, v1.1d, v2.1d, v3.1d }, [x8], #32
; CHECK-NEXT: str x8, [x0]
-; CHECK-NEXT: fmov d0, d0
; CHECK-NEXT: ret
entry:
%0 = load ptr, ptr %a, align 8
@@ -384,8 +360,7 @@ entry:
define <4 x i32> @ld4_u32_val1(ptr %a) {
; CHECK-LABEL: ld4_u32_val1:
-; CHECK: ld4 { v0.2s, v1.2s, v2.2s, v3.2s }, [x0]
-; CHECK-NEXT: fmov d0, d1
+; CHECK: ld4 { v31.2s, v0.2s, v1.2s, v2.2s }, [x0]
; CHECK-NEXT: ret
entry:
%vld4 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld4.v2i32.p0(ptr %a)
@@ -396,8 +371,7 @@ entry:
define <4 x i32> @ld4_u32_val2(ptr %a) {
; CHECK-LABEL: ld4_u32_val2:
-; CHECK: ld4 { v0.2s, v1.2s, v2.2s, v3.2s }, [x0]
-; CHECK-NEXT: fmov d0, d2
+; CHECK: ld4 { v30.2s, v31.2s, v0.2s, v1.2s }, [x0]
; CHECK-NEXT: ret
entry:
%vld4 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld4.v2i32.p0(ptr %a)
@@ -409,8 +383,7 @@ entry:
define <4 x i32> @ld4_u32_val3(ptr %a) {
; CHECK-LABEL: ld4_u32_val3:
-; CHECK: ld4 { v0.2s, v1.2s, v2.2s, v3.2s }, [x0]
-; CHECK-NEXT: fmov d0, d3
+; CHECK: ld4 { v29.2s, v30.2s, v31.2s, v0.2s }, [x0]
; CHECK-NEXT: ret
entry:
%vld4 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld4.v2i32.p0(ptr %a)
>From 743feec1f2ad171637f8999f08714e90cf8c251f Mon Sep 17 00:00:00 2001
From: Kieran Bailey <kieran.bailey at arm.com>
Date: Tue, 25 Aug 2026 08:50:13 +0000
Subject: [PATCH 3/3] Changed large switch opcode statement for checks to
ensure we have a real D reg tuple load and upper bit zeroing behaviour. Add
more D reg tuple test coverage to test file.
---
.../Target/AArch64/AArch64MIPeepholeOpt.cpp | 47 +--
.../CodeGen/AArch64/ld-tuple-dsub-fmov.ll | 287 ++++++++++++++++--
2 files changed, 281 insertions(+), 53 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64MIPeepholeOpt.cpp b/llvm/lib/Target/AArch64/AArch64MIPeepholeOpt.cpp
index 1638314e18a26..417c8d4ba73ee 100644
--- a/llvm/lib/Target/AArch64/AArch64MIPeepholeOpt.cpp
+++ b/llvm/lib/Target/AArch64/AArch64MIPeepholeOpt.cpp
@@ -700,37 +700,6 @@ bool AArch64MIPeepholeOptImpl::visitINSviGPR(MachineInstr &MI, unsigned Opc) {
return true;
}
-static bool isZeroingDRegLoadOpcode(unsigned int Op) {
- switch (Op) {
- case AArch64::LD1Twov1d:
- case AArch64::LD1Twov1d_POST:
- case AArch64::LD1Threev1d:
- case AArch64::LD1Threev1d_POST:
- case AArch64::LD1Fourv1d:
- case AArch64::LD1Fourv1d_POST:
- case AArch64::LD2Twov8b:
- case AArch64::LD2Twov8b_POST:
- case AArch64::LD2Twov4h:
- case AArch64::LD2Twov4h_POST:
- case AArch64::LD2Twov2s:
- case AArch64::LD2Twov2s_POST:
- case AArch64::LD3Threev8b:
- case AArch64::LD3Threev8b_POST:
- case AArch64::LD3Threev4h:
- case AArch64::LD3Threev4h_POST:
- case AArch64::LD3Threev2s:
- case AArch64::LD3Threev2s_POST:
- case AArch64::LD4Fourv8b:
- case AArch64::LD4Fourv8b_POST:
- case AArch64::LD4Fourv4h:
- case AArch64::LD4Fourv4h_POST:
- case AArch64::LD4Fourv2s:
- case AArch64::LD4Fourv2s_POST:
- return true;
- }
- return false;
-}
-
// All instructions that set a FPR64 will implicitly zero the top bits of the
// register. When the def is expressed as a COPY from a GPR, turn it into an
// explicit FMOV so it cannot be elided later in further passes.
@@ -748,14 +717,20 @@ static bool is64bitDefwithZeroHigh64bit(MachineInstr *MI,
return false;
Register SrcReg = SrcOp.getReg();
if (SrcOp.getSubReg()) {
- // If operand is defined by a LD1/2/3/4 that define a D subreg
- // Then upper bits are implicitly zeroed and fmov is unneeded
- if (!SrcReg.isVirtual()) {
+ // If operand is defined by a LD1/2/3/4 that define a D subreg tuple
+ // then upper bits of the tuple's registers are implicitly zeroed
+ // and the FMOV is unneeded.
+ if (!SrcReg.isVirtual())
return false;
- }
MachineInstr *SrcDef = MRI->getUniqueVRegDef(SrcReg);
- return SrcDef && isZeroingDRegLoadOpcode(SrcDef->getOpcode());
+ if (!SrcDef || SrcDef->getOpcode() <= TargetOpcode::GENERIC_OP_END ||
+ SrcDef->getDesc().isPseudo() || !SrcDef->mayLoad())
+ return false;
+
+ const TargetRegisterClass *RC = MRI->getRegClass(SrcReg);
+ return RC == &AArch64::DDRegClass || RC == &AArch64::DDDRegClass ||
+ RC == &AArch64::DDDDRegClass;
}
auto IsGPR64Like = [&]() -> bool {
if (SrcReg.isVirtual())
diff --git a/llvm/test/CodeGen/AArch64/ld-tuple-dsub-fmov.ll b/llvm/test/CodeGen/AArch64/ld-tuple-dsub-fmov.ll
index 159f28e11e28d..e28cd664076e1 100644
--- a/llvm/test/CodeGen/AArch64/ld-tuple-dsub-fmov.ll
+++ b/llvm/test/CodeGen/AArch64/ld-tuple-dsub-fmov.ll
@@ -3,12 +3,267 @@
target triple = "aarch64-unknown-linux-gnu"
-; Tests the codegen for the following code.
-; The D register resulting 'ld2/3/4' instruction implicitly zeroes the upper bits so we can return straight after it.
+; The D register resulting 'ld1/2/3/4' instruction implicitly
+; zeroes the upper bits so we can return straight after it,
+; avoiding an extra FMOV.
+;
+; Tests the codegen for the following code:
+;
; uint8x16_t foo(uint8_t *a) {
; return vcombine_u8(vld2_u8(a).val[0], vdup_n_u8(0));
; }
+; Tests for vcombine(vld1_x2(p).val[0], dup(0))
+
+define <16 x i8> @ld1_two_v8b(ptr %p) {
+; CHECK-LABEL: ld1_two_v8b:
+; CHECK: ld1 { v0.8b, v1.8b }, [x0]
+; CHECK-NEXT: ret
+entry:
+ %vld1x2 = call { <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld1x2.v8i8.p0(ptr %p)
+ %vld1x2.extract = extractvalue { <8 x i8>, <8 x i8> } %vld1x2, 0
+ %shuffle.i = shufflevector <8 x i8> %vld1x2.extract, <8 x i8> zeroinitializer, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ ret <16 x i8> %shuffle.i
+}
+
+define <16 x i8> @ld1_two_v8b_post(ptr %p) {
+; CHECK-LABEL: ld1_two_v8b_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld1 { v0.8b, v1.8b }, [x8], #16
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %p, align 8
+ %vld1x2 = call { <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld1x2.v8i8.p0(ptr %0)
+ %vld1x2.extract = extractvalue { <8 x i8>, <8 x i8> } %vld1x2, 0
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 16
+ store ptr %add.ptr, ptr %p, align 8
+ %shuffle.i = shufflevector <8 x i8> %vld1x2.extract, <8 x i8> zeroinitializer, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ ret <16 x i8> %shuffle.i
+}
+
+define <8 x i16> @ld1_two_v4h(ptr %p) {
+; CHECK-LABEL: ld1_two_v4h:
+; CHECK: ld1 { v0.4h, v1.4h }, [x0]
+; CHECK-NEXT: ret
+entry:
+ %vld1x2 = call { <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld1x2.v4i16.p0(ptr %p)
+ %vld1x2.extract = extractvalue { <4 x i16>, <4 x i16> } %vld1x2, 0
+ %shuffle.i = shufflevector <4 x i16> %vld1x2.extract, <4 x i16> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ ret <8 x i16> %shuffle.i
+}
+
+define <8 x i16> @ld1_two_v4h_post(ptr %p) {
+; CHECK-LABEL: ld1_two_v4h_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld1 { v0.4h, v1.4h }, [x8], #16
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %p, align 8
+ %vld1x2 = call { <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld1x2.v4i16.p0(ptr %0)
+ %vld1x2.extract = extractvalue { <4 x i16>, <4 x i16> } %vld1x2, 0
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 16
+ store ptr %add.ptr, ptr %p, align 8
+ %shuffle.i = shufflevector <4 x i16> %vld1x2.extract, <4 x i16> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ ret <8 x i16> %shuffle.i
+}
+
+define <4 x i32> @ld1_two_v2s(ptr %p) {
+; CHECK-LABEL: ld1_two_v2s:
+; CHECK: ld1 { v0.2s, v1.2s }, [x0]
+; CHECK-NEXT: ret
+entry:
+ %vld1x2 = call { <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld1x2.v2i32.p0(ptr %p)
+ %vld1x2.extract = extractvalue { <2 x i32>, <2 x i32> } %vld1x2, 0
+ %shuffle.i = shufflevector <2 x i32> %vld1x2.extract, <2 x i32> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ ret <4 x i32> %shuffle.i
+}
+
+define <4 x i32> @ld1_two_v2s_post(ptr %p) {
+; CHECK-LABEL: ld1_two_v2s_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld1 { v0.2s, v1.2s }, [x8], #16
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %p, align 8
+ %vld1x2 = call { <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld1x2.v2i32.p0(ptr %0)
+ %vld1x2.extract = extractvalue { <2 x i32>, <2 x i32> } %vld1x2, 0
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 16
+ store ptr %add.ptr, ptr %p, align 8
+ %shuffle.i = shufflevector <2 x i32> %vld1x2.extract, <2 x i32> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ ret <4 x i32> %shuffle.i
+}
+
+; Tests for vcombine(vld1_x3(p).val[0], dup(0))
+
+define <16 x i8> @ld1_three_v8b(ptr %p) {
+; CHECK-LABEL: ld1_three_v8b:
+; CHECK: ld1 { v0.8b, v1.8b, v2.8b }, [x0]
+; CHECK-NEXT: ret
+entry:
+ %vld1x3 = call { <8 x i8>, <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld1x3.v8i8.p0(ptr %p)
+ %vld1x3.extract = extractvalue { <8 x i8>, <8 x i8>, <8 x i8> } %vld1x3, 0
+ %shuffle.i = shufflevector <8 x i8> %vld1x3.extract, <8 x i8> zeroinitializer, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ ret <16 x i8> %shuffle.i
+}
+
+define <16 x i8> @ld1_three_v8b_post(ptr %p) {
+; CHECK-LABEL: ld1_three_v8b_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld1 { v0.8b, v1.8b, v2.8b }, [x8], #24
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %p, align 8
+ %vld1x3 = call { <8 x i8>, <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld1x3.v8i8.p0(ptr %0)
+ %vld1x3.extract = extractvalue { <8 x i8>, <8 x i8>, <8 x i8> } %vld1x3, 0
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 24
+ store ptr %add.ptr, ptr %p, align 8
+ %shuffle.i = shufflevector <8 x i8> %vld1x3.extract, <8 x i8> zeroinitializer, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ ret <16 x i8> %shuffle.i
+}
+
+define <8 x i16> @ld1_three_v4h(ptr %p) {
+; CHECK-LABEL: ld1_three_v4h:
+; CHECK: ld1 { v0.4h, v1.4h, v2.4h }, [x0]
+; CHECK-NEXT: ret
+entry:
+ %vld1x3 = call { <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld1x3.v4i16.p0(ptr %p)
+ %vld1x3.extract = extractvalue { <4 x i16>, <4 x i16>, <4 x i16> } %vld1x3, 0
+ %shuffle.i = shufflevector <4 x i16> %vld1x3.extract, <4 x i16> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ ret <8 x i16> %shuffle.i
+}
+
+define <8 x i16> @ld1_three_v4h_post(ptr %p) {
+; CHECK-LABEL: ld1_three_v4h_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld1 { v0.4h, v1.4h, v2.4h }, [x8], #24
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %p, align 8
+ %vld1x3 = call { <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld1x3.v4i16.p0(ptr %0)
+ %vld1x3.extract = extractvalue { <4 x i16>, <4 x i16>, <4 x i16> } %vld1x3, 0
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 24
+ store ptr %add.ptr, ptr %p, align 8
+ %shuffle.i = shufflevector <4 x i16> %vld1x3.extract, <4 x i16> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ ret <8 x i16> %shuffle.i
+}
+
+define <4 x i32> @ld1_three_v2s(ptr %p) {
+; CHECK-LABEL: ld1_three_v2s:
+; CHECK: ld1 { v0.2s, v1.2s, v2.2s }, [x0]
+; CHECK-NEXT: ret
+entry:
+ %vld1x3 = call { <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld1x3.v2i32.p0(ptr %p)
+ %vld1x3.extract = extractvalue { <2 x i32>, <2 x i32>, <2 x i32> } %vld1x3, 0
+ %shuffle.i = shufflevector <2 x i32> %vld1x3.extract, <2 x i32> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ ret <4 x i32> %shuffle.i
+}
+
+define <4 x i32> @ld1_three_v2s_post(ptr %p) {
+; CHECK-LABEL: ld1_three_v2s_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld1 { v0.2s, v1.2s, v2.2s }, [x8], #24
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %p, align 8
+ %vld1x3 = call { <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld1x3.v2i32.p0(ptr %0)
+ %vld1x3.extract = extractvalue { <2 x i32>, <2 x i32>, <2 x i32> } %vld1x3, 0
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 24
+ store ptr %add.ptr, ptr %p, align 8
+ %shuffle.i = shufflevector <2 x i32> %vld1x3.extract, <2 x i32> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ ret <4 x i32> %shuffle.i
+}
+
+; Tests for vcombine(vld1_x4(p).val[0], dup(0))
+
+define <16 x i8> @ld1_four_v8b(ptr %p) {
+; CHECK-LABEL: ld1_four_v8b:
+; CHECK: ld1 { v0.8b, v1.8b, v2.8b, v3.8b }, [x0]
+; CHECK-NEXT: ret
+entry:
+ %vld1x4 = call { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld1x4.v8i8.p0(ptr %p)
+ %vld1x4.extract = extractvalue { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } %vld1x4, 0
+ %shuffle.i = shufflevector <8 x i8> %vld1x4.extract, <8 x i8> zeroinitializer, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ ret <16 x i8> %shuffle.i
+}
+
+define <16 x i8> @ld1_four_v8b_post(ptr %p) {
+; CHECK-LABEL: ld1_four_v8b_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld1 { v0.8b, v1.8b, v2.8b, v3.8b }, [x8], #32
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %p, align 8
+ %vld1x4 = call { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld1x4.v8i8.p0(ptr %0)
+ %vld1x4.extract = extractvalue { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } %vld1x4, 0
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 32
+ store ptr %add.ptr, ptr %p, align 8
+ %shuffle.i = shufflevector <8 x i8> %vld1x4.extract, <8 x i8> zeroinitializer, <16 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
+ ret <16 x i8> %shuffle.i
+}
+
+define <8 x i16> @ld1_four_v4h(ptr %p) {
+; CHECK-LABEL: ld1_four_v4h:
+; CHECK: ld1 { v0.4h, v1.4h, v2.4h, v3.4h }, [x0]
+; CHECK-NEXT: ret
+entry:
+ %vld1x4 = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld1x4.v4i16.p0(ptr %p)
+ %vld1x4.extract = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } %vld1x4, 0
+ %shuffle.i = shufflevector <4 x i16> %vld1x4.extract, <4 x i16> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ ret <8 x i16> %shuffle.i
+}
+
+define <8 x i16> @ld1_four_v4h_post(ptr %p) {
+; CHECK-LABEL: ld1_four_v4h_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld1 { v0.4h, v1.4h, v2.4h, v3.4h }, [x8], #32
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %p, align 8
+ %vld1x4 = call { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld1x4.v4i16.p0(ptr %0)
+ %vld1x4.extract = extractvalue { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } %vld1x4, 0
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 32
+ store ptr %add.ptr, ptr %p, align 8
+ %shuffle.i = shufflevector <4 x i16> %vld1x4.extract, <4 x i16> zeroinitializer, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
+ ret <8 x i16> %shuffle.i
+}
+
+define <4 x i32> @ld1_four_v2s(ptr %p) {
+; CHECK-LABEL: ld1_four_v2s:
+; CHECK: ld1 { v0.2s, v1.2s, v2.2s, v3.2s }, [x0]
+; CHECK-NEXT: ret
+entry:
+ %vld1x4 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld1x4.v2i32.p0(ptr %p)
+ %vld1x4.extract = extractvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } %vld1x4, 0
+ %shuffle.i = shufflevector <2 x i32> %vld1x4.extract, <2 x i32> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ ret <4 x i32> %shuffle.i
+}
+
+define <4 x i32> @ld1_four_v2s_post(ptr %p) {
+; CHECK-LABEL: ld1_four_v2s_post:
+; CHECK: ldr x8, [x0]
+; CHECK-NEXT: ld1 { v0.2s, v1.2s, v2.2s, v3.2s }, [x8], #32
+; CHECK-NEXT: str x8, [x0]
+; CHECK-NEXT: ret
+entry:
+ %0 = load ptr, ptr %p, align 8
+ %vld1x4 = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld1x4.v2i32.p0(ptr %0)
+ %vld1x4.extract = extractvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } %vld1x4, 0
+ %add.ptr = getelementptr inbounds nuw i8, ptr %0, i64 32
+ store ptr %add.ptr, ptr %p, align 8
+ %shuffle.i = shufflevector <2 x i32> %vld1x4.extract, <2 x i32> zeroinitializer, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
+ ret <4 x i32> %shuffle.i
+}
+
+; Tests for vcombine(vld2(p).val[0], dup(0))
+
define <16 x i8> @ld2_u8_val0(ptr %a) {
; CHECK-LABEL: ld2_u8_val0:
; CHECK: ld2 { v0.8b, v1.8b }, [x0]
@@ -47,7 +302,6 @@ entry:
ret <8 x i16> %shuffle.i
}
-
define <8 x i16> @ld2_u16_val0_post(ptr %a) {
; CHECK-LABEL: ld2_u16_val0_post:
; CHECK: ldr x8, [x0]
@@ -75,7 +329,6 @@ entry:
ret <4 x i32> %shuffle.i
}
-
define <4 x i32> @ld2_u32_val0_post(ptr %a) {
; CHECK-LABEL: ld2_u32_val0_post:
; CHECK: ldr x8, [x0]
@@ -93,7 +346,6 @@ entry:
}
define <2 x i64> @ld2_u64_val0(ptr %a) {
-;
; CHECK-LABEL: ld2_u64_val0:
; CHECK: ld1 { v0.1d, v1.1d }, [x0]
; CHECK-NEXT: ret
@@ -104,9 +356,7 @@ entry:
ret <2 x i64> %shuffle.i
}
-
define <2 x i64> @ld2_u64_val0_post(ptr %a) {
-;
; CHECK-LABEL: ld2_u64_val0_post:
; CHECK: ldr x8, [x0]
; CHECK-NEXT: ld1 { v0.1d, v1.1d }, [x8], #16
@@ -122,6 +372,8 @@ entry:
ret <2 x i64> %shuffle.i
}
+; Tests for vcombine(vld3(p).val[0], dup(0))
+
define <16 x i8> @ld3_u8_val0(ptr %a) {
; CHECK-LABEL: ld3_u8_val0:
; CHECK: ld3 { v0.8b, v1.8b, v2.8b }, [x0]
@@ -133,7 +385,6 @@ entry:
ret <16 x i8> %shuffle.i
}
-
define <16 x i8> @ld3_u8_val0_post(ptr %a) {
;
; CHECK-LABEL: ld3_u8_val0_post:
@@ -162,7 +413,6 @@ entry:
ret <8 x i16> %shuffle.i
}
-
define <8 x i16> @ld3_u16_val0_post(ptr %a) {
;
; CHECK-LABEL: ld3_u16_val0_post:
@@ -191,7 +441,6 @@ entry:
ret <4 x i32> %shuffle.i
}
-
define <4 x i32> @ld3_u32_val0_post(ptr %a) {
;
; CHECK-LABEL: ld3_u32_val0_post:
@@ -221,7 +470,6 @@ entry:
ret <2 x i64> %shuffle.i
}
-
define <2 x i64> @ld3_u64_val0_post(ptr %a) {
;
; CHECK-LABEL: ld3_u64_val0_post:
@@ -239,6 +487,8 @@ entry:
ret <2 x i64> %shuffle.i
}
+; Tests for vcombine(vld4(p).val[0], dup(0))
+
define <16 x i8> @ld4_u8_val0(ptr %a) {
; CHECK-LABEL: ld4_u8_val0:
; CHECK: ld4 { v0.8b, v1.8b, v2.8b, v3.8b }, [x0]
@@ -250,7 +500,6 @@ entry:
ret <16 x i8> %shuffle.i
}
-
define <16 x i8> @ld4_u8_val0_post(ptr %a) {
;
; CHECK-LABEL: ld4_u8_val0_post:
@@ -279,7 +528,6 @@ entry:
ret <8 x i16> %shuffle.i
}
-
define <8 x i16> @ld4_u16_val0_post(ptr %a) {
;
; CHECK-LABEL: ld4_u16_val0_post:
@@ -308,7 +556,6 @@ entry:
ret <4 x i32> %shuffle.i
}
-
define <4 x i32> @ld4_u32_val0_post(ptr %a) {
;
; CHECK-LABEL: ld4_u32_val0_post:
@@ -338,7 +585,6 @@ entry:
ret <2 x i64> %shuffle.i
}
-
define <2 x i64> @ld4_u64_val0_post(ptr %a) {
;
; CHECK-LABEL: ld4_u64_val0_post:
@@ -380,7 +626,6 @@ entry:
ret <4 x i32> %shuffle.i
}
-
define <4 x i32> @ld4_u32_val3(ptr %a) {
; CHECK-LABEL: ld4_u32_val3:
; CHECK: ld4 { v29.2s, v30.2s, v31.2s, v0.2s }, [x0]
@@ -392,6 +637,15 @@ entry:
ret <4 x i32> %shuffle.i
}
+declare { <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld1x2.v8i8.p0(ptr)
+declare { <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld1x2.v4i16.p0(ptr)
+declare { <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld1x2.v2i32.p0(ptr)
+declare { <8 x i8>, <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld1x3.v8i8.p0(ptr)
+declare { <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld1x3.v4i16.p0(ptr)
+declare { <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld1x3.v2i32.p0(ptr)
+declare { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld1x4.v8i8.p0(ptr)
+declare { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld1x4.v4i16.p0(ptr)
+declare { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld1x4.v2i32.p0(ptr)
declare { <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld2.v8i8.p0(ptr)
declare { <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld2.v4i16.p0(ptr)
declare { <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld2.v2i32.p0(ptr)
@@ -404,4 +658,3 @@ declare { <8 x i8>, <8 x i8>, <8 x i8>, <8 x i8> } @llvm.aarch64.neon.ld4.v8i8.p
declare { <4 x i16>, <4 x i16>, <4 x i16>, <4 x i16> } @llvm.aarch64.neon.ld4.v4i16.p0(ptr)
declare { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.aarch64.neon.ld4.v2i32.p0(ptr)
declare { <1 x i64>, <1 x i64>, <1 x i64>, <1 x i64> } @llvm.aarch64.neon.ld4.v1i64.p0(ptr)
-
More information about the llvm-commits
mailing list