Skip to content

Commit f400013

Browse files
authored
[RISCV] Lower a shuffle which is nearly identity except one replicated element (#135292)
This can be done with a vrgather.vi/vx, and (possibly) a register move. The alternative is to do a vrgather.vv with a full width index vector. We'd already caught the two operands forms of this shuffle; this patch specifically handles the single operand form. Unfortunately only in abstract, it would be nice if we canonicalized shuffles in some way wouldn't it?
1 parent b03aa29 commit f400013

File tree

2 files changed

+60
-17
lines changed

2 files changed

+60
-17
lines changed

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4726,6 +4726,47 @@ static SDValue getDeinterleaveShiftAndTrunc(const SDLoc &DL, MVT VT,
47264726
DAG.getVectorIdxConstant(0, DL));
47274727
}
47284728

4729+
/// Match a single source shuffle which is an identity except that some
4730+
/// particular element is repeated. This can be lowered as a masked
4731+
/// vrgather.vi/vx. Note that the two source form of this is handled
4732+
/// by the recursive splitting logic and doesn't need special handling.
4733+
static SDValue lowerVECTOR_SHUFFLEAsVRGatherVX(ShuffleVectorSDNode *SVN,
4734+
const RISCVSubtarget &Subtarget,
4735+
SelectionDAG &DAG) {
4736+
4737+
SDLoc DL(SVN);
4738+
MVT VT = SVN->getSimpleValueType(0);
4739+
SDValue V1 = SVN->getOperand(0);
4740+
assert(SVN->getOperand(1).isUndef());
4741+
ArrayRef<int> Mask = SVN->getMask();
4742+
const unsigned NumElts = VT.getVectorNumElements();
4743+
MVT XLenVT = Subtarget.getXLenVT();
4744+
4745+
std::optional<int> SplatIdx;
4746+
for (auto [I, M] : enumerate(Mask)) {
4747+
if (M == -1 || I == (unsigned)M)
4748+
continue;
4749+
if (SplatIdx && *SplatIdx != M)
4750+
return SDValue();
4751+
SplatIdx = M;
4752+
}
4753+
4754+
if (!SplatIdx)
4755+
return SDValue();
4756+
4757+
SmallVector<SDValue> MaskVals;
4758+
for (int MaskIndex : Mask) {
4759+
bool SelectMaskVal = MaskIndex == *SplatIdx;
4760+
MaskVals.push_back(DAG.getConstant(SelectMaskVal, DL, XLenVT));
4761+
}
4762+
assert(MaskVals.size() == NumElts && "Unexpected select-like shuffle");
4763+
MVT MaskVT = MVT::getVectorVT(MVT::i1, NumElts);
4764+
SDValue SelectMask = DAG.getBuildVector(MaskVT, DL, MaskVals);
4765+
SDValue Splat = DAG.getVectorShuffle(VT, DL, V1, DAG.getUNDEF(VT),
4766+
SmallVector<int>(NumElts, *SplatIdx));
4767+
return DAG.getNode(ISD::VSELECT, DL, VT, SelectMask, Splat, V1);
4768+
}
4769+
47294770
// Lower the following shuffle to vslidedown.
47304771
// a)
47314772
// t49: v8i8 = extract_subvector t13, Constant:i64<0>
@@ -5852,6 +5893,9 @@ static SDValue lowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG,
58525893
if (SDValue V = lowerVECTOR_SHUFFLEAsRotate(SVN, DAG, Subtarget))
58535894
return V;
58545895

