[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