[llvm] [RISCV] Lower prefix slidedown shuffles using VL + tail-undisturbed (PR #210927)
Liao Chunyu via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 4 01:18:49 PDT 2026
https://github.com/ChunyuLiao updated https://github.com/llvm/llvm-project/pull/210927
>From e7cd0f7a3228ca9cceef1bd2fa6b5b6fe2ce15eb Mon Sep 17 00:00:00 2001
From: Liao Chunyu <chunyu at iscas.ac.cn>
Date: Mon, 13 Jul 2026 06:34:03 +0000
Subject: [PATCH 1/5] [RISCV] Lower prefix slide-pair shuffle as vslidedown
Example: vector_shuffle v8:v8i8, v9:v8i8 <9, 10, 2, 3, 4, 5, 6, 7>
We get: vmv.v.i v0, 3 + vslidedown.vi .... v0.t
VL is the number of 1s in MaskVals (the mask),
when the high bits are consecutive 1s.
This eliminates the mask-generating instruction.
Reuse SrcInfo and MaskVals from the generic slide-pair
path to derive the offset and VL
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 65 ++++++++++++++++
.../rvv/fixed-vectors-shuffle-deinterleave.ll | 7 +-
.../fixed-vectors-shuffle-deinterleave2.ll | 77 +++++++++++--------
.../rvv/fixed-vectors-shuffle-exact-vlen.ll | 10 +--
.../rvv/fixed-vectors-shuffle-transpose.ll | 24 +++---
5 files changed, 127 insertions(+), 56 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 5530ab1d79b7d..b42a63ba13f90 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -5596,6 +5596,66 @@ static SDValue lowerVECTOR_SHUFFLEAsVSlidedown(const SDLoc &DL, MVT VT,
DL, VT, convertFromScalableVector(SrcVT, Slidedown, DAG, Subtarget), 0);
}
+// vector_shuffle v8:v8i8, v9:v8i8 <9, 10, 2, 3, 4, 5, 6, 7>
+// ->
+// vsetvli zero, 2, e8, mf2, tu, ma
+// vslideup.v1 v8, v9, 1
+static SDValue lowerVECTOR_SHUFFLEAsPrefixVSlidedown(
+ const SDLoc &DL, MVT VT, SDValue V1, SDValue V2, ArrayRef<SDValue> MaskVals,
+ const std::array<std::pair<int, int>, 2> &SrcInfo, MVT ContainerVT,
+ const RISCVSubtarget &Subtarget, SelectionDAG &DAG) {
+ if (V1.isUndef() || V2.isUndef() || MaskVals.empty())
+ return SDValue();
+
+ const unsigned NumElts = VT.getVectorNumElements();
+ MVT XLenVT = Subtarget.getXLenVT();
+
+ int SlideAmt = SrcInfo[1].second;
+ // The first is not slide, the second is slidedown.
+ if (SrcInfo[0].second != 0 || SlideAmt >= 0)
+ return SDValue();
+
+ if (static_cast<unsigned>(-SlideAmt) >= NumElts)
+ return SDValue();
+
+ // Count the number of 1s in MaskVals,
+ // and ensure all 1s are at the beginning.
+ unsigned NumOnes = 0;
+ for (SDValue V : MaskVals) {
+ if (V.isUndef())
+ continue;
+ auto *C = dyn_cast<ConstantSDNode>(V);
+ if (!C)
+ return SDValue();
+ if (!C->isZero())
+ ++NumOnes;
+ }
+
+ if (NumOnes == 0 || NumOnes == NumElts || NumOnes > NumElts + SlideAmt)
+ return SDValue();
+
+ for (unsigned I = 0; I != NumOnes; ++I) {
+ auto *C = dyn_cast<ConstantSDNode>(MaskVals[I]);
+ if (!C || C->isZero())
+ return SDValue();
+ }
+
+ SDValue Src1 = SrcInfo[0].first == 0 ? V1 : V2;
+ SDValue Src2 = SrcInfo[1].first == 0 ? V1 : V2;
+
+ if (!Src1.hasOneUse())
+ return SDValue();
+
+ unsigned Policy =
+ RISCVVType::TAIL_UNDISTURBED_MASK_UNDISTURBED | RISCVVType::MASK_AGNOSTIC;
+ auto TrueMask = getDefaultVLOps(VT, ContainerVT, DL, DAG, Subtarget).first;
+ SDValue VL = DAG.getConstant(NumOnes, DL, XLenVT);
+ SDValue Slidedown = getVSlidedown(DAG, Subtarget, DL, ContainerVT, Src1, Src2,
+ DAG.getConstant(-SlideAmt, DL, XLenVT),
+ TrueMask, VL, Policy);
+ return convertFromScalableVector(VT, Slidedown, DAG, Subtarget);
+}
+
// Because vslideup leaves the destination elements at the start intact, we can
// use it to perform shuffles that insert subvectors:
//
@@ -6949,6 +7009,11 @@ SDValue RISCVTargetLowering::lowerVECTOR_SHUFFLE(SDValue Op,
MaskVals.push_back(DAG.getConstant(C, DL, XLenVT));
}
assert(MaskVals.size() == NumElts && "Unexpected select-like shuffle");
+
+ if (SDValue V = lowerVECTOR_SHUFFLEAsPrefixVSlidedown(
+ DL, VT, V1, V2, MaskVals, SrcInfo, ContainerVT, Subtarget, DAG))
+ return V;
+
MVT MaskVT = MVT::getVectorVT(MVT::i1, NumElts);
SDValue SelectMask = convertToScalableVector(
ContainerVT.changeVectorElementType(MVT::i1),
diff --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-deinterleave.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-deinterleave.ll
index 03fc1c30d8aac..d2d35c51ea3e0 100644
--- a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-deinterleave.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-deinterleave.ll
@@ -431,11 +431,12 @@ entry:
define void @deinterleave8_8_i8_two_source(ptr %in0, ptr %in1, ptr %out) {
; CHECK-LABEL: deinterleave8_8_i8_two_source:
; CHECK: # %bb.0: # %entry
-; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, mu
-; CHECK-NEXT: vmv.v.i v0, 1
+; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
; CHECK-NEXT: vle8.v v8, (a0)
; CHECK-NEXT: vle8.v v9, (a1)
-; CHECK-NEXT: vslidedown.vi v9, v8, 1, v0.t
+; CHECK-NEXT: vsetivli zero, 1, e8, mf2, tu, ma
+; CHECK-NEXT: vslidedown.vi v9, v8, 1
+; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
; CHECK-NEXT: vse8.v v9, (a2)
; CHECK-NEXT: ret
entry:
diff --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-deinterleave2.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-deinterleave2.ll
index 94429ac18dd3d..37bf0f8d4899c 100644
--- a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-deinterleave2.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-deinterleave2.ll
@@ -294,11 +294,12 @@ define void @vnsrl_32_i32(ptr %in, ptr %out) {
; ZVE32F-LABEL: vnsrl_32_i32:
; ZVE32F: # %bb.0: # %entry
; ZVE32F-NEXT: vsetivli zero, 4, e32, m1, ta, ma
-; ZVE32F-NEXT: vmv.v.i v0, 1
; ZVE32F-NEXT: vle32.v v8, (a0)
-; ZVE32F-NEXT: vsetivli zero, 2, e32, m1, ta, mu
+; ZVE32F-NEXT: vsetivli zero, 2, e32, m1, ta, ma
; ZVE32F-NEXT: vslidedown.vi v9, v8, 2
-; ZVE32F-NEXT: vslidedown.vi v9, v8, 1, v0.t
+; ZVE32F-NEXT: vsetivli zero, 1, e32, m1, tu, ma
+; ZVE32F-NEXT: vslidedown.vi v9, v8, 1
+; ZVE32F-NEXT: vsetivli zero, 2, e32, m1, ta, ma
; ZVE32F-NEXT: vse32.v v9, (a1)
; ZVE32F-NEXT: ret
;
@@ -367,11 +368,12 @@ define void @vnsrl_32_float(ptr %in, ptr %out) {
; ZVE32F-LABEL: vnsrl_32_float:
; ZVE32F: # %bb.0: # %entry
; ZVE32F-NEXT: vsetivli zero, 4, e32, m1, ta, ma
-; ZVE32F-NEXT: vmv.v.i v0, 1
; ZVE32F-NEXT: vle32.v v8, (a0)
-; ZVE32F-NEXT: vsetivli zero, 2, e32, m1, ta, mu
+; ZVE32F-NEXT: vsetivli zero, 2, e32, m1, ta, ma
; ZVE32F-NEXT: vslidedown.vi v9, v8, 2
-; ZVE32F-NEXT: vslidedown.vi v9, v8, 1, v0.t
+; ZVE32F-NEXT: vsetivli zero, 1, e32, m1, tu, ma
+; ZVE32F-NEXT: vslidedown.vi v9, v8, 1
+; ZVE32F-NEXT: vsetivli zero, 2, e32, m1, ta, ma
; ZVE32F-NEXT: vse32.v v9, (a1)
; ZVE32F-NEXT: ret
;
@@ -429,11 +431,12 @@ define void @vnsrl_64_i64(ptr %in, ptr %out) {
; V-LABEL: vnsrl_64_i64:
; V: # %bb.0: # %entry
; V-NEXT: vsetivli zero, 4, e64, m1, ta, ma
-; V-NEXT: vmv.v.i v0, 1
; V-NEXT: vle64.v v8, (a0)
-; V-NEXT: vsetivli zero, 2, e64, m1, ta, mu
+; V-NEXT: vsetivli zero, 2, e64, m1, ta, ma
; V-NEXT: vslidedown.vi v9, v8, 2
-; V-NEXT: vslidedown.vi v9, v8, 1, v0.t
+; V-NEXT: vsetivli zero, 1, e64, m1, tu, ma
+; V-NEXT: vslidedown.vi v9, v8, 1
+; V-NEXT: vsetivli zero, 2, e64, m1, ta, ma
; V-NEXT: vse64.v v9, (a1)
; V-NEXT: ret
;
@@ -498,11 +501,12 @@ define void @vnsrl_64_double(ptr %in, ptr %out) {
; V-LABEL: vnsrl_64_double:
; V: # %bb.0: # %entry
; V-NEXT: vsetivli zero, 4, e64, m1, ta, ma
-; V-NEXT: vmv.v.i v0, 1
; V-NEXT: vle64.v v8, (a0)
-; V-NEXT: vsetivli zero, 2, e64, m1, ta, mu
+; V-NEXT: vsetivli zero, 2, e64, m1, ta, ma
; V-NEXT: vslidedown.vi v9, v8, 2
-; V-NEXT: vslidedown.vi v9, v8, 1, v0.t
+; V-NEXT: vsetivli zero, 1, e64, m1, tu, ma
+; V-NEXT: vslidedown.vi v9, v8, 1
+; V-NEXT: vsetivli zero, 2, e64, m1, ta, ma
; V-NEXT: vse64.v v9, (a1)
; V-NEXT: ret
;
@@ -1217,21 +1221,23 @@ entry:
define void @vnsrl_32_i32_two_source(ptr %in0, ptr %in1, ptr %out) {
; V-LABEL: vnsrl_32_i32_two_source:
; V: # %bb.0: # %entry
-; V-NEXT: vsetivli zero, 2, e32, mf2, ta, mu
-; V-NEXT: vmv.v.i v0, 1
+; V-NEXT: vsetivli zero, 2, e32, mf2, ta, ma
; V-NEXT: vle32.v v8, (a0)
; V-NEXT: vle32.v v9, (a1)
-; V-NEXT: vslidedown.vi v9, v8, 1, v0.t
+; V-NEXT: vsetivli zero, 1, e32, mf2, tu, ma
+; V-NEXT: vslidedown.vi v9, v8, 1
+; V-NEXT: vsetivli zero, 2, e32, mf2, ta, ma
; V-NEXT: vse32.v v9, (a2)
; V-NEXT: ret
;
; ZVE32F-LABEL: vnsrl_32_i32_two_source:
; ZVE32F: # %bb.0: # %entry
-; ZVE32F-NEXT: vsetivli zero, 2, e32, m1, ta, mu
-; ZVE32F-NEXT: vmv.v.i v0, 1
+; ZVE32F-NEXT: vsetivli zero, 2, e32, m1, ta, ma
; ZVE32F-NEXT: vle32.v v8, (a0)
; ZVE32F-NEXT: vle32.v v9, (a1)
-; ZVE32F-NEXT: vslidedown.vi v9, v8, 1, v0.t
+; ZVE32F-NEXT: vsetivli zero, 1, e32, m1, tu, ma
+; ZVE32F-NEXT: vslidedown.vi v9, v8, 1
+; ZVE32F-NEXT: vsetivli zero, 2, e32, m1, ta, ma
; ZVE32F-NEXT: vse32.v v9, (a2)
; ZVE32F-NEXT: ret
;
@@ -1289,21 +1295,23 @@ entry:
define void @vnsrl_32_float_two_source(ptr %in0, ptr %in1, ptr %out) {
; V-LABEL: vnsrl_32_float_two_source:
; V: # %bb.0: # %entry
-; V-NEXT: vsetivli zero, 2, e32, mf2, ta, mu
-; V-NEXT: vmv.v.i v0, 1
+; V-NEXT: vsetivli zero, 2, e32, mf2, ta, ma
; V-NEXT: vle32.v v8, (a0)
; V-NEXT: vle32.v v9, (a1)
-; V-NEXT: vslidedown.vi v9, v8, 1, v0.t
+; V-NEXT: vsetivli zero, 1, e32, mf2, tu, ma
+; V-NEXT: vslidedown.vi v9, v8, 1
+; V-NEXT: vsetivli zero, 2, e32, mf2, ta, ma
; V-NEXT: vse32.v v9, (a2)
; V-NEXT: ret
;
; ZVE32F-LABEL: vnsrl_32_float_two_source:
; ZVE32F: # %bb.0: # %entry
-; ZVE32F-NEXT: vsetivli zero, 2, e32, m1, ta, mu
-; ZVE32F-NEXT: vmv.v.i v0, 1
+; ZVE32F-NEXT: vsetivli zero, 2, e32, m1, ta, ma
; ZVE32F-NEXT: vle32.v v8, (a0)
; ZVE32F-NEXT: vle32.v v9, (a1)
-; ZVE32F-NEXT: vslidedown.vi v9, v8, 1, v0.t
+; ZVE32F-NEXT: vsetivli zero, 1, e32, m1, tu, ma
+; ZVE32F-NEXT: vslidedown.vi v9, v8, 1
+; ZVE32F-NEXT: vsetivli zero, 2, e32, m1, ta, ma
; ZVE32F-NEXT: vse32.v v9, (a2)
; ZVE32F-NEXT: ret
;
@@ -1361,21 +1369,23 @@ entry:
define void @vnsrl_64_i64_two_source(ptr %in0, ptr %in1, ptr %out) {
; V-LABEL: vnsrl_64_i64_two_source:
; V: # %bb.0: # %entry
-; V-NEXT: vsetivli zero, 2, e64, m1, ta, mu
-; V-NEXT: vmv.v.i v0, 1
+; V-NEXT: vsetivli zero, 2, e64, m1, ta, ma
; V-NEXT: vle64.v v8, (a0)
; V-NEXT: vle64.v v9, (a1)
-; V-NEXT: vslidedown.vi v9, v8, 1, v0.t
+; V-NEXT: vsetivli zero, 1, e64, m1, tu, ma
+; V-NEXT: vslidedown.vi v9, v8, 1
+; V-NEXT: vsetivli zero, 2, e64, m1, ta, ma
; V-NEXT: vse64.v v9, (a2)
; V-NEXT: ret
;
; ZVE32F-LABEL: vnsrl_64_i64_two_source:
; ZVE32F: # %bb.0: # %entry
-; ZVE32F-NEXT: vsetivli zero, 4, e32, m1, ta, mu
-; ZVE32F-NEXT: vmv.v.i v0, 3
+; ZVE32F-NEXT: vsetivli zero, 4, e32, m1, ta, ma
; ZVE32F-NEXT: vle32.v v8, (a0)
; ZVE32F-NEXT: vle32.v v9, (a1)
-; ZVE32F-NEXT: vslidedown.vi v9, v8, 2, v0.t
+; ZVE32F-NEXT: vsetivli zero, 2, e32, m1, tu, ma
+; ZVE32F-NEXT: vslidedown.vi v9, v8, 2
+; ZVE32F-NEXT: vsetivli zero, 4, e32, m1, ta, ma
; ZVE32F-NEXT: vse32.v v9, (a2)
; ZVE32F-NEXT: ret
;
@@ -1432,11 +1442,12 @@ entry:
define void @vnsrl_64_double_two_source(ptr %in0, ptr %in1, ptr %out) {
; V-LABEL: vnsrl_64_double_two_source:
; V: # %bb.0: # %entry
-; V-NEXT: vsetivli zero, 2, e64, m1, ta, mu
-; V-NEXT: vmv.v.i v0, 1
+; V-NEXT: vsetivli zero, 2, e64, m1, ta, ma
; V-NEXT: vle64.v v8, (a0)
; V-NEXT: vle64.v v9, (a1)
-; V-NEXT: vslidedown.vi v9, v8, 1, v0.t
+; V-NEXT: vsetivli zero, 1, e64, m1, tu, ma
+; V-NEXT: vslidedown.vi v9, v8, 1
+; V-NEXT: vsetivli zero, 2, e64, m1, ta, ma
; V-NEXT: vse64.v v9, (a2)
; V-NEXT: ret
;
diff --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-exact-vlen.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-exact-vlen.ll
index 534eb5ca75fc4..ecb04f8c31235 100644
--- a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-exact-vlen.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-exact-vlen.ll
@@ -229,9 +229,8 @@ define i64 @extract_any_extend_vector_inreg_v16i64(<16 x i64> %a0, i32 %a1) vsca
; RV32: # %bb.0:
; RV32-NEXT: vsetivli zero, 16, e64, m8, ta, ma
; RV32-NEXT: vmv.v.i v16, 0
-; RV32-NEXT: vsetivli zero, 2, e64, m1, ta, mu
-; RV32-NEXT: vmv.v.i v0, 1
-; RV32-NEXT: vslidedown.vi v18, v15, 1, v0.t
+; RV32-NEXT: vsetivli zero, 1, e64, m1, tu, ma
+; RV32-NEXT: vslidedown.vi v18, v15, 1
; RV32-NEXT: vsetivli zero, 1, e64, m8, ta, ma
; RV32-NEXT: vslidedown.vx v8, v16, a0
; RV32-NEXT: li a0, 32
@@ -255,9 +254,8 @@ define i64 @extract_any_extend_vector_inreg_v16i64(<16 x i64> %a0, i32 %a1) vsca
; RV64-NEXT: andi sp, sp, -128
; RV64-NEXT: vsetivli zero, 16, e64, m8, ta, ma
; RV64-NEXT: vmv.v.i v16, 0
-; RV64-NEXT: vsetivli zero, 2, e64, m1, ta, mu
-; RV64-NEXT: vmv.v.i v0, 1
-; RV64-NEXT: vslidedown.vi v18, v15, 1, v0.t
+; RV64-NEXT: vsetivli zero, 1, e64, m1, tu, ma
+; RV64-NEXT: vslidedown.vi v18, v15, 1
; RV64-NEXT: mv s1, sp
; RV64-NEXT: vs8r.v v16, (s1)
; RV64-NEXT: andi a0, a0, 15
diff --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-transpose.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-transpose.ll
index ad7cf7eee5023..058fe1def6e58 100644
--- a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-transpose.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-transpose.ll
@@ -119,9 +119,8 @@ define <2 x i32> @trn1.v2i32(<2 x i32> %v0, <2 x i32> %v1) {
define <2 x i32> @trn2.v2i32(<2 x i32> %v0, <2 x i32> %v1) {
; CHECK-LABEL: trn2.v2i32:
; CHECK: # %bb.0:
-; CHECK-NEXT: vsetivli zero, 2, e32, mf2, ta, mu
-; CHECK-NEXT: vmv.v.i v0, 1
-; CHECK-NEXT: vslidedown.vi v9, v8, 1, v0.t
+; CHECK-NEXT: vsetivli zero, 1, e32, mf2, tu, ma
+; CHECK-NEXT: vslidedown.vi v9, v8, 1
; CHECK-NEXT: vmv1r.v v8, v9
; CHECK-NEXT: ret
%tmp0 = shufflevector <2 x i32> %v0, <2 x i32> %v1, <2 x i32> <i32 1, i32 3>
@@ -164,10 +163,9 @@ define <2 x i64> @trn1.v2i64(<2 x i64> %v0, <2 x i64> %v1) {
define <2 x i64> @trn2.v2i64(<2 x i64> %v0, <2 x i64> %v1) {
; CHECK-LABEL: trn2.v2i64:
; CHECK: # %bb.0:
-; CHECK-NEXT: vsetivli zero, 2, e64, m1, ta, mu
-; CHECK-NEXT: vmv.v.i v0, 1
-; CHECK-NEXT: vslidedown.vi v9, v8, 1, v0.t
-; CHECK-NEXT: vmv.v.v v8, v9
+; CHECK-NEXT: vsetivli zero, 1, e64, m1, tu, ma
+; CHECK-NEXT: vslidedown.vi v9, v8, 1
+; CHECK-NEXT: vmv1r.v v8, v9
; CHECK-NEXT: ret
%tmp0 = shufflevector <2 x i64> %v0, <2 x i64> %v1, <2 x i32> <i32 1, i32 3>
ret <2 x i64> %tmp0
@@ -186,9 +184,8 @@ define <2 x float> @trn1.v2f32(<2 x float> %v0, <2 x float> %v1) {
define <2 x float> @trn2.v2f32(<2 x float> %v0, <2 x float> %v1) {
; CHECK-LABEL: trn2.v2f32:
; CHECK: # %bb.0:
-; CHECK-NEXT: vsetivli zero, 2, e32, mf2, ta, mu
-; CHECK-NEXT: vmv.v.i v0, 1
-; CHECK-NEXT: vslidedown.vi v9, v8, 1, v0.t
+; CHECK-NEXT: vsetivli zero, 1, e32, mf2, tu, ma
+; CHECK-NEXT: vslidedown.vi v9, v8, 1
; CHECK-NEXT: vmv1r.v v8, v9
; CHECK-NEXT: ret
%tmp0 = shufflevector <2 x float> %v0, <2 x float> %v1, <2 x i32> <i32 1, i32 3>
@@ -231,10 +228,9 @@ define <2 x double> @trn1.v2f64(<2 x double> %v0, <2 x double> %v1) {
define <2 x double> @trn2.v2f64(<2 x double> %v0, <2 x double> %v1) {
; CHECK-LABEL: trn2.v2f64:
; CHECK: # %bb.0:
-; CHECK-NEXT: vsetivli zero, 2, e64, m1, ta, mu
-; CHECK-NEXT: vmv.v.i v0, 1
-; CHECK-NEXT: vslidedown.vi v9, v8, 1, v0.t
-; CHECK-NEXT: vmv.v.v v8, v9
+; CHECK-NEXT: vsetivli zero, 1, e64, m1, tu, ma
+; CHECK-NEXT: vslidedown.vi v9, v8, 1
+; CHECK-NEXT: vmv1r.v v8, v9
; CHECK-NEXT: ret
%tmp0 = shufflevector <2 x double> %v0, <2 x double> %v1, <2 x i32> <i32 1, i32 3>
ret <2 x double> %tmp0
>From 970ea75274d698b4892880b53136e27c45849e4a Mon Sep 17 00:00:00 2001
From: Liao Chunyu <chunyu at iscas.ac.cn>
Date: Thu, 23 Jul 2026 08:25:06 +0000
Subject: [PATCH 2/5] address comment from lukel97, use mask
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 64 ++++++++++---------
.../rvv/fixed-vectors-shuffle-exact-vlen.ll | 7 +-
.../RISCV/rvv/vector-deinterleave-fixed.ll | 20 +++---
3 files changed, 49 insertions(+), 42 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index b42a63ba13f90..8d75e9337cb36 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -5599,12 +5599,12 @@ static SDValue lowerVECTOR_SHUFFLEAsVSlidedown(const SDLoc &DL, MVT VT,
// vector_shuffle v8:v8i8, v9:v8i8 <9, 10, 2, 3, 4, 5, 6, 7>
// ->
// vsetvli zero, 2, e8, mf2, tu, ma
-// vslideup.v1 v8, v9, 1
+// vslidedown.vi v8, v9, 1
static SDValue lowerVECTOR_SHUFFLEAsPrefixVSlidedown(
- const SDLoc &DL, MVT VT, SDValue V1, SDValue V2, ArrayRef<SDValue> MaskVals,
+ const SDLoc &DL, MVT VT, SDValue V1, SDValue V2, ArrayRef<int> Mask,
const std::array<std::pair<int, int>, 2> &SrcInfo, MVT ContainerVT,
const RISCVSubtarget &Subtarget, SelectionDAG &DAG) {
- if (V1.isUndef() || V2.isUndef() || MaskVals.empty())
+ if (V1.isUndef() || V2.isUndef())
return SDValue();
const unsigned NumElts = VT.getVectorNumElements();
@@ -5615,44 +5615,46 @@ static SDValue lowerVECTOR_SHUFFLEAsPrefixVSlidedown(
if (SrcInfo[0].second != 0 || SlideAmt >= 0)
return SDValue();
- if (static_cast<unsigned>(-SlideAmt) >= NumElts)
+ unsigned SlideDownAmt = -SlideAmt;
+ if (SlideDownAmt >= NumElts)
return SDValue();
- // Count the number of 1s in MaskVals,
- // and ensure all 1s are at the beginning.
- unsigned NumOnes = 0;
- for (SDValue V : MaskVals) {
- if (V.isUndef())
- continue;
- auto *C = dyn_cast<ConstantSDNode>(V);
- if (!C)
- return SDValue();
- if (!C->isZero())
- ++NumOnes;
+ // Check whether the leading lanes are consecutive lanes
+ // from the second slide.
+ auto IsSecondSlideLane = [&](unsigned I) {
+ int M = Mask[I];
+ if (M < 0)
+ return false;
+
+ int Src = M >= (int)NumElts;
+ int Diff = (int)I - (M % NumElts);
+ return Src == SrcInfo[1].first && Diff == SrcInfo[1].second;
+ };
+
+ unsigned VL = 0;
+ for (unsigned I = 0; I != NumElts; ++I) {
+ if (!IsSecondSlideLane(I))
+ break;
+ ++VL;
}
- if (NumOnes == 0 || NumOnes == NumElts || NumOnes > NumElts + SlideAmt)
+ if (VL == 0 || VL == NumElts || VL > NumElts - SlideDownAmt)
return SDValue();
- for (unsigned I = 0; I != NumOnes; ++I) {
- auto *C = dyn_cast<ConstantSDNode>(MaskVals[I]);
- if (!C || C->isZero())
+ for (unsigned I = VL; I != NumElts; ++I)
+ if (IsSecondSlideLane(I))
return SDValue();
- }
SDValue Src1 = SrcInfo[0].first == 0 ? V1 : V2;
SDValue Src2 = SrcInfo[1].first == 0 ? V1 : V2;
- if (!Src1.hasOneUse())
- return SDValue();
-
unsigned Policy =
RISCVVType::TAIL_UNDISTURBED_MASK_UNDISTURBED | RISCVVType::MASK_AGNOSTIC;
auto TrueMask = getDefaultVLOps(VT, ContainerVT, DL, DAG, Subtarget).first;
- SDValue VL = DAG.getConstant(NumOnes, DL, XLenVT);
+ SDValue VLOp = DAG.getConstant(VL, DL, XLenVT);
SDValue Slidedown = getVSlidedown(DAG, Subtarget, DL, ContainerVT, Src1, Src2,
- DAG.getConstant(-SlideAmt, DL, XLenVT),
- TrueMask, VL, Policy);
+ DAG.getConstant(SlideDownAmt, DL, XLenVT),
+ TrueMask, VLOp, Policy);
return convertFromScalableVector(VT, Slidedown, DAG, Subtarget);
}
@@ -5667,7 +5669,7 @@ static SDValue lowerVECTOR_SHUFFLEAsPrefixVSlidedown(
// vector_shuffle v8:v8i8, v9:v8i8 <0, 1, 8, 9, 10, 5, 6, 7>
// ->
// vsetvli zero, 5, e8, mf2, tu, ma
-// vslideup.v1 v8, v9, 2
+// vslideup.vi v8, v9, 2
static SDValue lowerVECTOR_SHUFFLEAsVSlideup(const SDLoc &DL, MVT VT,
SDValue V1, SDValue V2,
ArrayRef<int> Mask,
@@ -6990,6 +6992,10 @@ SDValue RISCVTargetLowering::lowerVECTOR_SHUFFLE(SDValue Op,
return V;
}
+ if (SDValue V = lowerVECTOR_SHUFFLEAsPrefixVSlidedown(
+ DL, VT, V1, V2, Mask, SrcInfo, ContainerVT, Subtarget, DAG))
+ return V;
+
// Build the mask. Note that vslideup unconditionally preserves elements
// below the slide amount in the destination, and thus those elements are
// undefined in the mask. If the mask ends up all true (or undef), it
@@ -7010,10 +7016,6 @@ SDValue RISCVTargetLowering::lowerVECTOR_SHUFFLE(SDValue Op,
}
assert(MaskVals.size() == NumElts && "Unexpected select-like shuffle");
- if (SDValue V = lowerVECTOR_SHUFFLEAsPrefixVSlidedown(
- DL, VT, V1, V2, MaskVals, SrcInfo, ContainerVT, Subtarget, DAG))
- return V;
-
MVT MaskVT = MVT::getVectorVT(MVT::i1, NumElts);
SDValue SelectMask = convertToScalableVector(
ContainerVT.changeVectorElementType(MVT::i1),
diff --git a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-exact-vlen.ll b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-exact-vlen.ll
index ecb04f8c31235..6a296910ae382 100644
--- a/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-exact-vlen.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-exact-vlen.ll
@@ -283,12 +283,13 @@ define i64 @extract_any_extend_vector_inreg_v16i64(<16 x i64> %a0, i32 %a1) vsca
define <4 x double> @shuffles_add(<4 x double> %0, <4 x double> %1) vscale_range(2,2) {
; CHECK-LABEL: shuffles_add:
; CHECK: # %bb.0:
-; CHECK-NEXT: vsetivli zero, 2, e64, m1, ta, mu
-; CHECK-NEXT: vmv.v.i v0, 1
+; CHECK-NEXT: vsetivli zero, 2, e64, m1, ta, ma
; CHECK-NEXT: vmv1r.v v13, v10
; CHECK-NEXT: vslideup.vi v13, v11, 1
-; CHECK-NEXT: vslidedown.vi v11, v10, 1, v0.t
+; CHECK-NEXT: vsetivli zero, 1, e64, m1, tu, ma
+; CHECK-NEXT: vslidedown.vi v11, v10, 1
; CHECK-NEXT: vmv1r.v v10, v9
+; CHECK-NEXT: vsetivli zero, 2, e64, m1, ta, ma
; CHECK-NEXT: vrgather.vi v12, v9, 0
; CHECK-NEXT: vsetivli zero, 4, e64, m2, ta, ma
; CHECK-NEXT: vfadd.vv v8, v12, v10
diff --git a/llvm/test/CodeGen/RISCV/rvv/vector-deinterleave-fixed.ll b/llvm/test/CodeGen/RISCV/rvv/vector-deinterleave-fixed.ll
index bce071e988f0e..0c61b3212307b 100644
--- a/llvm/test/CodeGen/RISCV/rvv/vector-deinterleave-fixed.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/vector-deinterleave-fixed.ll
@@ -76,11 +76,13 @@ define {<2 x i64>, <2 x i64>} @vector_deinterleave_v2i64_v4i64(<4 x i64> %vec) {
; V: # %bb.0:
; V-NEXT: vsetivli zero, 2, e64, m2, ta, ma
; V-NEXT: vslidedown.vi v10, v8, 2
-; V-NEXT: vsetivli zero, 2, e64, m1, ta, mu
-; V-NEXT: vmv.v.i v0, 1
+; V-NEXT: vmv1r.v v9, v8
+; V-NEXT: vsetivli zero, 2, e64, m1, ta, ma
+; V-NEXT: vslideup.vi v9, v10, 1
+; V-NEXT: vsetivli zero, 1, e64, m1, tu, ma
+; V-NEXT: vslidedown.vi v10, v8, 1
+; V-NEXT: vmv1r.v v8, v9
; V-NEXT: vmv1r.v v9, v10
-; V-NEXT: vslidedown.vi v9, v8, 1, v0.t
-; V-NEXT: vslideup.vi v8, v10, 1
; V-NEXT: ret
;
; ZVZIP-LABEL: vector_deinterleave_v2i64_v4i64:
@@ -802,11 +804,13 @@ define {<2 x double>, <2 x double>} @vector_deinterleave_v2f64_v4f64(<4 x double
; V: # %bb.0:
; V-NEXT: vsetivli zero, 2, e64, m2, ta, ma
; V-NEXT: vslidedown.vi v10, v8, 2
-; V-NEXT: vsetivli zero, 2, e64, m1, ta, mu
-; V-NEXT: vmv.v.i v0, 1
+; V-NEXT: vmv1r.v v9, v8
+; V-NEXT: vsetivli zero, 2, e64, m1, ta, ma
+; V-NEXT: vslideup.vi v9, v10, 1
+; V-NEXT: vsetivli zero, 1, e64, m1, tu, ma
+; V-NEXT: vslidedown.vi v10, v8, 1
+; V-NEXT: vmv1r.v v8, v9
; V-NEXT: vmv1r.v v9, v10
-; V-NEXT: vslidedown.vi v9, v8, 1, v0.t
-; V-NEXT: vslideup.vi v8, v10, 1
; V-NEXT: ret
;
; ZVZIP-LABEL: vector_deinterleave_v2f64_v4f64:
>From bf509d323c7b8970b6ebd71af858b5027f6a472e Mon Sep 17 00:00:00 2001
From: Liao Chunyu <chunyu at iscas.ac.cn>
Date: Thu, 23 Jul 2026 08:32:01 +0000
Subject: [PATCH 3/5] address from mshockwave
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 8d75e9337cb36..af2eb5219129f 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -5602,7 +5602,7 @@ static SDValue lowerVECTOR_SHUFFLEAsVSlidedown(const SDLoc &DL, MVT VT,
// vslidedown.vi v8, v9, 1
static SDValue lowerVECTOR_SHUFFLEAsPrefixVSlidedown(
const SDLoc &DL, MVT VT, SDValue V1, SDValue V2, ArrayRef<int> Mask,
- const std::array<std::pair<int, int>, 2> &SrcInfo, MVT ContainerVT,
+ ArrayRef<std::pair<int, int>> SrcInfo, MVT ContainerVT,
const RISCVSubtarget &Subtarget, SelectionDAG &DAG) {
if (V1.isUndef() || V2.isUndef())
return SDValue();
>From 21d0363d48161adaa239c914799d1d40b6edbf32 Mon Sep 17 00:00:00 2001
From: Liao Chunyu <chunyu at iscas.ac.cn>
Date: Thu, 23 Jul 2026 08:53:32 +0000
Subject: [PATCH 4/5] delete empty line
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index af2eb5219129f..baf0d67a84be5 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -7015,7 +7015,6 @@ SDValue RISCVTargetLowering::lowerVECTOR_SHUFFLE(SDValue Op,
MaskVals.push_back(DAG.getConstant(C, DL, XLenVT));
}
assert(MaskVals.size() == NumElts && "Unexpected select-like shuffle");
-
MVT MaskVT = MVT::getVectorVT(MVT::i1, NumElts);
SDValue SelectMask = convertToScalableVector(
ContainerVT.changeVectorElementType(MVT::i1),
>From 4dea9165a209946aebbf5264ae49154a6ca5f7d2 Mon Sep 17 00:00:00 2001
From: Liao Chunyu <chunyu at iscas.ac.cn>
Date: Tue, 4 Aug 2026 07:14:11 +0000
Subject: [PATCH 5/5] merge to loops and other comments
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index baf0d67a84be5..62c344bd2fe46 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -5615,10 +5615,6 @@ static SDValue lowerVECTOR_SHUFFLEAsPrefixVSlidedown(
if (SrcInfo[0].second != 0 || SlideAmt >= 0)
return SDValue();
- unsigned SlideDownAmt = -SlideAmt;
- if (SlideDownAmt >= NumElts)
- return SDValue();
-
// Check whether the leading lanes are consecutive lanes
// from the second slide.
auto IsSecondSlideLane = [&](unsigned I) {
@@ -5632,19 +5628,22 @@ static SDValue lowerVECTOR_SHUFFLEAsPrefixVSlidedown(
};
unsigned VL = 0;
+ bool IsFirst = false;
for (unsigned I = 0; I != NumElts; ++I) {
- if (!IsSecondSlideLane(I))
- break;
+ if (!IsSecondSlideLane(I)) {
+ IsFirst = true;
+ continue;
+ }
+
+ if (IsFirst)
+ return SDValue();
++VL;
}
+ unsigned SlideDownAmt = -SlideAmt;
if (VL == 0 || VL == NumElts || VL > NumElts - SlideDownAmt)
return SDValue();
- for (unsigned I = VL; I != NumElts; ++I)
- if (IsSecondSlideLane(I))
- return SDValue();
-
SDValue Src1 = SrcInfo[0].first == 0 ? V1 : V2;
SDValue Src2 = SrcInfo[1].first == 0 ? V1 : V2;
@@ -5652,6 +5651,8 @@ static SDValue lowerVECTOR_SHUFFLEAsPrefixVSlidedown(
RISCVVType::TAIL_UNDISTURBED_MASK_UNDISTURBED | RISCVVType::MASK_AGNOSTIC;
auto TrueMask = getDefaultVLOps(VT, ContainerVT, DL, DAG, Subtarget).first;
SDValue VLOp = DAG.getConstant(VL, DL, XLenVT);
+ Src1 = convertToScalableVector(ContainerVT, Src1, DAG, Subtarget);
+ Src2 = convertToScalableVector(ContainerVT, Src2, DAG, Subtarget);
SDValue Slidedown = getVSlidedown(DAG, Subtarget, DL, ContainerVT, Src1, Src2,
DAG.getConstant(SlideDownAmt, DL, XLenVT),
TrueMask, VLOp, Policy);
More information about the llvm-commits
mailing list