[llvm] [AArch64] Add combine for interleave deinterleave (3/n) (PR #208414)

David Green via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 14 14:53:33 PDT 2026


================
@@ -30423,48 +30481,80 @@ static SDValue performVectorDeinterleaveCombine(
       return SDValue();
   }
 
-  // Normal loads are currently already handled by the InterleavedAccessPass so
-  // we don't expect to see them here. Bail out if the masked load has an
-  // unexpected number of uses, since we want to avoid a situation where we have
-  // both deinterleaving loads and normal loads in the same block. Also, discard
-  // masked loads that are extending, indexed, have an unexpected offset or have
-  // an unsupported passthru value until we find a valid use case.
-  auto MaskedLoad = dyn_cast<MaskedLoadSDNode>(Op0->getOperand(0));
-  if (!MaskedLoad || !MaskedLoad->hasNUsesOfValue(NumParts, 0) ||
-      !MaskedLoad->isSimple() || !ISD::isNormalMaskedLoad(MaskedLoad) ||
-      !MaskedLoad->getOffset().isUndef() ||
-      (!MaskedLoad->getPassThru()->isUndef() &&
-       !isZerosVector(MaskedLoad->getPassThru().getNode())))
-    return SDValue();
-
-  // Now prove that the mask is an interleave of identical masks.
+  SDValue WideVec = Op0->getOperand(0);
   SDLoc DL(N);
-  SDValue NarrowMask =
-      getNarrowMaskForInterleavedOps(DAG, DL, MaskedLoad->getMask(), NumParts);
-  if (!NarrowMask)
-    return SDValue();
 
-  const Intrinsic::ID IID = NumParts == 2 ? Intrinsic::aarch64_sve_ld2_sret
-                                          : Intrinsic::aarch64_sve_ld4_sret;
-  SDValue NewLdOps[] = {MaskedLoad->getChain(),
-                        DAG.getConstant(IID, DL, MVT::i32), NarrowMask,
-                        MaskedLoad->getBasePtr()};
+  SmallVector<EVT, 5> ResVTs(NumParts, SubVecTy);
+  ResVTs.push_back(MVT::Other);
+  SDVTList ResVTList = DAG.getVTList(ResVTs);
+
   SDValue Res;
-  if (NumParts == 2)
-    Res = DAG.getNode(ISD::INTRINSIC_W_CHAIN, DL,
-                      {SubVecTy, SubVecTy, MVT::Other}, NewLdOps);
-  else
-    Res = DAG.getNode(ISD::INTRINSIC_W_CHAIN, DL,
-                      {SubVecTy, SubVecTy, SubVecTy, SubVecTy, MVT::Other},
-                      NewLdOps);
+  if (IsScalable) {
+    if (NumParts == 3)
+      return SDValue();
+    SDValue Chain, BasePtr, Pred;
+    if (auto *MaskedLoad = dyn_cast<MaskedLoadSDNode>(WideVec)) {
+      // Bail out if the masked load has an unexpected number of uses, since we
+      // want to avoid a situation where we have both deinterleaving loads and
+      // normal loads in the same block. Also, discard masked loads that are
+      // extending, indexed, have an unexpected offset or have an unsupported
+      // passthru value until we find a valid use case.
+      if (!MaskedLoad->hasNUsesOfValue(NumParts, 0) ||
+          !MaskedLoad->isSimple() || !ISD::isNormalMaskedLoad(MaskedLoad) ||
+          !MaskedLoad->getOffset().isUndef() ||
+          (!MaskedLoad->getPassThru()->isUndef() &&
+           !isZerosVector(MaskedLoad->getPassThru().getNode())))
+        return SDValue();
+
+      // Now prove that the mask is an interleave of identical masks.
+      Pred = getNarrowMaskForInterleavedOps(DAG, DL, MaskedLoad->getMask(),
+                                            NumParts);
+      if (!Pred)
+        return SDValue();
+      Chain = MaskedLoad->getChain();
+      BasePtr = MaskedLoad->getBasePtr();
+    } else {
+      auto *Load = dyn_cast<LoadSDNode>(WideVec);
+      if (!Load || !Load->hasNUsesOfValue(NumParts, 0) || !Load->isSimple() ||
+          !ISD::isNormalLoad(Load) || !Load->getOffset().isUndef())
+        return SDValue();
+
+      EVT PredVT = SubVecTy.changeVectorElementType(*DAG.getContext(), MVT::i1);
+      Pred = DAG.getConstant(1, DL, PredVT);
+      Chain = Load->getChain();
+      BasePtr = Load->getBasePtr();
+    }
+
+    const Intrinsic::ID IID = NumParts == 2 ? Intrinsic::aarch64_sve_ld2_sret
+                                            : Intrinsic::aarch64_sve_ld4_sret;
+    SDValue NewLdOps[] = {Chain, DAG.getConstant(IID, DL, MVT::i32), Pred,
+                          BasePtr};
+    Res = DAG.getNode(ISD::INTRINSIC_W_CHAIN, DL, ResVTList, NewLdOps);
----------------
davemgreen wrote:

Same here

https://github.com/llvm/llvm-project/pull/208414


More information about the llvm-commits mailing list