[RISCV][P-ext] Generalize lowerVECTOR_SHUFFLEAsRV32PNarrowingShift (#210522)

The previous implementation only matches
`shuffle(extract_subvector(src), extract_subvector(src), mask)`.
This patch generalizes it to `shuffle(a, b, mask)`, so we can now lower
it to `PNSRL(concat(a,b), element_bits)` if it is a deinterleave
shuffle. And we use `foldConcatVector` to handle the original pattern
with `extract_subvector`.
This commit is contained in:
Hongyu Chen 2026-07-20 16:51:25 +08:00 committed by GitHub
parent b8300a7665
commit b9b454166e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 142 additions and 31 deletions

View file

@ -2574,3 +2574,71 @@ int16x4_t test_pnziph_i16x4(int32x2_t rs1, int32x2_t rs2) {
uint16x4_t test_pnziph_u16x4(uint32x2_t rs1, uint32x2_t rs2) {
return __riscv_pnziph_u16x4(rs1, rs2);
}
// CHECK-LABEL: test_pzip_i8x8:
// RV32: wzip8p
// RV64: zip8p
int8x8_t test_pzip_i8x8(int8x4_t a, int8x4_t b) {
return __riscv_pzip_i8x8(a, b);
}
// CHECK-LABEL: test_pzip_u8x8:
// RV32: wzip8p
// RV64: zip8p
uint8x8_t test_pzip_u8x8(uint8x4_t a, uint8x4_t b) {
return __riscv_pzip_u8x8(a, b);
}
// CHECK-LABEL: test_pzip_i16x4:
// RV32: wzip16p
// RV64: zip16p
int16x4_t test_pzip_i16x4(int16x2_t a, int16x2_t b) {
return __riscv_pzip_i16x4(a, b);
}
// CHECK-LABEL: test_pzip_u16x4:
// RV32: wzip16p
// RV64: zip16p
uint16x4_t test_pzip_u16x4(uint16x2_t a, uint16x2_t b) {
return __riscv_pzip_u16x4(a, b);
}
// CHECK-LABEL: test_punzipe_i8x4:
// RV32: pncvt.b
// RV64: pncvt.wb
int8x4_t test_punzipe_i8x4(int8x8_t a) { return __riscv_punzipe_i8x4(a); }
// CHECK-LABEL: test_punzipo_i8x4:
// RV32: pncvth.b
// RV64: pncvth.wb
int8x4_t test_punzipo_i8x4(int8x8_t a) { return __riscv_punzipo_i8x4(a); }
// CHECK-LABEL: test_punzipe_u8x4:
// RV32: pncvt.b
// RV64: pncvt.wb
uint8x4_t test_punzipe_u8x4(uint8x8_t a) { return __riscv_punzipe_u8x4(a); }
// CHECK-LABEL: test_punzipo_u8x4:
// RV32: pncvth.b
// RV64: pncvth.wb
uint8x4_t test_punzipo_u8x4(uint8x8_t a) { return __riscv_punzipo_u8x4(a); }
// CHECK-LABEL: test_punzipe_i16x2:
// RV32: pncvt.h
// RV64: pncvt.wh
int16x2_t test_punzipe_i16x2(int16x4_t a) { return __riscv_punzipe_i16x2(a); }
// CHECK-LABEL: test_punzipo_i16x2:
// RV32: pncvth.h
// RV64: pncvth.wh
int16x2_t test_punzipo_i16x2(int16x4_t a) { return __riscv_punzipo_i16x2(a); }
// CHECK-LABEL: test_punzipe_u16x2:
// RV32: pncvt.h
// RV64: pncvt.wh
uint16x2_t test_punzipe_u16x2(uint16x4_t a) { return __riscv_punzipe_u16x2(a); }
// CHECK-LABEL: test_punzipo_u16x2:
// RV32: pncvth.h
// RV64: pncvth.wh
uint16x2_t test_punzipo_u16x2(uint16x4_t a) { return __riscv_punzipo_u16x2(a); }

View file

@ -6457,12 +6457,8 @@ static SDValue lowerVECTOR_SHUFFLEAsPUnzip(ShuffleVectorSDNode *SVN,
return DAG.getNode(Opc, DL, VT, V1, V2);
}
// Match a legalized single-source deinterleave shuffle where the source
// vector was split into two extract_subvectors of the same vector, e.g.
// t20: v4i8 = extract_subvector t5, 0
// t19: v4i8 = extract_subvector t5, 4
// t21: v4i8 = vector_shuffle<0,2,4,6> t20, t19
// and lower it to an RV32 P narrowing shift on the original source.
// Match a legalized deinterleave shuffle on two RV32 vector halves and lower
// it to an RV32 P narrowing shift on the concatenated source.
static SDValue
lowerVECTOR_SHUFFLEAsRV32PNarrowingShift(ShuffleVectorSDNode *SVN,
const RISCVSubtarget &Subtarget,
@ -6473,41 +6469,24 @@ lowerVECTOR_SHUFFLEAsRV32PNarrowingShift(ShuffleVectorSDNode *SVN,
SDValue V1 = SVN->getOperand(0);
SDValue V2 = SVN->getOperand(1);
SDLoc DL(SVN);
unsigned NumElts = VT.getVectorNumElements();
// The inputs should be two extract_subvectors from the same source.
using namespace llvm::SDPatternMatch;
SDValue Src;
int64_t V1Index, V2Index;
if (!sd_match(V1, m_ExtractSubvector(m_Value(Src), m_ConstInt(V1Index))) ||
!sd_match(V2, m_ExtractSubvector(m_Specific(Src), m_ConstInt(V2Index))))
return SDValue();
SDValue Src = foldConcatVector(V1, V2);
if (!Src) {
MVT SrcVT = VT == MVT::v4i8 ? MVT::v8i8 : MVT::v4i16;
Src = DAG.getNode(ISD::CONCAT_VECTORS, DL, SrcVT, V1, V2);
}
// The source vector should be twice the size.
unsigned NumElts = VT.getVectorNumElements();
if (Src.getValueType().getVectorNumElements() != 2 * NumElts)
return SDValue();
// The two extract_subvectors should be from different halves.
if ((V1Index != 0 || V2Index != NumElts) &&
(V1Index != NumElts || V2Index != 0))
return SDValue();
// Translate the shuffle mask, which indexes into the concatenation of V1
// and V2, into indices into Src.
SmallVector<int, 4> Indices(NumElts, -1);
for (auto [I, M] : enumerate(SVN->getMask())) {
if (M < 0)
continue;
int64_t Base = static_cast<unsigned>(M) < NumElts ? V1Index : V2Index;
Indices[I] = Base + (M % NumElts);
}
unsigned Index = 0;
if (!ShuffleVectorInst::isDeInterleaveMaskOfFactor(Indices, 2, Index))
if (!ShuffleVectorInst::isDeInterleaveMaskOfFactor(SVN->getMask(), 2, Index))
return SDValue();
unsigned EltBits = VT.getVectorElementType().getSizeInBits();
SDLoc DL(SVN);
return DAG.getNode(RISCVISD::PNSRL, DL, VT, Src,
DAG.getConstant(Index * EltBits, DL, MVT::i32));
}

View file

@ -254,5 +254,69 @@ define <4 x i16> @test_unzip16hp_v4i16_partial_poison(<4 x i16> %a, <4 x i16> %b
%r = shufflevector <4 x i16> %a, <4 x i16> %b, <4 x i32> <i32 1, i32 3, i32 poison, i32 7>
ret <4 x i16> %r
}
define i32 @test_punzipe_v4i8_coerce(i64 %a.coerce) {
; RV32-LABEL: test_punzipe_v4i8_coerce:
; RV32: # %bb.0:
; RV32-NEXT: pncvt.b a0, a0
; RV32-NEXT: ret
;
; RV64-LABEL: test_punzipe_v4i8_coerce:
; RV64: # %bb.0:
; RV64-NEXT: pncvt.wb a0, a0
; RV64-NEXT: ret
%a = bitcast i64 %a.coerce to <8 x i8>
%r = shufflevector <8 x i8> %a, <8 x i8> poison, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
%ret = bitcast <4 x i8> %r to i32
ret i32 %ret
}
define i32 @test_punzipo_v4i8_coerce(i64 %a.coerce) {
; RV32-LABEL: test_punzipo_v4i8_coerce:
; RV32: # %bb.0:
; RV32-NEXT: pncvth.b a0, a0
; RV32-NEXT: ret
;
; RV64-LABEL: test_punzipo_v4i8_coerce:
; RV64: # %bb.0:
; RV64-NEXT: pncvth.wb a0, a0
; RV64-NEXT: ret
%a = bitcast i64 %a.coerce to <8 x i8>
%r = shufflevector <8 x i8> %a, <8 x i8> poison, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
%ret = bitcast <4 x i8> %r to i32
ret i32 %ret
}
define i32 @test_punzipe_v2i16_coerce(i64 %a.coerce) {
; RV32-LABEL: test_punzipe_v2i16_coerce:
; RV32: # %bb.0:
; RV32-NEXT: pncvt.h a0, a0
; RV32-NEXT: ret
;
; RV64-LABEL: test_punzipe_v2i16_coerce:
; RV64: # %bb.0:
; RV64-NEXT: pncvt.wh a0, a0
; RV64-NEXT: ret
%a = bitcast i64 %a.coerce to <4 x i16>
%r = shufflevector <4 x i16> %a, <4 x i16> poison, <2 x i32> <i32 0, i32 2>
%ret = bitcast <2 x i16> %r to i32
ret i32 %ret
}
define i32 @test_punzipo_v2i16_coerce(i64 %a.coerce) {
; RV32-LABEL: test_punzipo_v2i16_coerce:
; RV32: # %bb.0:
; RV32-NEXT: pncvth.h a0, a0
; RV32-NEXT: ret
;
; RV64-LABEL: test_punzipo_v2i16_coerce:
; RV64: # %bb.0:
; RV64-NEXT: pncvth.wh a0, a0
; RV64-NEXT: ret
%a = bitcast i64 %a.coerce to <4 x i16>
%r = shufflevector <4 x i16> %a, <4 x i16> poison, <2 x i32> <i32 1, i32 3>
%ret = bitcast <2 x i16> %r to i32
ret i32 %ret
}
;; NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line:
; CHECK: {{.*}}