diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -2946,38 +2946,66 @@ } // Lower the following shuffle to vslidedown. +// a) // t49: v8i8 = extract_subvector t13, Constant:i64<0> -// t109: v8i8 = extract_subvector t12, Constant:i64<8> +// t109: v8i8 = extract_subvector t13, Constant:i64<8> // t108: v8i8 = vector_shuffle<1,2,3,4,5,6,7,8> t49, t106 +// b) +// t69: v16i16 = extract_subvector t68, Constant:i64<0> +// t23: v8i16 = extract_subvector t69, Constant:i64<0> +// t29: v4i16 = extract_subvector t23, Constant:i64<4> +// t26: v8i16 = extract_subvector t69, Constant:i64<8> +// t30: v4i16 = extract_subvector t26, Constant:i64<0> +// t54: v4i16 = vector_shuffle<1,2,3,4> t29, t30 static SDValue lowerVECTOR_SHUFFLEAsVSlidedown(const SDLoc &DL, MVT VT, SDValue V1, SDValue V2, ArrayRef Mask, const RISCVSubtarget &Subtarget, SelectionDAG &DAG) { - // Both input must be extracts. - if (V1.getOpcode() != ISD::EXTRACT_SUBVECTOR || - V2.getOpcode() != ISD::EXTRACT_SUBVECTOR) - return SDValue(); + auto findNonEXTRACT_SUBVECTORParent = + [](SDValue Parent) -> std::pair { + uint64_t Offset = 0; + while (Parent.getOpcode() == ISD::EXTRACT_SUBVECTOR && + // EXTRACT_SUBVECTOR can be used to extract a fixed-width vector from + // a scalable vector. But we don't want to match the case. + Parent.getOperand(0).getSimpleValueType().isFixedLengthVector()) { + Offset += Parent.getConstantOperandVal(1); + Parent = Parent.getOperand(0); + } + return std::make_pair(Parent, Offset); + }; + + auto [V1Src, V1IndexOffset] = findNonEXTRACT_SUBVECTORParent(V1); + auto [V2Src, V2IndexOffset] = findNonEXTRACT_SUBVECTORParent(V2); // Extracting from the same source. - SDValue Src = V1.getOperand(0); - if (Src != V2.getOperand(0)) + SDValue Src = V1Src; + if (Src != V2Src) return SDValue(); - // V1 must be started with 0. - // V1 and V2 are continuous. - if (V1.getConstantOperandVal(1) != 0 || - VT.getVectorNumElements() != V2.getConstantOperandVal(1)) - return SDValue(); + // Rebuild mask because Src may be from multiple EXTRACT_SUBVECTORs. + SmallVector NewMask(Mask); + for (size_t i = 0; i != NewMask.size(); ++i) { + if (NewMask[i] == -1) + continue; + + if (static_cast(NewMask[i]) < NewMask.size()) { + NewMask[i] = NewMask[i] + V1IndexOffset; + } else { + // Minus NewMask.size() is needed. Otherwise, the b case would be + // <5,6,7,12> instead of <5,6,7,8>. + NewMask[i] = NewMask[i] - NewMask.size() + V2IndexOffset; + } + } // First index must be known and non-zero. It will be used as the slidedown // amount. - if (Mask[0] <= 0) + if (NewMask[0] <= 0) return SDValue(); - // Mask is also continuous. - for (unsigned i = 1; i != Mask.size(); ++i) - if (Mask[i - 1] + 1 != Mask[i]) + // NewMask is also continuous. + for (unsigned i = 1; i != NewMask.size(); ++i) + if (NewMask[i - 1] + 1 != NewMask[i]) return SDValue(); MVT XLenVT = Subtarget.getXLenVT(); @@ -2987,7 +3015,7 @@ SDValue Slidedown = DAG.getNode( RISCVISD::VSLIDEDOWN_VL, DL, ContainerVT, DAG.getUNDEF(ContainerVT), convertToScalableVector(ContainerVT, Src, DAG, Subtarget), - DAG.getConstant(Mask[0], DL, XLenVT), TrueMask, VL); + DAG.getConstant(NewMask[0], DL, XLenVT), TrueMask, VL); return DAG.getNode( ISD::EXTRACT_SUBVECTOR, DL, VT, convertFromScalableVector(SrcVT, Slidedown, DAG, Subtarget), diff --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-int-shuffles.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-int-shuffles.ll --- a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-int-shuffles.ll +++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-int-shuffles.ll @@ -643,14 +643,9 @@ define <4 x i16> @shuffle_shuffle_vslidedown(<16 x i16> %0) { ; CHECK-LABEL: shuffle_shuffle_vslidedown: ; CHECK: # %bb.0: # %entry -; CHECK-NEXT: vsetivli zero, 8, e16, m2, ta, ma -; CHECK-NEXT: vslidedown.vi v10, v8, 8 -; CHECK-NEXT: vsetivli zero, 4, e16, m1, ta, ma -; CHECK-NEXT: vslidedown.vi v8, v8, 4 -; CHECK-NEXT: vsetivli zero, 3, e16, mf2, ta, ma -; CHECK-NEXT: vslidedown.vi v8, v8, 1 -; CHECK-NEXT: vsetivli zero, 4, e16, mf2, tu, ma -; CHECK-NEXT: vslideup.vi v8, v10, 3 +; CHECK-NEXT: vsetivli zero, 16, e16, m2, ta, ma +; CHECK-NEXT: vslidedown.vi v8, v8, 5 +; CHECK-NEXT: # kill: def $v8 killed $v8 killed $v8m2 ; CHECK-NEXT: ret entry: %1 = shufflevector <16 x i16> %0, <16 x i16> poison, <8 x i32>