[llvm] [ARM] Add combine for vector_deinterleave load (PR #225747)
Kamlesh Kumar via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 29 03:47:37 PDT 2026
https://github.com/kamleshbhalui updated https://github.com/llvm/llvm-project/pull/225747
>From 0aec74bc4c8754e6c0154b253e762eb7467edf9c Mon Sep 17 00:00:00 2001
From: Kamlesh Kumar <kamlesh.kumar at arm.com>
Date: Wed, 23 Sep 2026 11:23:43 +0000
Subject: [PATCH 1/4] add test
---
.../CodeGen/ARM/vector-deinterleave-load.ll | 96 +++++++++++++++++++
1 file changed, 96 insertions(+)
create mode 100644 llvm/test/CodeGen/ARM/vector-deinterleave-load.ll
diff --git a/llvm/test/CodeGen/ARM/vector-deinterleave-load.ll b/llvm/test/CodeGen/ARM/vector-deinterleave-load.ll
new file mode 100644
index 0000000000000..590df93383cd1
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/vector-deinterleave-load.ll
@@ -0,0 +1,96 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=armv8-none-eabi -mattr=+neon < %s | FileCheck %s --check-prefixes=CHECK,CHECK-IAENABLED
+; RUN: llc -mtriple=armv8-none-eabi -mattr=+neon -lower-interleaved-accesses=false < %s | FileCheck %s --check-prefixes=CHECK,CHECK-IADISABLED
+
+define void @arm_vector_deinterleave_idx_ld2(ptr %src) {
+; CHECK-LABEL: arm_vector_deinterleave_idx_ld2:
+; CHECK: @ %bb.0: @ %entry
+; CHECK-NEXT: vld1.32 {d16, d17}, [r0:128]!
+; CHECK-NEXT: vld1.64 {d18, d19}, [r0:128]
+; CHECK-NEXT: vuzp.32 q8, q9
+; CHECK-NEXT: @ fake_use: $q8
+; CHECK-NEXT: @ fake_use: $q9
+; CHECK-NEXT: bx lr
+entry:
+ %load = load <8 x float>, ptr %src
+ %deinterleave = call { <4 x float>, <4 x float> } @llvm.vector.deinterleave2.v8f32(<8 x float> %load)
+ %f0 = extractvalue { <4 x float>, <4 x float> } %deinterleave, 0
+ %f1 = extractvalue { <4 x float>, <4 x float> } %deinterleave, 1
+ call void (...) @llvm.fake.use(<4 x float> %f0)
+ call void (...) @llvm.fake.use(<4 x float> %f1)
+ ret void
+}
+
+define void @arm_vector_deinterleave_idx_ld3(ptr %src) {
+; CHECK-LABEL: arm_vector_deinterleave_idx_ld3:
+; CHECK: @ %bb.0: @ %entry
+; CHECK-NEXT: .save {r11}
+; CHECK-NEXT: push {r11}
+; CHECK-NEXT: .setfp r11, sp
+; CHECK-NEXT: mov r11, sp
+; CHECK-NEXT: .pad #60
+; CHECK-NEXT: sub sp, sp, #60
+; CHECK-NEXT: bfc sp, #0, #4
+; CHECK-NEXT: vld1.32 {d16, d17}, [r0:128]!
+; CHECK-NEXT: mov r1, sp
+; CHECK-NEXT: vld1.32 {d18, d19}, [r0:128]!
+; CHECK-NEXT: vld1.64 {d20, d21}, [r0:128]
+; CHECK-NEXT: add r0, r1, #32
+; CHECK-NEXT: vst1.64 {d20, d21}, [r0:128]
+; CHECK-NEXT: mov r0, r1
+; CHECK-NEXT: vst1.64 {d16, d17}, [r0:128]!
+; CHECK-NEXT: vst1.64 {d18, d19}, [r0]
+; CHECK-NEXT: vld3.32 {d16, d18, d20}, [r1:64]!
+; CHECK-NEXT: vld3.32 {d17, d19, d21}, [r1:64]
+; CHECK-NEXT: @ fake_use: $q8
+; CHECK-NEXT: @ fake_use: $q9
+; CHECK-NEXT: @ fake_use: $q10 $q8_q9_q10_q11
+; CHECK-NEXT: mov sp, r11
+; CHECK-NEXT: pop {r11}
+; CHECK-NEXT: bx lr
+entry:
+ %load = load <12 x float>, ptr %src
+ %deinterleave = call { <4 x float>, <4 x float>, <4 x float> } @llvm.vector.deinterleave3.v12f32(<12 x float> %load)
+ %f0 = extractvalue { <4 x float>, <4 x float>, <4 x float> } %deinterleave, 0
+ %f1 = extractvalue { <4 x float>, <4 x float>, <4 x float> } %deinterleave, 1
+ %f2 = extractvalue { <4 x float>, <4 x float>, <4 x float> } %deinterleave, 2
+
+ call void (...) @llvm.fake.use(<4 x float> %f0)
+ call void (...) @llvm.fake.use(<4 x float> %f1)
+ call void (...) @llvm.fake.use(<4 x float> %f2)
+ ret void
+}
+
+define void @arm_vector_deinterleave_idx_ld4(ptr %src) {
+; CHECK-LABEL: arm_vector_deinterleave_idx_ld4:
+; CHECK: @ %bb.0: @ %entry
+; CHECK-NEXT: vld1.32 {d16, d17}, [r0:128]!
+; CHECK-NEXT: vld1.32 {d18, d19}, [r0:128]!
+; CHECK-NEXT: vld1.32 {d20, d21}, [r0:128]!
+; CHECK-NEXT: vld1.64 {d22, d23}, [r0:128]
+; CHECK-NEXT: vuzp.32 q8, q9
+; CHECK-NEXT: vuzp.32 q10, q11
+; CHECK-NEXT: vuzp.32 q8, q10
+; CHECK-NEXT: @ fake_use: $q8
+; CHECK-NEXT: @ fake_use: $q10
+; CHECK-NEXT: vuzp.32 q9, q11
+; CHECK-NEXT: @ fake_use: $q9
+; CHECK-NEXT: @ fake_use: $q11
+; CHECK-NEXT: bx lr
+entry:
+ %load = load <16 x float>, ptr %src
+ %deinterleave = call { <4 x float>, <4 x float>, <4 x float>, <4 x float> } @llvm.vector.deinterleave4.v16f32(<16 x float> %load)
+ %f0 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %deinterleave, 0
+ %f1 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %deinterleave, 1
+ %f2 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %deinterleave, 2
+ %f3 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %deinterleave, 3
+
+ call void (...) @llvm.fake.use(<4 x float> %f0)
+ call void (...) @llvm.fake.use(<4 x float> %f1)
+ call void (...) @llvm.fake.use(<4 x float> %f2)
+ call void (...) @llvm.fake.use(<4 x float> %f3)
+ ret void
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
+; CHECK-IADISABLED: {{.*}}
+; CHECK-IAENABLED: {{.*}}
>From 4ac7fddc7d2d681e60935f3b1a02ac3b62136ae2 Mon Sep 17 00:00:00 2001
From: Kamlesh Kumar <kamlesh.kumar at arm.com>
Date: Wed, 23 Sep 2026 11:26:03 +0000
Subject: [PATCH 2/4] [ARM] Add combine for vector_deinterleave
If vector_deinterleave operands are coming from
load it can be combined to form ldN instruction.
For Wider load type legalizer create multiple vector_deinterleave
nodes, if those operands are from contigous load then form ldN.
---
llvm/lib/Target/ARM/ARMISelLowering.cpp | 146 +++++++++++++++++-
.../CodeGen/ARM/vector-deinterleave-load.ll | 36 +----
2 files changed, 150 insertions(+), 32 deletions(-)
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 194b597bc77ba..8dca29d4fc90d 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -821,8 +821,8 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM_,
if (Subtarget->hasNEON() || Subtarget->hasMVEIntegerOps()) {
setTargetDAGCombine(
- {ISD::BUILD_VECTOR, ISD::VECTOR_SHUFFLE, ISD::INSERT_SUBVECTOR,
- ISD::INSERT_VECTOR_ELT, ISD::EXTRACT_VECTOR_ELT,
+ {ISD::BUILD_VECTOR, ISD::VECTOR_SHUFFLE, ISD::VECTOR_DEINTERLEAVE,
+ ISD::INSERT_SUBVECTOR, ISD::INSERT_VECTOR_ELT, ISD::EXTRACT_VECTOR_ELT,
ISD::SIGN_EXTEND_INREG, ISD::STORE, ISD::SIGN_EXTEND, ISD::ZERO_EXTEND,
ISD::ANY_EXTEND, ISD::INTRINSIC_WO_CHAIN, ISD::INTRINSIC_W_CHAIN,
ISD::INTRINSIC_VOID, ISD::VECREDUCE_ADD, ISD::ADD, ISD::BITCAST});
@@ -15446,6 +15446,146 @@ static SDValue PerformBUILD_VECTORCombine(SDNode *N,
return DAG.getNode(ISD::BITCAST, dl, VT, BV);
}
+static SDValue performLegalizedVECTOR_DEINTERLEAVECombine(
+ SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG) {
+ // Type legalization splits a wide load into consecutive legal loads. Combine
+ // each group used by a legal VECTOR_DEINTERLEAVE into a structured load.
+ if (DCI.getDAGCombineLevel() < AfterLegalizeTypes)
+ return SDValue();
+
+ unsigned NumParts = N->getNumOperands();
+ if (NumParts < 2 || NumParts > 4)
+ return SDValue();
+
+ EVT SubVecTy = N->getValueType(0);
+ if (!SubVecTy.is64BitVector() && !SubVecTy.is128BitVector())
+ return SDValue();
+
+ SmallVector<LoadSDNode *, 4> Loads;
+ for (const SDValue &Operand : N->op_values()) {
+ auto *Load = dyn_cast<LoadSDNode>(Operand);
+ if (!Load || !Operand.hasOneUse())
+ return SDValue();
+ Loads.push_back(Load);
+ }
+
+ LoadSDNode *BaseLoad = Loads[0];
+ unsigned Bytes = SubVecTy.getStoreSize().getFixedValue();
+ for (auto [Idx, Load] : enumerate(Loads)) {
+ if (!DAG.areNonVolatileConsecutiveLoads(Load, BaseLoad, Bytes, Idx))
+ return SDValue();
+ }
+
+ static constexpr Intrinsic::ID NEONLoads[] = {Intrinsic::arm_neon_vld2,
+ Intrinsic::arm_neon_vld3,
+ Intrinsic::arm_neon_vld4};
+ SDLoc DL(N);
+ EVT MemVT =
+ EVT::getVectorVT(*DAG.getContext(), SubVecTy.getVectorElementType(),
+ SubVecTy.getVectorElementCount() * NumParts);
+ MachineFunction &MF = DAG.getMachineFunction();
+ MachineMemOperand *MMO =
+ MF.getMachineMemOperand(BaseLoad->getMemOperand(), 0, NumParts * Bytes);
+
+ SmallVector<EVT, 5> ResVTs(NumParts, SubVecTy);
+ ResVTs.push_back(MVT::Other);
+
+ // We can now generate a structured load!
+ SDValue NewLoad = DAG.getMemIntrinsicNode(
+ ISD::INTRINSIC_W_CHAIN, DL, DAG.getVTList(ResVTs),
+ {BaseLoad->getChain(),
+ DAG.getTargetConstant(NEONLoads[NumParts - 2], DL, MVT::i64),
+ BaseLoad->getBasePtr()},
+ MemVT, MMO);
+
+ SmallVector<SDValue, 4> ResOps;
+ for (unsigned I = 0; I != NumParts; ++I)
+ ResOps.push_back(NewLoad.getValue(I));
+
+ // Replace uses of the original chain result with the new chain result.
+ for (LoadSDNode *Load : Loads)
+ DAG.ReplaceAllUsesOfValueWith(SDValue(Load, 1), NewLoad.getValue(NumParts));
+
+ return DCI.CombineTo(N, ResOps, false);
+}
+
+// Combine a deinterleave of adjacent subvectors from one load into a
+// structured NEON load.
+static SDValue
+PerformVECTOR_DEINTERLEAVECombine(SDNode *N,
+ TargetLowering::DAGCombinerInfo &DCI,
+ const ARMSubtarget *Subtarget) {
+
+ if (!Subtarget->hasNEON())
+ return SDValue();
+
+ if (SDValue Res = performLegalizedVECTOR_DEINTERLEAVECombine(N, DCI, DCI.DAG))
+ return Res;
+
+ if (!DCI.isBeforeLegalize())
+ return SDValue();
+
+ SelectionDAG &DAG = DCI.DAG;
+ unsigned NumParts = N->getNumOperands();
+ if (NumParts != 2 && NumParts != 3 && NumParts != 4)
+ return SDValue();
+ EVT SubVecTy = N->getValueType(0);
+ const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+
+ if (!TLI.isTypeLegal(SubVecTy))
+ return SDValue();
+
+ unsigned SubVecBits = SubVecTy.getSizeInBits().getKnownMinValue();
+ if (SubVecBits != 64 && SubVecBits != 128) {
+ return SDValue();
+ }
+
+ // Make sure each input operand is the correct extract_subvector of the same
+ // wider vector.
+ unsigned MinNumElements = SubVecTy.getVectorMinNumElements();
+ SDValue Op0 = N->getOperand(0);
+ for (unsigned I = 0; I < NumParts; I++) {
+ SDValue OpI = N->getOperand(I);
+ if (OpI->getOpcode() != ISD::EXTRACT_SUBVECTOR ||
+ OpI->getOperand(0) != Op0->getOperand(0))
+ return SDValue();
+ if (OpI->getConstantOperandVal(1) != (I * MinNumElements))
+ return SDValue();
+ }
+
+ SDValue WideVec = Op0->getOperand(0);
+ SDLoc DL(N);
+
+ SmallVector<EVT, 5> ResVTs(NumParts, SubVecTy);
+ ResVTs.push_back(MVT::Other);
+ SDVTList ResVTList = DAG.getVTList(ResVTs);
+ auto *Load = dyn_cast<LoadSDNode>(WideVec);
+ if (!Load || !Load->hasNUsesOfValue(NumParts, 0) || !Load->isSimple() ||
+ !ISD::isNormalLoad(Load) || !Load->getOffset().isUndef())
+ return SDValue();
+
+ static constexpr Intrinsic::ID NEONLoads[] = {Intrinsic::arm_neon_vld2,
+ Intrinsic::arm_neon_vld3,
+ Intrinsic::arm_neon_vld4};
+ SDValue NewLdOps[] = {
+ Load->getChain(),
+ DAG.getTargetConstant(NEONLoads[NumParts - 2], DL, MVT::i64),
+ Load->getBasePtr()};
+ SDValue Res =
+ DAG.getMemIntrinsicNode(ISD::INTRINSIC_W_CHAIN, DL, ResVTList, NewLdOps,
+ Load->getMemoryVT(), Load->getMemOperand());
+
+ // We can now generate a structured load!
+ SmallVector<SDValue, 4> ResOps(NumParts);
+ for (unsigned Idx = 0; Idx < NumParts; Idx++)
+ ResOps[Idx] = SDValue(Res.getNode(), Idx);
+
+ // Replace uses of the original chain result with the new chain result.
+ DAG.ReplaceAllUsesOfValueWith(WideVec.getValue(1),
+ SDValue(Res.getNode(), NumParts));
+ return DCI.CombineTo(N, ResOps, false);
+}
+
/// Target-specific dag combine xforms for ARMISD::BUILD_VECTOR.
static SDValue
PerformARMBUILD_VECTORCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) {
@@ -19202,6 +19342,8 @@ SDValue ARMTargetLowering::PerformDAGCombine(SDNode *N,
return PerformCSETCombine(N, DCI.DAG);
case ISD::LOAD:
return PerformLOADCombine(N, DCI, Subtarget);
+ case ISD::VECTOR_DEINTERLEAVE:
+ return PerformVECTOR_DEINTERLEAVECombine(N, DCI, Subtarget);
case ARMISD::VLD1DUP:
case ARMISD::VLD2DUP:
case ARMISD::VLD3DUP:
diff --git a/llvm/test/CodeGen/ARM/vector-deinterleave-load.ll b/llvm/test/CodeGen/ARM/vector-deinterleave-load.ll
index 590df93383cd1..154d3df6aedd1 100644
--- a/llvm/test/CodeGen/ARM/vector-deinterleave-load.ll
+++ b/llvm/test/CodeGen/ARM/vector-deinterleave-load.ll
@@ -24,29 +24,11 @@ entry:
define void @arm_vector_deinterleave_idx_ld3(ptr %src) {
; CHECK-LABEL: arm_vector_deinterleave_idx_ld3:
; CHECK: @ %bb.0: @ %entry
-; CHECK-NEXT: .save {r11}
-; CHECK-NEXT: push {r11}
-; CHECK-NEXT: .setfp r11, sp
-; CHECK-NEXT: mov r11, sp
-; CHECK-NEXT: .pad #60
-; CHECK-NEXT: sub sp, sp, #60
-; CHECK-NEXT: bfc sp, #0, #4
-; CHECK-NEXT: vld1.32 {d16, d17}, [r0:128]!
-; CHECK-NEXT: mov r1, sp
-; CHECK-NEXT: vld1.32 {d18, d19}, [r0:128]!
-; CHECK-NEXT: vld1.64 {d20, d21}, [r0:128]
-; CHECK-NEXT: add r0, r1, #32
-; CHECK-NEXT: vst1.64 {d20, d21}, [r0:128]
-; CHECK-NEXT: mov r0, r1
-; CHECK-NEXT: vst1.64 {d16, d17}, [r0:128]!
-; CHECK-NEXT: vst1.64 {d18, d19}, [r0]
-; CHECK-NEXT: vld3.32 {d16, d18, d20}, [r1:64]!
-; CHECK-NEXT: vld3.32 {d17, d19, d21}, [r1:64]
+; CHECK-NEXT: vld3.32 {d16, d18, d20}, [r0:64]!
+; CHECK-NEXT: vld3.32 {d17, d19, d21}, [r0:64]
; CHECK-NEXT: @ fake_use: $q8
; CHECK-NEXT: @ fake_use: $q9
; CHECK-NEXT: @ fake_use: $q10 $q8_q9_q10_q11
-; CHECK-NEXT: mov sp, r11
-; CHECK-NEXT: pop {r11}
; CHECK-NEXT: bx lr
entry:
%load = load <12 x float>, ptr %src
@@ -64,18 +46,12 @@ entry:
define void @arm_vector_deinterleave_idx_ld4(ptr %src) {
; CHECK-LABEL: arm_vector_deinterleave_idx_ld4:
; CHECK: @ %bb.0: @ %entry
-; CHECK-NEXT: vld1.32 {d16, d17}, [r0:128]!
-; CHECK-NEXT: vld1.32 {d18, d19}, [r0:128]!
-; CHECK-NEXT: vld1.32 {d20, d21}, [r0:128]!
-; CHECK-NEXT: vld1.64 {d22, d23}, [r0:128]
-; CHECK-NEXT: vuzp.32 q8, q9
-; CHECK-NEXT: vuzp.32 q10, q11
-; CHECK-NEXT: vuzp.32 q8, q10
+; CHECK-NEXT: vld4.32 {d16, d18, d20, d22}, [r0:256]!
+; CHECK-NEXT: vld4.32 {d17, d19, d21, d23}, [r0:256]
; CHECK-NEXT: @ fake_use: $q8
-; CHECK-NEXT: @ fake_use: $q10
-; CHECK-NEXT: vuzp.32 q9, q11
; CHECK-NEXT: @ fake_use: $q9
-; CHECK-NEXT: @ fake_use: $q11
+; CHECK-NEXT: @ fake_use: $q10
+; CHECK-NEXT: @ fake_use: $q11 $q8_q9_q10_q11
; CHECK-NEXT: bx lr
entry:
%load = load <16 x float>, ptr %src
>From d23c475b10a11a86cb8cbbd0db8a570b52038007 Mon Sep 17 00:00:00 2001
From: Kamlesh Kumar <kamlesh.kumar at arm.com>
Date: Mon, 28 Sep 2026 17:24:17 +0100
Subject: [PATCH 3/4] added mve support and more tests
---
llvm/lib/Target/ARM/ARMISelLowering.cpp | 65 +++-
.../CodeGen/ARM/vector-deinterleave-load.ll | 351 +++++++++++++++++-
.../Thumb2/vector-deinterleave-load.ll | 190 ++++++++++
3 files changed, 585 insertions(+), 21 deletions(-)
create mode 100644 llvm/test/CodeGen/Thumb2/vector-deinterleave-load.ll
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index 8dca29d4fc90d..da6fd16dade2e 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -15447,7 +15447,8 @@ static SDValue PerformBUILD_VECTORCombine(SDNode *N,
}
static SDValue performLegalizedVECTOR_DEINTERLEAVECombine(
- SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG) {
+ SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG,
+ const ARMSubtarget *Subtarget) {
// Type legalization splits a wide load into consecutive legal loads. Combine
// each group used by a legal VECTOR_DEINTERLEAVE into a structured load.
if (DCI.getDAGCombineLevel() < AfterLegalizeTypes)
@@ -15457,9 +15458,15 @@ static SDValue performLegalizedVECTOR_DEINTERLEAVECombine(
if (NumParts < 2 || NumParts > 4)
return SDValue();
+ if (NumParts == 3 && !Subtarget->hasNEON())
+ return SDValue();
+
EVT SubVecTy = N->getValueType(0);
if (!SubVecTy.is64BitVector() && !SubVecTy.is128BitVector())
return SDValue();
+ unsigned EltBits = SubVecTy.getScalarSizeInBits();
+ if (EltBits != 8 && EltBits != 16 && EltBits != 32)
+ return SDValue();
SmallVector<LoadSDNode *, 4> Loads;
for (const SDValue &Operand : N->op_values()) {
@@ -15490,13 +15497,19 @@ static SDValue performLegalizedVECTOR_DEINTERLEAVECombine(
SmallVector<EVT, 5> ResVTs(NumParts, SubVecTy);
ResVTs.push_back(MVT::Other);
+ SmallVector<SDValue> NewLdOps;
+ NewLdOps.push_back(BaseLoad->getChain());
+ Intrinsic::ID IID = 0;
+ if (Subtarget->hasNEON())
+ IID = NEONLoads[NumParts - 2];
+ else
+ IID = NumParts == 2 ? Intrinsic::arm_mve_vld2q : Intrinsic::arm_mve_vld4q;
+
+ NewLdOps.push_back(DAG.getTargetConstant(IID, DL, MVT::i64));
+ NewLdOps.push_back(BaseLoad->getBasePtr());
// We can now generate a structured load!
SDValue NewLoad = DAG.getMemIntrinsicNode(
- ISD::INTRINSIC_W_CHAIN, DL, DAG.getVTList(ResVTs),
- {BaseLoad->getChain(),
- DAG.getTargetConstant(NEONLoads[NumParts - 2], DL, MVT::i64),
- BaseLoad->getBasePtr()},
- MemVT, MMO);
+ ISD::INTRINSIC_W_CHAIN, DL, DAG.getVTList(ResVTs), NewLdOps, MemVT, MMO);
SmallVector<SDValue, 4> ResOps;
for (unsigned I = 0; I != NumParts; ++I)
@@ -15515,11 +15528,8 @@ static SDValue
PerformVECTOR_DEINTERLEAVECombine(SDNode *N,
TargetLowering::DAGCombinerInfo &DCI,
const ARMSubtarget *Subtarget) {
-
- if (!Subtarget->hasNEON())
- return SDValue();
-
- if (SDValue Res = performLegalizedVECTOR_DEINTERLEAVECombine(N, DCI, DCI.DAG))
+ if (SDValue Res = performLegalizedVECTOR_DEINTERLEAVECombine(N, DCI, DCI.DAG,
+ Subtarget))
return Res;
if (!DCI.isBeforeLegalize())
@@ -15529,16 +15539,22 @@ PerformVECTOR_DEINTERLEAVECombine(SDNode *N,
unsigned NumParts = N->getNumOperands();
if (NumParts != 2 && NumParts != 3 && NumParts != 4)
return SDValue();
+
+ if (NumParts == 3 && !Subtarget->hasNEON())
+ return SDValue();
+
EVT SubVecTy = N->getValueType(0);
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
if (!TLI.isTypeLegal(SubVecTy))
return SDValue();
- unsigned SubVecBits = SubVecTy.getSizeInBits().getKnownMinValue();
- if (SubVecBits != 64 && SubVecBits != 128) {
+ if (!SubVecTy.is64BitVector() && !SubVecTy.is128BitVector())
+ return SDValue();
+
+ unsigned EltBits = SubVecTy.getScalarSizeInBits();
+ if (EltBits != 8 && EltBits != 16 && EltBits != 32)
return SDValue();
- }
// Make sure each input operand is the correct extract_subvector of the same
// wider vector.
@@ -15567,10 +15583,17 @@ PerformVECTOR_DEINTERLEAVECombine(SDNode *N,
static constexpr Intrinsic::ID NEONLoads[] = {Intrinsic::arm_neon_vld2,
Intrinsic::arm_neon_vld3,
Intrinsic::arm_neon_vld4};
- SDValue NewLdOps[] = {
- Load->getChain(),
- DAG.getTargetConstant(NEONLoads[NumParts - 2], DL, MVT::i64),
- Load->getBasePtr()};
+ SmallVector<SDValue> NewLdOps;
+ Intrinsic::ID IID = 0;
+ NewLdOps.push_back(Load->getChain());
+ if (Subtarget->hasNEON())
+ IID = NEONLoads[NumParts - 2];
+ else
+ IID = NumParts == 2 ? Intrinsic::arm_mve_vld2q : Intrinsic::arm_mve_vld4q;
+ NewLdOps.push_back(DAG.getTargetConstant(IID, DL, MVT::i64));
+
+ NewLdOps.push_back(Load->getBasePtr());
+
SDValue Res =
DAG.getMemIntrinsicNode(ISD::INTRINSIC_W_CHAIN, DL, ResVTList, NewLdOps,
Load->getMemoryVT(), Load->getMemOperand());
@@ -16853,7 +16876,11 @@ static SDValue PerformLOADCombine(SDNode *N,
TargetLowering::DAGCombinerInfo &DCI,
const ARMSubtarget *Subtarget) {
EVT VT = N->getValueType(0);
-
+ // Let the deinterleave combine form a structured load first.
+ if (DCI.getDAGCombineLevel() >= AfterLegalizeTypes && ISD::isNormalLoad(N))
+ for (SDUse &Use : N->uses())
+ if (Use.getUser()->getOpcode() == ISD::VECTOR_DEINTERLEAVE)
+ return SDValue();
// If this is a legal vector load, try to combine it into a VLD1_UPD.
if (Subtarget->hasNEON() && ISD::isNormalLoad(N) && VT.isVector() &&
DCI.DAG.getTargetLoweringInfo().isTypeLegal(VT))
diff --git a/llvm/test/CodeGen/ARM/vector-deinterleave-load.ll b/llvm/test/CodeGen/ARM/vector-deinterleave-load.ll
index 154d3df6aedd1..fc585e63f1c33 100644
--- a/llvm/test/CodeGen/ARM/vector-deinterleave-load.ll
+++ b/llvm/test/CodeGen/ARM/vector-deinterleave-load.ll
@@ -1,6 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
-; RUN: llc -mtriple=armv8-none-eabi -mattr=+neon < %s | FileCheck %s --check-prefixes=CHECK,CHECK-IAENABLED
-; RUN: llc -mtriple=armv8-none-eabi -mattr=+neon -lower-interleaved-accesses=false < %s | FileCheck %s --check-prefixes=CHECK,CHECK-IADISABLED
+; RUN: llc -mtriple=armv8-none-eabihf -mattr=+neon < %s | FileCheck %s --check-prefixes=CHECK,CHECK-IAENABLED
+; RUN: llc -mtriple=armv8-none-eabihf -mattr=+neon -lower-interleaved-accesses=false < %s | FileCheck %s --check-prefixes=CHECK,CHECK-IADISABLED
define void @arm_vector_deinterleave_idx_ld2(ptr %src) {
; CHECK-LABEL: arm_vector_deinterleave_idx_ld2:
@@ -67,6 +67,353 @@ entry:
call void (...) @llvm.fake.use(<4 x float> %f3)
ret void
}
+
+
+define void @factor2_v4i32(ptr %src) {
+; CHECK-LABEL: factor2_v4i32:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vld1.32 {d16, d17}, [r0:128]!
+; CHECK-NEXT: vld1.64 {d18, d19}, [r0:128]
+; CHECK-NEXT: vuzp.32 q8, q9
+; CHECK-NEXT: @ fake_use: $q8
+; CHECK-NEXT: @ fake_use: $q9
+; CHECK-NEXT: bx lr
+ %load = load <8 x i32>, ptr %src
+ %deinterleave = call { <4 x i32>, <4 x i32> } @llvm.vector.deinterleave2.v8i32(<8 x i32> %load)
+ %v0 = extractvalue { <4 x i32>, <4 x i32> } %deinterleave, 0
+ %v1 = extractvalue { <4 x i32>, <4 x i32> } %deinterleave, 1
+ call void (...) @llvm.fake.use(<4 x i32> %v0)
+ call void (...) @llvm.fake.use(<4 x i32> %v1)
+ ret void
+}
+
+define void @factor3_v2i32(ptr %src) {
+; CHECK-LABEL: factor3_v2i32:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vld3.32 {d16, d17, d18}, [r0:64]
+; CHECK-NEXT: @ fake_use: $d16
+; CHECK-NEXT: @ fake_use: $d17
+; CHECK-NEXT: @ fake_use: $d18 $q8_q9
+; CHECK-NEXT: bx lr
+ %load = load <6 x i32>, ptr %src
+ %deinterleave = call { <2 x i32>, <2 x i32>, <2 x i32> } @llvm.vector.deinterleave3.v6i32(<6 x i32> %load)
+ %v0 = extractvalue { <2 x i32>, <2 x i32>, <2 x i32> } %deinterleave, 0
+ %v1 = extractvalue { <2 x i32>, <2 x i32>, <2 x i32> } %deinterleave, 1
+ %v2 = extractvalue { <2 x i32>, <2 x i32>, <2 x i32> } %deinterleave, 2
+ call void (...) @llvm.fake.use(<2 x i32> %v0)
+ call void (...) @llvm.fake.use(<2 x i32> %v1)
+ call void (...) @llvm.fake.use(<2 x i32> %v2)
+ ret void
+}
+
+define void @factor3_v4i32(ptr %src) {
+; CHECK-LABEL: factor3_v4i32:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vld3.32 {d16, d18, d20}, [r0:64]!
+; CHECK-NEXT: vld3.32 {d17, d19, d21}, [r0:64]
+; CHECK-NEXT: @ fake_use: $q8
+; CHECK-NEXT: @ fake_use: $q9
+; CHECK-NEXT: @ fake_use: $q10 $q8_q9_q10_q11
+; CHECK-NEXT: bx lr
+ %load = load <12 x i32>, ptr %src
+ %deinterleave = call { <4 x i32>, <4 x i32>, <4 x i32> } @llvm.vector.deinterleave3.v12i32(<12 x i32> %load)
+ %v0 = extractvalue { <4 x i32>, <4 x i32>, <4 x i32> } %deinterleave, 0
+ %v1 = extractvalue { <4 x i32>, <4 x i32>, <4 x i32> } %deinterleave, 1
+ %v2 = extractvalue { <4 x i32>, <4 x i32>, <4 x i32> } %deinterleave, 2
+ call void (...) @llvm.fake.use(<4 x i32> %v0)
+ call void (...) @llvm.fake.use(<4 x i32> %v1)
+ call void (...) @llvm.fake.use(<4 x i32> %v2)
+ ret void
+}
+
+define void @factor3_v8i32(ptr %src) {
+; CHECK-LABEL: factor3_v8i32:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vld3.32 {d16, d18, d20}, [r0]!
+; CHECK-NEXT: vld3.32 {d17, d19, d21}, [r0]!
+; CHECK-NEXT: @ fake_use: $q8
+; CHECK-NEXT: @ fake_use: $q9
+; CHECK-NEXT: @ fake_use: $q10 $q8_q9_q10_q11
+; CHECK-NEXT: vld3.32 {d24, d26, d28}, [r0]!
+; CHECK-NEXT: vld3.32 {d25, d27, d29}, [r0]
+; CHECK-NEXT: @ fake_use: $q12
+; CHECK-NEXT: vorr q12, q13, q13
+; CHECK-NEXT: @ fake_use: $q12
+; CHECK-NEXT: vorr q0, q14, q14
+; CHECK-NEXT: @ fake_use: $q0
+; CHECK-NEXT: bx lr
+ %load = load <24 x i32>, ptr %src, align 4
+ %deinterleave = call { <8 x i32>, <8 x i32>, <8 x i32> } @llvm.vector.deinterleave3.v24i32(<24 x i32> %load)
+ %v0 = extractvalue { <8 x i32>, <8 x i32>, <8 x i32> } %deinterleave, 0
+ %v1 = extractvalue { <8 x i32>, <8 x i32>, <8 x i32> } %deinterleave, 1
+ %v2 = extractvalue { <8 x i32>, <8 x i32>, <8 x i32> } %deinterleave, 2
+ call void (...) @llvm.fake.use(<8 x i32> %v0)
+ call void (...) @llvm.fake.use(<8 x i32> %v1)
+ call void (...) @llvm.fake.use(<8 x i32> %v2)
+ ret void
+}
+
+define void @factor4_v2i32(ptr %src) {
+; CHECK-LABEL: factor4_v2i32:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vld4.32 {d16, d17, d18, d19}, [r0:256]
+; CHECK-NEXT: @ fake_use: $d16
+; CHECK-NEXT: @ fake_use: $d17
+; CHECK-NEXT: @ fake_use: $d18
+; CHECK-NEXT: @ fake_use: $d19 $q8_q9
+; CHECK-NEXT: bx lr
+ %load = load <8 x i32>, ptr %src
+ %deinterleave = call { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } @llvm.vector.deinterleave4.v8i32(<8 x i32> %load)
+ %v0 = extractvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } %deinterleave, 0
+ %v1 = extractvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } %deinterleave, 1
+ %v2 = extractvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } %deinterleave, 2
+ %v3 = extractvalue { <2 x i32>, <2 x i32>, <2 x i32>, <2 x i32> } %deinterleave, 3
+ call void (...) @llvm.fake.use(<2 x i32> %v0)
+ call void (...) @llvm.fake.use(<2 x i32> %v1)
+ call void (...) @llvm.fake.use(<2 x i32> %v2)
+ call void (...) @llvm.fake.use(<2 x i32> %v3)
+ ret void
+}
+
+define void @factor4_v4i32(ptr %src) {
+; CHECK-LABEL: factor4_v4i32:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vld4.32 {d16, d18, d20, d22}, [r0:256]!
+; CHECK-NEXT: vld4.32 {d17, d19, d21, d23}, [r0:256]
+; CHECK-NEXT: @ fake_use: $q8
+; CHECK-NEXT: @ fake_use: $q9
+; CHECK-NEXT: @ fake_use: $q10
+; CHECK-NEXT: @ fake_use: $q11 $q8_q9_q10_q11
+; CHECK-NEXT: bx lr
+ %load = load <16 x i32>, ptr %src
+ %deinterleave = call { <4 x i32>, <4 x i32>, <4 x i32>, <4 x i32> } @llvm.vector.deinterleave4.v16i32(<16 x i32> %load)
+ %v0 = extractvalue { <4 x i32>, <4 x i32>, <4 x i32>, <4 x i32> } %deinterleave, 0
+ %v1 = extractvalue { <4 x i32>, <4 x i32>, <4 x i32>, <4 x i32> } %deinterleave, 1
+ %v2 = extractvalue { <4 x i32>, <4 x i32>, <4 x i32>, <4 x i32> } %deinterleave, 2
+ %v3 = extractvalue { <4 x i32>, <4 x i32>, <4 x i32>, <4 x i32> } %deinterleave, 3
+ call void (...) @llvm.fake.use(<4 x i32> %v0)
+ call void (...) @llvm.fake.use(<4 x i32> %v1)
+ call void (...) @llvm.fake.use(<4 x i32> %v2)
+ call void (...) @llvm.fake.use(<4 x i32> %v3)
+ ret void
+}
+
+define void @factor4_v8i32(ptr %src) {
+; CHECK-LABEL: factor4_v8i32:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vld4.32 {d16, d18, d20, d22}, [r0:256]!
+; CHECK-NEXT: vld4.32 {d17, d19, d21, d23}, [r0:256]!
+; CHECK-NEXT: @ fake_use: $q8
+; CHECK-NEXT: @ fake_use: $q9
+; CHECK-NEXT: @ fake_use: $q10
+; CHECK-NEXT: @ fake_use: $q11 $q8_q9_q10_q11
+; CHECK-NEXT: vld4.32 {d24, d26, d28, d30}, [r0:256]!
+; CHECK-NEXT: vld4.32 {d25, d27, d29, d31}, [r0:256]
+; CHECK-NEXT: vorr q0, q12, q12
+; CHECK-NEXT: @ fake_use: $q0
+; CHECK-NEXT: vorr q0, q15, q15
+; CHECK-NEXT: @ fake_use: $q0
+; CHECK-NEXT: vorr q1, q14, q14
+; CHECK-NEXT: @ fake_use: $q1
+; CHECK-NEXT: vorr q12, q13, q13
+; CHECK-NEXT: @ fake_use: $q12
+; CHECK-NEXT: bx lr
+ %load = load <32 x i32>, ptr %src
+ %deinterleave = call { <8 x i32>, <8 x i32>, <8 x i32>, <8 x i32> } @llvm.vector.deinterleave4.v32i32(<32 x i32> %load)
+ %v0 = extractvalue { <8 x i32>, <8 x i32>, <8 x i32>, <8 x i32> } %deinterleave, 0
+ %v1 = extractvalue { <8 x i32>, <8 x i32>, <8 x i32>, <8 x i32> } %deinterleave, 1
+ %v2 = extractvalue { <8 x i32>, <8 x i32>, <8 x i32>, <8 x i32> } %deinterleave, 2
+ %v3 = extractvalue { <8 x i32>, <8 x i32>, <8 x i32>, <8 x i32> } %deinterleave, 3
+ call void (...) @llvm.fake.use(<8 x i32> %v0)
+ call void (...) @llvm.fake.use(<8 x i32> %v1)
+ call void (...) @llvm.fake.use(<8 x i32> %v2)
+ call void (...) @llvm.fake.use(<8 x i32> %v3)
+ ret void
+}
+
+define void @factor4_v16i8(ptr %src) {
+; CHECK-LABEL: factor4_v16i8:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vld4.8 {d16, d18, d20, d22}, [r0:256]!
+; CHECK-NEXT: vld4.8 {d17, d19, d21, d23}, [r0:256]
+; CHECK-NEXT: @ fake_use: $q8
+; CHECK-NEXT: @ fake_use: $q9
+; CHECK-NEXT: @ fake_use: $q10
+; CHECK-NEXT: @ fake_use: $q11 $q8_q9_q10_q11
+; CHECK-NEXT: bx lr
+ %load = load <64 x i8>, ptr %src
+ %deinterleave = call { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } @llvm.vector.deinterleave4.v64i8(<64 x i8> %load)
+ %v0 = extractvalue { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } %deinterleave, 0
+ %v1 = extractvalue { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } %deinterleave, 1
+ %v2 = extractvalue { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } %deinterleave, 2
+ %v3 = extractvalue { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } %deinterleave, 3
+ call void (...) @llvm.fake.use(<16 x i8> %v0)
+ call void (...) @llvm.fake.use(<16 x i8> %v1)
+ call void (...) @llvm.fake.use(<16 x i8> %v2)
+ call void (...) @llvm.fake.use(<16 x i8> %v3)
+ ret void
+}
+
+define void @factor4_v8i16(ptr %src) {
+; CHECK-LABEL: factor4_v8i16:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vld4.16 {d16, d18, d20, d22}, [r0:256]!
+; CHECK-NEXT: vld4.16 {d17, d19, d21, d23}, [r0:256]
+; CHECK-NEXT: @ fake_use: $q8
+; CHECK-NEXT: @ fake_use: $q9
+; CHECK-NEXT: @ fake_use: $q10
+; CHECK-NEXT: @ fake_use: $q11 $q8_q9_q10_q11
+; CHECK-NEXT: bx lr
+ %load = load <32 x i16>, ptr %src
+ %deinterleave = call { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave4.v32i16(<32 x i16> %load)
+ %v0 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 0
+ %v1 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 1
+ %v2 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 2
+ %v3 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 3
+ call void (...) @llvm.fake.use(<8 x i16> %v0)
+ call void (...) @llvm.fake.use(<8 x i16> %v1)
+ call void (...) @llvm.fake.use(<8 x i16> %v2)
+ call void (...) @llvm.fake.use(<8 x i16> %v3)
+ ret void
+}
+
+define void @factor4_v8f16(ptr %src) {
+; CHECK-LABEL: factor4_v8f16:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: .save {r4, r5, r6, r7, r11, lr}
+; CHECK-NEXT: push {r4, r5, r6, r7, r11, lr}
+; CHECK-NEXT: add r1, r0, #8
+; CHECK-NEXT: vld1.32 {d16[0]}, [r0]
+; CHECK-NEXT: vld1.32 {d17[0]}, [r1]
+; CHECK-NEXT: add r1, r0, #16
+; CHECK-NEXT: vld1.32 {d18[0]}, [r1]
+; CHECK-NEXT: add r1, r0, #24
+; CHECK-NEXT: vld1.32 {d19[0]}, [r1]
+; CHECK-NEXT: add r1, r0, #32
+; CHECK-NEXT: vld1.32 {d20[0]}, [r1]
+; CHECK-NEXT: add r1, r0, #40
+; CHECK-NEXT: vld1.32 {d21[0]}, [r1]
+; CHECK-NEXT: add r1, r0, #48
+; CHECK-NEXT: vld1.32 {d22[0]}, [r1]
+; CHECK-NEXT: add r1, r0, #4
+; CHECK-NEXT: vld1.32 {d16[1]}, [r1]
+; CHECK-NEXT: add r1, r0, #12
+; CHECK-NEXT: vld1.32 {d17[1]}, [r1]
+; CHECK-NEXT: add r1, r0, #56
+; CHECK-NEXT: vld1.32 {d23[0]}, [r1]
+; CHECK-NEXT: add r1, r0, #20
+; CHECK-NEXT: vld1.32 {d18[1]}, [r1]
+; CHECK-NEXT: add r1, r0, #28
+; CHECK-NEXT: vld1.32 {d19[1]}, [r1]
+; CHECK-NEXT: add r1, r0, #36
+; CHECK-NEXT: vld1.32 {d20[1]}, [r1]
+; CHECK-NEXT: add r1, r0, #44
+; CHECK-NEXT: vld1.32 {d21[1]}, [r1]
+; CHECK-NEXT: add r1, r0, #52
+; CHECK-NEXT: add r0, r0, #60
+; CHECK-NEXT: vld1.32 {d22[1]}, [r1]
+; CHECK-NEXT: vld1.32 {d23[1]}, [r0]
+; CHECK-NEXT: vmov.u16 r2, d16[0]
+; CHECK-NEXT: @ fake_use: $r2
+; CHECK-NEXT: vmov.u16 r3, d19[0]
+; CHECK-NEXT: @ fake_use: $r3
+; CHECK-NEXT: vmov.u16 r1, d20[0]
+; CHECK-NEXT: @ fake_use: $r1
+; CHECK-NEXT: vmov.u16 r4, d22[0]
+; CHECK-NEXT: @ fake_use: $r4
+; CHECK-NEXT: vmov.u16 r5, d23[0]
+; CHECK-NEXT: @ fake_use: $r5
+; CHECK-NEXT: vmov.u16 r12, d17[0]
+; CHECK-NEXT: @ fake_use: $r12
+; CHECK-NEXT: vmov.u16 r0, d18[0]
+; CHECK-NEXT: @ fake_use: $r0
+; CHECK-NEXT: vmov.u16 lr, d21[0]
+; CHECK-NEXT: @ fake_use: $lr
+; CHECK-NEXT: vmov.u16 r2, d16[1]
+; CHECK-NEXT: @ fake_use: $r2
+; CHECK-NEXT: vmov.u16 r3, d19[1]
+; CHECK-NEXT: @ fake_use: $r3
+; CHECK-NEXT: vmov.u16 r1, d20[1]
+; CHECK-NEXT: @ fake_use: $r1
+; CHECK-NEXT: vmov.u16 r4, d22[1]
+; CHECK-NEXT: @ fake_use: $r4
+; CHECK-NEXT: vmov.u16 r5, d23[1]
+; CHECK-NEXT: @ fake_use: $r5
+; CHECK-NEXT: vmov.u16 r12, d17[1]
+; CHECK-NEXT: @ fake_use: $r12
+; CHECK-NEXT: vmov.u16 r0, d18[1]
+; CHECK-NEXT: @ fake_use: $r0
+; CHECK-NEXT: vmov.u16 lr, d21[1]
+; CHECK-NEXT: @ fake_use: $lr
+; CHECK-NEXT: vmov.u16 r2, d16[2]
+; CHECK-NEXT: @ fake_use: $r2
+; CHECK-NEXT: vmov.u16 r6, d18[2]
+; CHECK-NEXT: @ fake_use: $r6
+; CHECK-NEXT: vmov.u16 r3, d19[2]
+; CHECK-NEXT: @ fake_use: $r3
+; CHECK-NEXT: vmov.u16 r1, d20[2]
+; CHECK-NEXT: @ fake_use: $r1
+; CHECK-NEXT: vmov.u16 r4, d22[2]
+; CHECK-NEXT: @ fake_use: $r4
+; CHECK-NEXT: vmov.u16 r5, d23[2]
+; CHECK-NEXT: @ fake_use: $r5
+; CHECK-NEXT: vmov.u16 r12, d17[2]
+; CHECK-NEXT: @ fake_use: $r12
+; CHECK-NEXT: vmov.u16 lr, d21[2]
+; CHECK-NEXT: @ fake_use: $lr
+; CHECK-NEXT: vmov.u16 r7, d16[3]
+; CHECK-NEXT: @ fake_use: $r7
+; CHECK-NEXT: vmov.u16 r0, d17[3]
+; CHECK-NEXT: @ fake_use: $r0
+; CHECK-NEXT: vmov.u16 r6, d18[3]
+; CHECK-NEXT: @ fake_use: $r6
+; CHECK-NEXT: vmov.u16 r3, d19[3]
+; CHECK-NEXT: @ fake_use: $r3
+; CHECK-NEXT: vmov.u16 r1, d20[3]
+; CHECK-NEXT: @ fake_use: $r1
+; CHECK-NEXT: vmov.u16 r2, d21[3]
+; CHECK-NEXT: @ fake_use: $r2
+; CHECK-NEXT: vmov.u16 r4, d22[3]
+; CHECK-NEXT: @ fake_use: $r4
+; CHECK-NEXT: vmov.u16 r5, d23[3]
+; CHECK-NEXT: @ fake_use: $r5
+; CHECK-NEXT: pop {r4, r5, r6, r7, r11, pc}
+ %load = load <32 x half>, ptr %src, align 2
+ %deinterleave = call { <8 x half>, <8 x half>, <8 x half>, <8 x half> } @llvm.vector.deinterleave4.v32f16(<32 x half> %load)
+ %v0 = extractvalue { <8 x half>, <8 x half>, <8 x half>, <8 x half> } %deinterleave, 0
+ %v1 = extractvalue { <8 x half>, <8 x half>, <8 x half>, <8 x half> } %deinterleave, 1
+ %v2 = extractvalue { <8 x half>, <8 x half>, <8 x half>, <8 x half> } %deinterleave, 2
+ %v3 = extractvalue { <8 x half>, <8 x half>, <8 x half>, <8 x half> } %deinterleave, 3
+ call void (...) @llvm.fake.use(<8 x half> %v0)
+ call void (...) @llvm.fake.use(<8 x half> %v1)
+ call void (...) @llvm.fake.use(<8 x half> %v2)
+ call void (...) @llvm.fake.use(<8 x half> %v3)
+ ret void
+}
+
+define void @factor4_v4f32(ptr %src) {
+; CHECK-LABEL: factor4_v4f32:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vld4.32 {d16, d18, d20, d22}, [r0]!
+; CHECK-NEXT: vld4.32 {d17, d19, d21, d23}, [r0]
+; CHECK-NEXT: @ fake_use: $q8
+; CHECK-NEXT: @ fake_use: $q9
+; CHECK-NEXT: @ fake_use: $q10
+; CHECK-NEXT: @ fake_use: $q11 $q8_q9_q10_q11
+; CHECK-NEXT: bx lr
+ %load = load <16 x float>, ptr %src, align 4
+ %deinterleave = call { <4 x float>, <4 x float>, <4 x float>, <4 x float> } @llvm.vector.deinterleave4.v16f32(<16 x float> %load)
+ %v0 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %deinterleave, 0
+ %v1 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %deinterleave, 1
+ %v2 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %deinterleave, 2
+ %v3 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %deinterleave, 3
+ call void (...) @llvm.fake.use(<4 x float> %v0)
+ call void (...) @llvm.fake.use(<4 x float> %v1)
+ call void (...) @llvm.fake.use(<4 x float> %v2)
+ call void (...) @llvm.fake.use(<4 x float> %v3)
+ ret void
+}
+
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CHECK-IADISABLED: {{.*}}
; CHECK-IAENABLED: {{.*}}
diff --git a/llvm/test/CodeGen/Thumb2/vector-deinterleave-load.ll b/llvm/test/CodeGen/Thumb2/vector-deinterleave-load.ll
new file mode 100644
index 0000000000000..6353171b5bae8
--- /dev/null
+++ b/llvm/test/CodeGen/Thumb2/vector-deinterleave-load.ll
@@ -0,0 +1,190 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=thumbv8.1m.main-none-none-eabihf -mattr=+mve,+mve.fp < %s | FileCheck %s
+; RUN: llc -mtriple=thumbv8.1m.main-none-none-eabihf -mattr=+mve,+mve.fp -lower-interleaved-accesses=false < %s | FileCheck %s
+
+define void @factor2_v4i32(ptr %src) {
+; CHECK-LABEL: factor2_v4i32:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vldrw.u32 q0, [r0, #16]
+; CHECK-NEXT: vldrw.u32 q1, [r0]
+; CHECK-NEXT: vmov.f32 s8, s5
+; CHECK-NEXT: vmov.f32 s9, s7
+; CHECK-NEXT: vmov.f32 s5, s6
+; CHECK-NEXT: vmov.f32 s10, s1
+; CHECK-NEXT: vmov.f32 s11, s3
+; CHECK-NEXT: @ fake_use: $q2
+; CHECK-NEXT: vmov.f32 s6, s0
+; CHECK-NEXT: vmov.f32 s7, s2
+; CHECK-NEXT: @ fake_use: $q1
+; CHECK-NEXT: bx lr
+ %load = load <8 x i32>, ptr %src
+ %deinterleave = call { <4 x i32>, <4 x i32> } @llvm.vector.deinterleave2.v8i32(<8 x i32> %load)
+ %v0 = extractvalue { <4 x i32>, <4 x i32> } %deinterleave, 0
+ %v1 = extractvalue { <4 x i32>, <4 x i32> } %deinterleave, 1
+ call void (...) @llvm.fake.use(<4 x i32> %v0)
+ call void (...) @llvm.fake.use(<4 x i32> %v1)
+ ret void
+}
+
+define void @factor4_v16i8(ptr %src) {
+; CHECK-LABEL: factor4_v16i8:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vld40.8 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: vld41.8 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: vld42.8 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: vld43.8 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: @ fake_use: $q0
+; CHECK-NEXT: @ fake_use: $q1
+; CHECK-NEXT: @ fake_use: $q2
+; CHECK-NEXT: @ fake_use: $q3
+; CHECK-NEXT: bx lr
+ %load = load <64 x i8>, ptr %src
+ %deinterleave = call { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } @llvm.vector.deinterleave4.v64i8(<64 x i8> %load)
+ %v0 = extractvalue { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } %deinterleave, 0
+ %v1 = extractvalue { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } %deinterleave, 1
+ %v2 = extractvalue { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } %deinterleave, 2
+ %v3 = extractvalue { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } %deinterleave, 3
+ call void (...) @llvm.fake.use(<16 x i8> %v0)
+ call void (...) @llvm.fake.use(<16 x i8> %v1)
+ call void (...) @llvm.fake.use(<16 x i8> %v2)
+ call void (...) @llvm.fake.use(<16 x i8> %v3)
+ ret void
+}
+
+define void @factor4_v8i16(ptr %src) {
+; CHECK-LABEL: factor4_v8i16:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vld40.16 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: vld41.16 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: vld42.16 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: vld43.16 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: @ fake_use: $q0
+; CHECK-NEXT: @ fake_use: $q1
+; CHECK-NEXT: @ fake_use: $q2
+; CHECK-NEXT: @ fake_use: $q3
+; CHECK-NEXT: bx lr
+ %load = load <32 x i16>, ptr %src
+ %deinterleave = call { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } @llvm.vector.deinterleave4.v32i16(<32 x i16> %load)
+ %v0 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 0
+ %v1 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 1
+ %v2 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 2
+ %v3 = extractvalue { <8 x i16>, <8 x i16>, <8 x i16>, <8 x i16> } %deinterleave, 3
+ call void (...) @llvm.fake.use(<8 x i16> %v0)
+ call void (...) @llvm.fake.use(<8 x i16> %v1)
+ call void (...) @llvm.fake.use(<8 x i16> %v2)
+ call void (...) @llvm.fake.use(<8 x i16> %v3)
+ ret void
+}
+
+define void @factor4_v8f16(ptr %src) {
+; CHECK-LABEL: factor4_v8f16:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vld40.16 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: vld41.16 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: vld42.16 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: vld43.16 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: @ fake_use: $q0
+; CHECK-NEXT: @ fake_use: $q1
+; CHECK-NEXT: vmov q0, q2
+; CHECK-NEXT: @ fake_use: $q0
+; CHECK-NEXT: vmov q0, q3
+; CHECK-NEXT: @ fake_use: $q0
+; CHECK-NEXT: bx lr
+ %load = load <32 x half>, ptr %src
+ %deinterleave = call { <8 x half>, <8 x half>, <8 x half>, <8 x half> } @llvm.vector.deinterleave4.v32f16(<32 x half> %load)
+ %v0 = extractvalue { <8 x half>, <8 x half>, <8 x half>, <8 x half> } %deinterleave, 0
+ %v1 = extractvalue { <8 x half>, <8 x half>, <8 x half>, <8 x half> } %deinterleave, 1
+ %v2 = extractvalue { <8 x half>, <8 x half>, <8 x half>, <8 x half> } %deinterleave, 2
+ %v3 = extractvalue { <8 x half>, <8 x half>, <8 x half>, <8 x half> } %deinterleave, 3
+ call void (...) @llvm.fake.use(<8 x half> %v0)
+ call void (...) @llvm.fake.use(<8 x half> %v1)
+ call void (...) @llvm.fake.use(<8 x half> %v2)
+ call void (...) @llvm.fake.use(<8 x half> %v3)
+ ret void
+}
+
+define void @factor4_v4f32(ptr %src) {
+; CHECK-LABEL: factor4_v4f32:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vld40.32 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: vld41.32 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: vld42.32 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: vld43.32 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: @ fake_use: $q0
+; CHECK-NEXT: @ fake_use: $q1
+; CHECK-NEXT: @ fake_use: $q2
+; CHECK-NEXT: @ fake_use: $q3
+; CHECK-NEXT: bx lr
+ %load = load <16 x float>, ptr %src
+ %deinterleave = call { <4 x float>, <4 x float>, <4 x float>, <4 x float> } @llvm.vector.deinterleave4.v16f32(<16 x float> %load)
+ %v0 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %deinterleave, 0
+ %v1 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %deinterleave, 1
+ %v2 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %deinterleave, 2
+ %v3 = extractvalue { <4 x float>, <4 x float>, <4 x float>, <4 x float> } %deinterleave, 3
+ call void (...) @llvm.fake.use(<4 x float> %v0)
+ call void (...) @llvm.fake.use(<4 x float> %v1)
+ call void (...) @llvm.fake.use(<4 x float> %v2)
+ call void (...) @llvm.fake.use(<4 x float> %v3)
+ ret void
+}
+
+define void @factor4_v8i32(ptr %src) {
+; CHECK-LABEL: factor4_v8i32:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: .vsave {d8, d9, d10, d11, d12, d13, d14, d15}
+; CHECK-NEXT: vpush {d8, d9, d10, d11, d12, d13, d14, d15}
+; CHECK-NEXT: vld40.32 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: vld41.32 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: vld42.32 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: vld43.32 {q0, q1, q2, q3}, [r0]!
+; CHECK-NEXT: @ fake_use: $q0
+; CHECK-NEXT: @ fake_use: $q1
+; CHECK-NEXT: @ fake_use: $q2
+; CHECK-NEXT: vld40.32 {q4, q5, q6, q7}, [r0]
+; CHECK-NEXT: @ fake_use: $q3
+; CHECK-NEXT: vld41.32 {q4, q5, q6, q7}, [r0]
+; CHECK-NEXT: vld42.32 {q4, q5, q6, q7}, [r0]
+; CHECK-NEXT: vld43.32 {q4, q5, q6, q7}, [r0]
+; CHECK-NEXT: @ fake_use: $q4
+; CHECK-NEXT: @ fake_use: $q5
+; CHECK-NEXT: @ fake_use: $q6
+; CHECK-NEXT: @ fake_use: $q7
+; CHECK-NEXT: vpop {d8, d9, d10, d11, d12, d13, d14, d15}
+; CHECK-NEXT: bx lr
+ %load = load <32 x i32>, ptr %src
+ %deinterleave = call { <8 x i32>, <8 x i32>, <8 x i32>, <8 x i32> } @llvm.vector.deinterleave4.v32i32(<32 x i32> %load)
+ %v0 = extractvalue { <8 x i32>, <8 x i32>, <8 x i32>, <8 x i32> } %deinterleave, 0
+ %v1 = extractvalue { <8 x i32>, <8 x i32>, <8 x i32>, <8 x i32> } %deinterleave, 1
+ %v2 = extractvalue { <8 x i32>, <8 x i32>, <8 x i32>, <8 x i32> } %deinterleave, 2
+ %v3 = extractvalue { <8 x i32>, <8 x i32>, <8 x i32>, <8 x i32> } %deinterleave, 3
+ call void (...) @llvm.fake.use(<8 x i32> %v0)
+ call void (...) @llvm.fake.use(<8 x i32> %v1)
+ call void (...) @llvm.fake.use(<8 x i32> %v2)
+ call void (...) @llvm.fake.use(<8 x i32> %v3)
+ ret void
+}
+
+define void @factor4_v4i32(ptr %src) {
+; CHECK-LABEL: factor4_v4i32:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: vld40.32 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: vld41.32 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: vld42.32 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: vld43.32 {q0, q1, q2, q3}, [r0]
+; CHECK-NEXT: @ fake_use: $q0
+; CHECK-NEXT: @ fake_use: $q1
+; CHECK-NEXT: @ fake_use: $q2
+; CHECK-NEXT: @ fake_use: $q3
+; CHECK-NEXT: bx lr
+ %load = load <16 x i32>, ptr %src
+ %deinterleave = call { <4 x i32>, <4 x i32>, <4 x i32>, <4 x i32> } @llvm.vector.deinterleave4.v16i32(<16 x i32> %load)
+ %v0 = extractvalue { <4 x i32>, <4 x i32>, <4 x i32>, <4 x i32> } %deinterleave, 0
+ %v1 = extractvalue { <4 x i32>, <4 x i32>, <4 x i32>, <4 x i32> } %deinterleave, 1
+ %v2 = extractvalue { <4 x i32>, <4 x i32>, <4 x i32>, <4 x i32> } %deinterleave, 2
+ %v3 = extractvalue { <4 x i32>, <4 x i32>, <4 x i32>, <4 x i32> } %deinterleave, 3
+ call void (...) @llvm.fake.use(<4 x i32> %v0)
+ call void (...) @llvm.fake.use(<4 x i32> %v1)
+ call void (...) @llvm.fake.use(<4 x i32> %v2)
+ call void (...) @llvm.fake.use(<4 x i32> %v3)
+ ret void
+}
>From 1a5b40b05390893ff1cbbd507f1093f895032db5 Mon Sep 17 00:00:00 2001
From: Kamlesh Kumar <kamlesh.kumar at arm.com>
Date: Tue, 29 Sep 2026 11:47:16 +0100
Subject: [PATCH 4/4] add fp16 attribute
---
.../CodeGen/ARM/vector-deinterleave-load.ll | 109 ++----------------
1 file changed, 9 insertions(+), 100 deletions(-)
diff --git a/llvm/test/CodeGen/ARM/vector-deinterleave-load.ll b/llvm/test/CodeGen/ARM/vector-deinterleave-load.ll
index fc585e63f1c33..035346f2df2a5 100644
--- a/llvm/test/CodeGen/ARM/vector-deinterleave-load.ll
+++ b/llvm/test/CodeGen/ARM/vector-deinterleave-load.ll
@@ -1,6 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
-; RUN: llc -mtriple=armv8-none-eabihf -mattr=+neon < %s | FileCheck %s --check-prefixes=CHECK,CHECK-IAENABLED
-; RUN: llc -mtriple=armv8-none-eabihf -mattr=+neon -lower-interleaved-accesses=false < %s | FileCheck %s --check-prefixes=CHECK,CHECK-IADISABLED
+; RUN: llc -mtriple=armv8-none-eabihf -mattr=+neon,+fullfp16 < %s | FileCheck %s --check-prefixes=CHECK,CHECK-IAENABLED
+; RUN: llc -mtriple=armv8-none-eabihf -mattr=+neon,+fullfp16 -lower-interleaved-accesses=false < %s | FileCheck %s --check-prefixes=CHECK,CHECK-IADISABLED
define void @arm_vector_deinterleave_idx_ld2(ptr %src) {
; CHECK-LABEL: arm_vector_deinterleave_idx_ld2:
@@ -280,104 +280,13 @@ define void @factor4_v8i16(ptr %src) {
define void @factor4_v8f16(ptr %src) {
; CHECK-LABEL: factor4_v8f16:
; CHECK: @ %bb.0:
-; CHECK-NEXT: .save {r4, r5, r6, r7, r11, lr}
-; CHECK-NEXT: push {r4, r5, r6, r7, r11, lr}
-; CHECK-NEXT: add r1, r0, #8
-; CHECK-NEXT: vld1.32 {d16[0]}, [r0]
-; CHECK-NEXT: vld1.32 {d17[0]}, [r1]
-; CHECK-NEXT: add r1, r0, #16
-; CHECK-NEXT: vld1.32 {d18[0]}, [r1]
-; CHECK-NEXT: add r1, r0, #24
-; CHECK-NEXT: vld1.32 {d19[0]}, [r1]
-; CHECK-NEXT: add r1, r0, #32
-; CHECK-NEXT: vld1.32 {d20[0]}, [r1]
-; CHECK-NEXT: add r1, r0, #40
-; CHECK-NEXT: vld1.32 {d21[0]}, [r1]
-; CHECK-NEXT: add r1, r0, #48
-; CHECK-NEXT: vld1.32 {d22[0]}, [r1]
-; CHECK-NEXT: add r1, r0, #4
-; CHECK-NEXT: vld1.32 {d16[1]}, [r1]
-; CHECK-NEXT: add r1, r0, #12
-; CHECK-NEXT: vld1.32 {d17[1]}, [r1]
-; CHECK-NEXT: add r1, r0, #56
-; CHECK-NEXT: vld1.32 {d23[0]}, [r1]
-; CHECK-NEXT: add r1, r0, #20
-; CHECK-NEXT: vld1.32 {d18[1]}, [r1]
-; CHECK-NEXT: add r1, r0, #28
-; CHECK-NEXT: vld1.32 {d19[1]}, [r1]
-; CHECK-NEXT: add r1, r0, #36
-; CHECK-NEXT: vld1.32 {d20[1]}, [r1]
-; CHECK-NEXT: add r1, r0, #44
-; CHECK-NEXT: vld1.32 {d21[1]}, [r1]
-; CHECK-NEXT: add r1, r0, #52
-; CHECK-NEXT: add r0, r0, #60
-; CHECK-NEXT: vld1.32 {d22[1]}, [r1]
-; CHECK-NEXT: vld1.32 {d23[1]}, [r0]
-; CHECK-NEXT: vmov.u16 r2, d16[0]
-; CHECK-NEXT: @ fake_use: $r2
-; CHECK-NEXT: vmov.u16 r3, d19[0]
-; CHECK-NEXT: @ fake_use: $r3
-; CHECK-NEXT: vmov.u16 r1, d20[0]
-; CHECK-NEXT: @ fake_use: $r1
-; CHECK-NEXT: vmov.u16 r4, d22[0]
-; CHECK-NEXT: @ fake_use: $r4
-; CHECK-NEXT: vmov.u16 r5, d23[0]
-; CHECK-NEXT: @ fake_use: $r5
-; CHECK-NEXT: vmov.u16 r12, d17[0]
-; CHECK-NEXT: @ fake_use: $r12
-; CHECK-NEXT: vmov.u16 r0, d18[0]
-; CHECK-NEXT: @ fake_use: $r0
-; CHECK-NEXT: vmov.u16 lr, d21[0]
-; CHECK-NEXT: @ fake_use: $lr
-; CHECK-NEXT: vmov.u16 r2, d16[1]
-; CHECK-NEXT: @ fake_use: $r2
-; CHECK-NEXT: vmov.u16 r3, d19[1]
-; CHECK-NEXT: @ fake_use: $r3
-; CHECK-NEXT: vmov.u16 r1, d20[1]
-; CHECK-NEXT: @ fake_use: $r1
-; CHECK-NEXT: vmov.u16 r4, d22[1]
-; CHECK-NEXT: @ fake_use: $r4
-; CHECK-NEXT: vmov.u16 r5, d23[1]
-; CHECK-NEXT: @ fake_use: $r5
-; CHECK-NEXT: vmov.u16 r12, d17[1]
-; CHECK-NEXT: @ fake_use: $r12
-; CHECK-NEXT: vmov.u16 r0, d18[1]
-; CHECK-NEXT: @ fake_use: $r0
-; CHECK-NEXT: vmov.u16 lr, d21[1]
-; CHECK-NEXT: @ fake_use: $lr
-; CHECK-NEXT: vmov.u16 r2, d16[2]
-; CHECK-NEXT: @ fake_use: $r2
-; CHECK-NEXT: vmov.u16 r6, d18[2]
-; CHECK-NEXT: @ fake_use: $r6
-; CHECK-NEXT: vmov.u16 r3, d19[2]
-; CHECK-NEXT: @ fake_use: $r3
-; CHECK-NEXT: vmov.u16 r1, d20[2]
-; CHECK-NEXT: @ fake_use: $r1
-; CHECK-NEXT: vmov.u16 r4, d22[2]
-; CHECK-NEXT: @ fake_use: $r4
-; CHECK-NEXT: vmov.u16 r5, d23[2]
-; CHECK-NEXT: @ fake_use: $r5
-; CHECK-NEXT: vmov.u16 r12, d17[2]
-; CHECK-NEXT: @ fake_use: $r12
-; CHECK-NEXT: vmov.u16 lr, d21[2]
-; CHECK-NEXT: @ fake_use: $lr
-; CHECK-NEXT: vmov.u16 r7, d16[3]
-; CHECK-NEXT: @ fake_use: $r7
-; CHECK-NEXT: vmov.u16 r0, d17[3]
-; CHECK-NEXT: @ fake_use: $r0
-; CHECK-NEXT: vmov.u16 r6, d18[3]
-; CHECK-NEXT: @ fake_use: $r6
-; CHECK-NEXT: vmov.u16 r3, d19[3]
-; CHECK-NEXT: @ fake_use: $r3
-; CHECK-NEXT: vmov.u16 r1, d20[3]
-; CHECK-NEXT: @ fake_use: $r1
-; CHECK-NEXT: vmov.u16 r2, d21[3]
-; CHECK-NEXT: @ fake_use: $r2
-; CHECK-NEXT: vmov.u16 r4, d22[3]
-; CHECK-NEXT: @ fake_use: $r4
-; CHECK-NEXT: vmov.u16 r5, d23[3]
-; CHECK-NEXT: @ fake_use: $r5
-; CHECK-NEXT: pop {r4, r5, r6, r7, r11, pc}
+; CHECK-NEXT: vld4.16 {d16, d18, d20, d22}, [r0]!
+; CHECK-NEXT: vld4.16 {d17, d19, d21, d23}, [r0]
+; CHECK-NEXT: @ fake_use: $q8
+; CHECK-NEXT: @ fake_use: $q9
+; CHECK-NEXT: @ fake_use: $q10
+; CHECK-NEXT: @ fake_use: $q11 $q8_q9_q10_q11
+; CHECK-NEXT: bx lr
%load = load <32 x half>, ptr %src, align 2
%deinterleave = call { <8 x half>, <8 x half>, <8 x half>, <8 x half> } @llvm.vector.deinterleave4.v32f16(<32 x half> %load)
%v0 = extractvalue { <8 x half>, <8 x half>, <8 x half>, <8 x half> } %deinterleave, 0
More information about the llvm-commits
mailing list