5896+
if (SDValue V = lowerVECTOR_SHUFFLEAsVRGatherVX(SVN, Subtarget, DAG))
5897+
return V;
5898+
58555899
// Match a spread(4,8) which can be done via extend and shift. Spread(2)
58565900
// is fully covered in interleave(2) above, so it is ignored here.
58575901
if (VT.getScalarSizeInBits() < Subtarget.getELen()) {

llvm/test/CodeGen/RISCV/rvv/fixed-vectors-shuffle-int.ll

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,11 +1419,11 @@ define <8 x i32> @shuffle_v8i32_locally_repeating_neg(<8 x i32> %a) {
14191419
define <8 x i8> @identity_splat0(<8 x i8> %v) {
14201420
; CHECK-LABEL: identity_splat0:
14211421
; CHECK: # %bb.0:
1422-
; CHECK-NEXT: lui a0, %hi(.LCPI88_0)
1423-
; CHECK-NEXT: addi a0, a0, %lo(.LCPI88_0)
1424-
; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
1425-
; CHECK-NEXT: vle8.v v10, (a0)
1426-
; CHECK-NEXT: vrgather.vv v9, v8, v10
1422+
; CHECK-NEXT: li a0, 25
1423+
; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, mu
1424+
; CHECK-NEXT: vmv.s.x v0, a0
1425+
; CHECK-NEXT: vmv1r.v v9, v8
1426+
; CHECK-NEXT: vrgather.vi v9, v8, 0, v0.t
14271427
; CHECK-NEXT: vmv1r.v v8, v9
14281428
; CHECK-NEXT: ret
14291429
%shuf = shufflevector <8 x i8> %v, <8 x i8> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 0, i32 0, i32 5, i32 6, i32 7>
@@ -1433,11 +1433,11 @@ define <8 x i8> @identity_splat0(<8 x i8> %v) {
14331433
define <8 x i8> @identity_splat2(<8 x i8> %v) {
14341434
; CHECK-LABEL: identity_splat2:
14351435
; CHECK: # %bb.0:
1436-
; CHECK-NEXT: lui a0, %hi(.LCPI89_0)
1437-
; CHECK-NEXT: addi a0, a0, %lo(.LCPI89_0)
1438-
; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
1439-
; CHECK-NEXT: vle8.v v10, (a0)
1440-
; CHECK-NEXT: vrgather.vv v9, v8, v10
1436+
; CHECK-NEXT: li a0, 28
1437+
; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, mu
1438+
; CHECK-NEXT: vmv.s.x v0, a0
1439+
; CHECK-NEXT: vmv1r.v v9, v8
1440+
; CHECK-NEXT: vrgather.vi v9, v8, 2, v0.t
14411441
; CHECK-NEXT: vmv1r.v v8, v9
14421442
; CHECK-NEXT: ret
14431443
%shuf = shufflevector <8 x i8> %v, <8 x i8> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 2, i32 2, i32 5, i32 6, i32 7>
@@ -1448,14 +1448,13 @@ define <8 x i8> @identity_splat2(<8 x i8> %v) {
14481448
define <8 x i8> @vmerge_vxm(<8 x i8> %v, i8 %s) {
14491449
; CHECK-LABEL: vmerge_vxm:
14501450
; CHECK: # %bb.0:
1451-
; CHECK-NEXT: lui a1, %hi(.LCPI90_0)
1452-
; CHECK-NEXT: addi a1, a1, %lo(.LCPI90_0)
1453-
; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
1454-
; CHECK-NEXT: vle8.v v10, (a1)
1455-
; CHECK-NEXT: vsetvli zero, zero, e8, mf2, tu, ma
1451+
; CHECK-NEXT: li a1, 25
1452+
; CHECK-NEXT: vsetivli zero, 8, e8, m1, tu, ma
14561453
; CHECK-NEXT: vmv.s.x v8, a0
1457-
; CHECK-NEXT: vsetvli zero, zero, e8, mf2, ta, ma
1458-
; CHECK-NEXT: vrgather.vv v9, v8, v10
1454+
; CHECK-NEXT: vmv.s.x v0, a1
1455+
; CHECK-NEXT: vmv1r.v v9, v8
1456+
; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, mu
1457+
; CHECK-NEXT: vrgather.vi v9, v8, 0, v0.t
14591458
; CHECK-NEXT: vmv1r.v v8, v9
14601459
; CHECK-NEXT: ret
14611460
%ins = insertelement <8 x i8> %v, i8 %s, i32 0

0 commit comments

Comments
 (0)