diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -962,6 +962,7 @@ SDValue WidenVecRes_STRICT_FSETCC(SDNode* N); SDValue WidenVecRes_UNDEF(SDNode *N); SDValue WidenVecRes_VECTOR_SHUFFLE(ShuffleVectorSDNode *N); + SDValue WidenVecRes_VECTOR_REVERSE(SDNode *N); SDValue WidenVecRes_Ternary(SDNode *N); SDValue WidenVecRes_Binary(SDNode *N); diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp @@ -3881,6 +3881,9 @@ case ISD::VP_GATHER: Res = WidenVecRes_VP_GATHER(cast(N)); break; + case ISD::VECTOR_REVERSE: + Res = WidenVecRes_VECTOR_REVERSE(N); + break; case ISD::ADD: case ISD::VP_ADD: case ISD::AND: case ISD::VP_AND: @@ -5533,6 +5536,61 @@ return DAG.getVectorShuffle(WidenVT, dl, InOp1, InOp2, NewMask); } +SDValue DAGTypeLegalizer::WidenVecRes_VECTOR_REVERSE(SDNode *N) { + EVT VT = N->getValueType(0); + EVT EltVT = VT.getVectorElementType(); + SDLoc dl(N); + + EVT WidenVT = TLI.getTypeToTransformTo(*DAG.getContext(), VT); + SDValue OpValue = GetWidenedVector(N->getOperand(0)); + assert(WidenVT == OpValue.getValueType() && "Unexpected widened vector type"); + + SDValue ReverseVal = DAG.getNode(ISD::VECTOR_REVERSE, dl, WidenVT, OpValue); + unsigned WidenNumElts = WidenVT.getVectorMinNumElements(); + unsigned VTNumElts = VT.getVectorMinNumElements(); + unsigned IdxVal = WidenNumElts - VTNumElts; + + if (VT.isScalableVector()) { + // Try to split the 'Widen ReverseVal' into smaller extracts and concat the + // results together, e.g.(nxv6i64 -> nxv8i64) + // nxv8i64 vector_reverse + // <-> + // nxv8i64 concat( + // nxv2i64 extract_subvector(nxv8i64, 2) + // nxv2i64 extract_subvector(nxv8i64, 4) + // nxv2i64 extract_subvector(nxv8i64, 6) + // nxv2i64 undef) + + unsigned GCD = std::gcd(VTNumElts, WidenNumElts); + EVT PartVT = EVT::getVectorVT(*DAG.getContext(), EltVT, + ElementCount::getScalable(GCD)); + assert((IdxVal % GCD) == 0 && "Expected Idx to be a multiple of the broken " + "down type's element count"); + SmallVector Parts; + unsigned i = 0; + for (; i < VTNumElts / GCD; ++i) + Parts.push_back( + DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, PartVT, ReverseVal, + DAG.getVectorIdxConstant(IdxVal + i * GCD, dl))); + for (; i < WidenNumElts / GCD; ++i) + Parts.push_back(DAG.getUNDEF(PartVT)); + + return DAG.getNode(ISD::CONCAT_VECTORS, dl, WidenVT, Parts); + } + + // Use VECTOR_SHUFFLE to combine new vector from 'ReverseVal' for + // fixed-vectors. + SmallVector Mask; + for (unsigned i = 0; i != VTNumElts; ++i) { + Mask.push_back(IdxVal + i); + } + for (unsigned i = VTNumElts; i != WidenNumElts; ++i) + Mask.push_back(-1); + + return DAG.getVectorShuffle(WidenVT, dl, ReverseVal, DAG.getUNDEF(WidenVT), + Mask); +} + SDValue DAGTypeLegalizer::WidenVecRes_SETCC(SDNode *N) { assert(N->getValueType(0).isVector() && N->getOperand(0).getValueType().isVector() && diff --git a/llvm/test/CodeGen/RISCV/rvv/named-vector-shuffle-reverse.ll b/llvm/test/CodeGen/RISCV/rvv/named-vector-shuffle-reverse.ll --- a/llvm/test/CodeGen/RISCV/rvv/named-vector-shuffle-reverse.ll +++ b/llvm/test/CodeGen/RISCV/rvv/named-vector-shuffle-reverse.ll @@ -1630,6 +1630,77 @@ ret %res } +; Test widen reverse vector + +define @reverse_nxv3i64( %a) { +; CHECK-LABEL: reverse_nxv3i64: +; CHECK: # %bb.0: +; CHECK-NEXT: csrr a0, vlenb +; CHECK-NEXT: srli a0, a0, 1 +; CHECK-NEXT: addi a0, a0, -1 +; CHECK-NEXT: vsetvli a1, zero, e64, m4, ta, mu +; CHECK-NEXT: vid.v v12 +; CHECK-NEXT: vrsub.vx v12, v12, a0 +; CHECK-NEXT: vrgather.vv v16, v8, v12 +; CHECK-NEXT: vmv1r.v v8, v17 +; CHECK-NEXT: vmv1r.v v9, v18 +; CHECK-NEXT: vmv1r.v v10, v19 +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.reverse.nxv3i64( %a) + ret %res +} + +define @reverse_nxv6i64( %a) { +; CHECK-LABEL: reverse_nxv6i64: +; CHECK: # %bb.0: +; CHECK-NEXT: csrr a0, vlenb +; CHECK-NEXT: addi a0, a0, -1 +; CHECK-NEXT: vsetvli a1, zero, e64, m8, ta, mu +; CHECK-NEXT: vid.v v16 +; CHECK-NEXT: vrsub.vx v16, v16, a0 +; CHECK-NEXT: vrgather.vv v24, v8, v16 +; CHECK-NEXT: vmv2r.v v8, v26 +; CHECK-NEXT: vmv2r.v v10, v28 +; CHECK-NEXT: vmv2r.v v12, v30 +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.reverse.nxv6i64( %a) + ret %res +} + +define @reverse_nxv12i64( %a) { +; CHECK-LABEL: reverse_nxv12i64: +; CHECK: # %bb.0: +; CHECK-NEXT: addi sp, sp, -64 +; CHECK-NEXT: .cfi_def_cfa_offset 64 +; CHECK-NEXT: addi s0, sp, 64 +; CHECK-NEXT: .cfi_def_cfa s0, 0 +; CHECK-NEXT: csrr a0, vlenb +; CHECK-NEXT: slli a0, a0, 4 +; CHECK-NEXT: sub sp, sp, a0 +; CHECK-NEXT: andi sp, sp, -64 +; CHECK-NEXT: csrr a0, vlenb +; CHECK-NEXT: addi a1, a0, -1 +; CHECK-NEXT: vsetvli a2, zero, e64, m8, ta, mu +; CHECK-NEXT: vid.v v24 +; CHECK-NEXT: vrsub.vx v24, v24, a1 +; CHECK-NEXT: vrgather.vv v0, v16, v24 +; CHECK-NEXT: vmv4r.v v16, v4 +; CHECK-NEXT: vrgather.vv v0, v8, v24 +; CHECK-NEXT: vmv4r.v v20, v0 +; CHECK-NEXT: slli a0, a0, 3 +; CHECK-NEXT: addi a1, sp, 64 +; CHECK-NEXT: add a0, a1, a0 +; CHECK-NEXT: vs4r.v v4, (a0) +; CHECK-NEXT: vs8r.v v16, (a1) +; CHECK-NEXT: vl8re64.v v16, (a0) +; CHECK-NEXT: vl8re64.v v8, (a1) +; CHECK-NEXT: addi sp, s0, -64 +; CHECK-NEXT: addi sp, sp, 64 +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.reverse.nxv12i64( %a) + ret %res +} + declare @llvm.experimental.vector.reverse.nxv2i1() declare @llvm.experimental.vector.reverse.nxv4i1() declare @llvm.experimental.vector.reverse.nxv8i1() @@ -1673,3 +1744,6 @@ declare @llvm.experimental.vector.reverse.nxv2f64() declare @llvm.experimental.vector.reverse.nxv4f64() declare @llvm.experimental.vector.reverse.nxv8f64() +declare @llvm.experimental.vector.reverse.nxv3i64() +declare @llvm.experimental.vector.reverse.nxv6i64() +declare @llvm.experimental.vector.reverse.nxv12i64()