[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