[llvm] [RISCV] Use slideup to lower build_vector when all operand are (extract_element X, 0) (PR #154450)
Min-Yih Hsu via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 2 09:19:56 PDT 2025
================
@@ -4513,41 +4513,104 @@ static SDValue lowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG,
const unsigned Policy = RISCVVType::TAIL_AGNOSTIC | RISCVVType::MASK_AGNOSTIC;
+ // General case: splat the first operand and slide other operands down one
+ // by one to form a vector. Alternatively, if every operand is an
+ // extraction from element 0 of a vector, we use that vector from the last
+ // extraction as the start value and slide up instead of slide down. Such that
+ // (1) we can avoid the initial splat (2) we can turn those vslide1up into
+ // vslideup of 1 later and eliminate the vector to scalar movement, which is
+ // something we cannot do with vslide1down/vslidedown.
+ // Of course, using vslide1up/vslideup might increase the register pressure,
+ // and that's why we conservatively limit to cases where every operands is an
+ // extraction from first element.
+ SmallVector<SDValue> Operands(Op->op_begin(), Op->op_end());
+ SDValue EVec;
+ bool SlideUp = false;
+ auto getVSlide = [&](EVT ContainerVT, SDValue Passthru, SDValue Vec,
+ SDValue Offset, SDValue Mask, SDValue VL) -> SDValue {
+ if (SlideUp)
+ return getVSlideup(DAG, Subtarget, DL, ContainerVT, Passthru, Vec, Offset,
+ Mask, VL, Policy);
+ return getVSlidedown(DAG, Subtarget, DL, ContainerVT, Passthru, Vec, Offset,
+ Mask, VL, Policy);
+ };
+
+ // The reason we don't use all_of here is because we're also capturing EVec
+ // from the last non-undef operand. If the std::execution_policy of the
+ // underlying std::all_of is anything but std::sequenced_policy we might
+ // capture the wrong EVec.
+ for (SDValue V : Operands) {
+ using namespace SDPatternMatch;
+ SlideUp = V.isUndef() || sd_match(V, m_ExtractElt(m_Value(EVec), m_Zero()));
+ if (!SlideUp)
+ break;
+ }
+
+ if (SlideUp) {
+ MVT EVecContainerVT = EVec.getSimpleValueType();
+ // Make sure the original vector has scalable vector type.
+ if (EVecContainerVT.isFixedLengthVector()) {
+ EVecContainerVT =
+ getContainerForFixedLengthVector(DAG, EVecContainerVT, Subtarget);
+ EVec = convertToScalableVector(EVecContainerVT, EVec, DAG, Subtarget);
+ }
+
+ // Adapt EVec's type into ContainerVT.
+ if (EVecContainerVT.getVectorMinNumElements() <
+ ContainerVT.getVectorMinNumElements())
+ EVec = DAG.getInsertSubvector(DL, DAG.getUNDEF(ContainerVT), EVec, 0);
+ else
+ EVec = DAG.getExtractSubvector(DL, ContainerVT, EVec, 0);
+
+ // Reverse the elements as we're going to slide up from the last element.
+ std::reverse(Operands.begin(), Operands.end());
----------------
mshockwave wrote:
> Nit, does llvm::reverse work here?
That was actually [what I thought](https://github.com/llvm/llvm-project/pull/154450#discussion_r2289250696), but unfortunately, `llvm::reverse` returns an iterator range instead of reversing content in-place.
https://github.com/llvm/llvm-project/pull/154450
More information about the llvm-commits
mailing list