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

Hongyu Chen via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 20 01:12:11 PDT 2026


https://github.com/XChy updated https://github.com/llvm/llvm-project/pull/210522

>From 595bef1bb8aa58e270b2224ba5f40ec8c0321dda Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Sat, 18 Jul 2026 23:59:48 +0800
Subject: [PATCH 1/2] [RISCV][P-ext] Generalize
 lowerVECTOR_SHUFFLEAsRV32PNarrowingShift

---
 .../riscv_packed_simd.c                       | 84 +++++++++++++++++++
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   | 41 +++------
 llvm/test/CodeGen/RISCV/rvp-zip.ll            | 64 ++++++++++++++
 3 files changed, 158 insertions(+), 31 deletions(-)

diff --git a/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c b/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
index 6aa08d6a58c00..b2990531e0257 100644
--- a/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
+++ b/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
@@ -2574,3 +2574,87 @@ 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);
+}
\ No newline at end of file
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 9aaee1e47eab3..0e33e140aaa72 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -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));
 }
diff --git a/llvm/test/CodeGen/RISCV/rvp-zip.ll b/llvm/test/CodeGen/RISCV/rvp-zip.ll
index 766db01267521..ecb2fc8f01be6 100644
--- a/llvm/test/CodeGen/RISCV/rvp-zip.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-zip.ll
@@ -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: {{.*}}

>From c940ef70d9f99fb4313996a6cc25db45f6e6fef1 Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Sun, 19 Jul 2026 00:17:46 +0800
Subject: [PATCH 2/2] format

---
 .../riscv_packed_simd.c                       | 32 +++++--------------
 1 file changed, 8 insertions(+), 24 deletions(-)

diff --git a/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c b/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
index b2990531e0257..2af196cdaadc0 100644
--- a/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
+++ b/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
@@ -2606,55 +2606,39 @@ uint16x4_t test_pzip_u16x4(uint16x2_t a, uint16x2_t 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);
-}
+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);
-}
+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);
-}
+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);
-}
+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);
-}
+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);
-}
+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);
-}
+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);
-}
\ No newline at end of file
+uint16x2_t test_punzipo_u16x2(uint16x4_t a) { return __riscv_punzipo_u16x2(a); }



More information about the llvm-commits mailing list