https://github.com/Michael-Chen-NJU updated 
https://github.com/llvm/llvm-project/pull/208394

From 0ba031c82d604204af614a554f2928a69e61b266 Mon Sep 17 00:00:00 2001
From: Michael-Chen-NJU <[email protected]>
Date: Thu, 9 Jul 2026 16:13:28 +0800
Subject: [PATCH 1/2] [Clang][RISCV][P-ext] Support packed widening convert
 intrinsics

---
 clang/lib/Headers/riscv_packed_simd.h         |  27 +++
 clang/test/CodeGen/RISCV/rvp-intrinsics.c     | 162 ++++++++++++++++++
 .../riscv_packed_simd.c                       |  50 ++++++
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   |  62 ++++++-
 .../CodeGen/RISCV/rvp-widening-convert.ll     | 139 +++++++++++++++
 5 files changed, 438 insertions(+), 2 deletions(-)
 create mode 100644 llvm/test/CodeGen/RISCV/rvp-widening-convert.ll

diff --git a/clang/lib/Headers/riscv_packed_simd.h 
b/clang/lib/Headers/riscv_packed_simd.h
index b4de186ac9575..21953fdee1fce 100644
--- a/clang/lib/Headers/riscv_packed_simd.h
+++ b/clang/lib/Headers/riscv_packed_simd.h
@@ -120,6 +120,20 @@ typedef uint32_t uint32x2_t 
__attribute__((__vector_size__(8)));
     return builtin(__rs1);                                                     
\
   }
 
+#define __packed_widen_convert(name, rty, ty)                                  
\
+  static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1) {          
\
+    return __builtin_convertvector(__rs1, rty);                                
\
+  }
+#define __packed_widen_high2(name, rty, ty)                                    
\
+  static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1) {          
\
+    return (rty)__builtin_shufflevector((ty){0}, __rs1, 0, 2, 1, 3);           
\
+  }
+#define __packed_widen_high4(name, rty, ty)                                    
\
+  static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1) {          
\
+    return (rty)__builtin_shufflevector((ty){0}, __rs1, 0, 4, 1, 5, 2, 6, 3,   
\
+                                        7);                                    
\
+  }
+
 /* Packed Reverse: reverse the order of the elements. Lowered to a single
  * rev8/rev16/ppairoe.* by the backend's packed reverse-shuffle handling. */
 #define __packed_reverse2(name, ty)                                            
\
@@ -455,6 +469,16 @@ __packed_unary_op(pnot_u16x4, uint16x4_t, ~)
 __packed_unary_op(pnot_i32x2, int32x2_t, ~)
 __packed_unary_op(pnot_u32x2, uint32x2_t, ~)
 
+/* Packed Widening Convert */
+__packed_widen_convert(pwcvt_i16x4, int16x4_t, int8x4_t)
+__packed_widen_convert(pwcvt_i32x2, int32x2_t, int16x2_t)
+__packed_widen_convert(pwcvtu_u16x4, uint16x4_t, uint8x4_t)
+__packed_widen_convert(pwcvtu_u32x2, uint32x2_t, uint16x2_t)
+__packed_widen_high4(pwcvth_i16x4, int16x4_t, int8x4_t)
+__packed_widen_high4(pwcvth_u16x4, uint16x4_t, uint8x4_t)
+__packed_widen_high2(pwcvth_i32x2, int32x2_t, int16x2_t)
+__packed_widen_high2(pwcvth_u32x2, uint32x2_t, uint16x2_t)
+
 /* Packed Reverse (32-bit) */
 __packed_reverse4(prev_i8x4, int8x4_t)
 __packed_reverse4(prev_u8x4, uint8x4_t)
@@ -597,6 +621,9 @@ __packed_psabs(psabs_i16x4, int16x4_t, 
__builtin_riscv_psabs_i16x4)
 #undef __packed_reduction
 #undef __packed_merge_builtin
 #undef __packed_psabs
+#undef __packed_widen_convert
+#undef __packed_widen_high2
+#undef __packed_widen_high4
 #undef __packed_reverse2
 #undef __packed_reverse4
 #undef __packed_reverse8
diff --git a/clang/test/CodeGen/RISCV/rvp-intrinsics.c 
b/clang/test/CodeGen/RISCV/rvp-intrinsics.c
index 504e88e7ec096..2244cc816913d 100644
--- a/clang/test/CodeGen/RISCV/rvp-intrinsics.c
+++ b/clang/test/CodeGen/RISCV/rvp-intrinsics.c
@@ -7031,3 +7031,165 @@ int8x8_t test_psabs_i8x8(int8x8_t rs1) {
 int16x4_t test_psabs_i16x4(int16x4_t rs1) {
   return __riscv_psabs_i16x4(rs1);
 }
+
+/* Packed Widening Convert */
+
+// RV32-LABEL: define dso_local i64 @test_pwcvt_i16x4(
+// RV32-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[CONV_I:%.*]] = sext <4 x i8> [[TMP0]] to <4 x i16>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[CONV_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP1]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwcvt_i16x4(
+// RV64-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[CONV_I:%.*]] = sext <4 x i8> [[TMP0]] to <4 x i16>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[CONV_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP1]]
+//
+int16x4_t test_pwcvt_i16x4(int8x4_t rs1) {
+  return __riscv_pwcvt_i16x4(rs1);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pwcvt_i32x2(
+// RV32-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[CONV_I:%.*]] = sext <2 x i16> [[TMP0]] to <2 x i32>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <2 x i32> [[CONV_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP1]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwcvt_i32x2(
+// RV64-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[CONV_I:%.*]] = sext <2 x i16> [[TMP0]] to <2 x i32>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <2 x i32> [[CONV_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP1]]
+//
+int32x2_t test_pwcvt_i32x2(int16x2_t rs1) {
+  return __riscv_pwcvt_i32x2(rs1);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pwcvtu_u16x4(
+// RV32-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[CONV_I:%.*]] = zext <4 x i8> [[TMP0]] to <4 x i16>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[CONV_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP1]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwcvtu_u16x4(
+// RV64-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[CONV_I:%.*]] = zext <4 x i8> [[TMP0]] to <4 x i16>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[CONV_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP1]]
+//
+uint16x4_t test_pwcvtu_u16x4(uint8x4_t rs1) {
+  return __riscv_pwcvtu_u16x4(rs1);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pwcvtu_u32x2(
+// RV32-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[CONV_I:%.*]] = zext <2 x i16> [[TMP0]] to <2 x i32>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <2 x i32> [[CONV_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP1]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwcvtu_u32x2(
+// RV64-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[CONV_I:%.*]] = zext <2 x i16> [[TMP0]] to <2 x i32>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <2 x i32> [[CONV_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP1]]
+//
+uint32x2_t test_pwcvtu_u32x2(uint16x2_t rs1) {
+  return __riscv_pwcvtu_u32x2(rs1);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pwcvth_i16x4(
+// RV32-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <4 x i8> zeroinitializer, 
<4 x i8> [[TMP0]], <8 x i32> <i32 0, i32 4, i32 1, i32 5, i32 2, i32 6, i32 3, 
i32 7>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <8 x i8> [[SHUFFLE_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP1]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwcvth_i16x4(
+// RV64-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <4 x i8> zeroinitializer, 
<4 x i8> [[TMP0]], <8 x i32> <i32 0, i32 4, i32 1, i32 5, i32 2, i32 6, i32 3, 
i32 7>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <8 x i8> [[SHUFFLE_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP1]]
+//
+int16x4_t test_pwcvth_i16x4(int8x4_t rs1) {
+  return __riscv_pwcvth_i16x4(rs1);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pwcvth_u16x4(
+// RV32-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <4 x i8> zeroinitializer, 
<4 x i8> [[TMP0]], <8 x i32> <i32 0, i32 4, i32 1, i32 5, i32 2, i32 6, i32 3, 
i32 7>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <8 x i8> [[SHUFFLE_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP1]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwcvth_u16x4(
+// RV64-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <4 x i8> zeroinitializer, 
<4 x i8> [[TMP0]], <8 x i32> <i32 0, i32 4, i32 1, i32 5, i32 2, i32 6, i32 3, 
i32 7>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <8 x i8> [[SHUFFLE_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP1]]
+//
+uint16x4_t test_pwcvth_u16x4(uint8x4_t rs1) {
+  return __riscv_pwcvth_u16x4(rs1);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pwcvth_i32x2(
+// RV32-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <2 x i16> zeroinitializer, 
<2 x i16> [[TMP0]], <4 x i32> <i32 0, i32 2, i32 1, i32 3>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP1]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwcvth_i32x2(
+// RV64-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <2 x i16> zeroinitializer, 
<2 x i16> [[TMP0]], <4 x i32> <i32 0, i32 2, i32 1, i32 3>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP1]]
+//
+int32x2_t test_pwcvth_i32x2(int16x2_t rs1) {
+  return __riscv_pwcvth_i32x2(rs1);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pwcvth_u32x2(
+// RV32-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <2 x i16> zeroinitializer, 
<2 x i16> [[TMP0]], <4 x i32> <i32 0, i32 2, i32 1, i32 3>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP1]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwcvth_u32x2(
+// RV64-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <2 x i16> zeroinitializer, 
<2 x i16> [[TMP0]], <4 x i32> <i32 0, i32 2, i32 1, i32 3>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <4 x i16> [[SHUFFLE_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP1]]
+//
+uint32x2_t test_pwcvth_u32x2(uint16x2_t rs1) {
+  return __riscv_pwcvth_u32x2(rs1);
+}
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 3e53c097888f0..fb2e245f83282 100644
--- a/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
+++ b/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
@@ -2083,6 +2083,56 @@ uint64_t test_predsumu_u32x2_u64(uint32x2_t a, uint64_t 
b) {
   return __riscv_predsumu_u32x2_u64(a, b);
 }
 
+// CHECK-LABEL: test_pwcvt_i16x4:
+// RV32:        pwcvt.b
+// RV64:        pwcvtu.wb
+// RV64:        psext.h.b
+int16x4_t test_pwcvt_i16x4(int8x4_t rs1) { return __riscv_pwcvt_i16x4(rs1); }
+
+// CHECK-LABEL: test_pwcvt_i32x2:
+// RV32:        pwcvt.h
+// RV64:        pwcvtu.wh
+// RV64:        psext.w.h
+int32x2_t test_pwcvt_i32x2(int16x2_t rs1) { return __riscv_pwcvt_i32x2(rs1); }
+
+// CHECK-LABEL: test_pwcvtu_u16x4:
+// RV32:        pwcvtu.b
+// RV64:        pwcvtu.wb
+uint16x4_t test_pwcvtu_u16x4(uint8x4_t rs1) {
+  return __riscv_pwcvtu_u16x4(rs1);
+}
+
+// CHECK-LABEL: test_pwcvtu_u32x2:
+// RV32:        pwcvtu.h
+// RV64:        pwcvtu.wh
+uint32x2_t test_pwcvtu_u32x2(uint16x2_t rs1) {
+  return __riscv_pwcvtu_u32x2(rs1);
+}
+
+// CHECK-LABEL: test_pwcvth_i16x4:
+// RV32:        pwcvth.b
+// RV64:        pwcvth.wb
+int16x4_t test_pwcvth_i16x4(int8x4_t rs1) { return __riscv_pwcvth_i16x4(rs1); }
+
+// CHECK-LABEL: test_pwcvth_u16x4:
+// RV32:        pwcvth.b
+// RV64:        pwcvth.wb
+uint16x4_t test_pwcvth_u16x4(uint8x4_t rs1) {
+  return __riscv_pwcvth_u16x4(rs1);
+}
+
+// CHECK-LABEL: test_pwcvth_i32x2:
+// RV32:        pwcvth.h
+// RV64:        pwcvth.wh
+int32x2_t test_pwcvth_i32x2(int16x2_t rs1) { return __riscv_pwcvth_i32x2(rs1); 
}
+
+// CHECK-LABEL: test_pwcvth_u32x2:
+// RV32:        pwcvth.h
+// RV64:        pwcvth.wh
+uint32x2_t test_pwcvth_u32x2(uint16x2_t rs1) {
+  return __riscv_pwcvth_u32x2(rs1);
+}
+
 // CHECK-LABEL: test_pmerge_merge_u8x4:
 // CHECK:        merge
 uint8x4_t test_pmerge_merge_u8x4(uint8x4_t rd, uint8x4_t rs1, uint8x4_t rs2) {
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp 
b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index fda994a04b00f..14ed09815802d 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -6352,11 +6352,69 @@ SDValue 
RISCVTargetLowering::lowerVECTOR_SHUFFLE(SDValue Op,
   unsigned NumElts = VT.getVectorNumElements();
   ShuffleVectorSDNode *SVN = cast<ShuffleVectorSDNode>(Op.getNode());
 
-  // Select an element reverse shuffle to VECTOR_REVERSE 
(rev8/rev16/ppairoe.*).
+  // Select RVP-specific packed shuffles before falling back to the generic
+  // fixed/scalable-vector lowering below.
   if (Subtarget.hasStdExtP() && !Subtarget.hasVInstructions()) {
+    ArrayRef<int> Mask = SVN->getMask();
+
+    // Match the IR produced by the packed widening high-half convert header
+    // intrinsics:
+    //   shufflevector zeroinitializer, src, <0, N, 1, N+1, ...>
+    //   bitcast to the widened vector type
+    // This places each source element in the high half of the widened element.
+    // Lower it to PZIP with a zero first operand and let tablegen select
+    // pwcvth.* via zip*p/wzip*p.
+    auto IsBuildVectorAllZeros = [](SDValue V) {
+      if (V.getOpcode() == ISD::BUILD_VECTOR)
+        return ISD::isBuildVectorAllZeros(V.getNode());
+      return V.getOpcode() == ISD::SPLAT_VECTOR &&
+             isNullConstant(V.getOperand(0));
+    };
+
+    auto IsWidenHighMask = [&](unsigned SrcNumElts) {
+      for (unsigned I = 0; I != SrcNumElts; ++I)
+        if (Mask[2 * I] != (int)I || Mask[2 * I + 1] != (int)(NumElts + I))
+          return false;
+      return true;
+    };
+    auto GetZeroVector = [&]() { return DAG.getConstant(0, DL, VT); };
+
+    SDValue Src = V2;
+    if (V2.getOpcode() == ISD::CONCAT_VECTORS && V2.getOperand(1).isUndef())
+      Src = V2.getOperand(0);
+    MVT SrcVT = Src.getSimpleValueType();
+    if (IsBuildVectorAllZeros(V1) && SrcVT.isFixedLengthVector() &&
+        SrcVT.getVectorNumElements() * 2 == NumElts &&
+        V2.getSimpleValueType().getVectorNumElements() == NumElts) {
+      unsigned SrcNumElts = SrcVT.getVectorNumElements();
+      if (IsWidenHighMask(SrcNumElts) &&
+          (SrcVT == MVT::v4i8 || SrcVT == MVT::v2i16)) {
+        if (Subtarget.is64Bit()) {
+          MVT WideSrcVT = SrcVT == MVT::v4i8 ? MVT::v8i8 : MVT::v4i16;
+          SDValue WideSrc = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64,
+                                        DAG.getBitcast(MVT::i32, Src));
+          Src = DAG.getBitcast(WideSrcVT, WideSrc);
+        } else {
+          Src = DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, Src,
+                            DAG.getUNDEF(SrcVT));
+        }
+        return DAG.getNode(RISCVISD::PZIP, DL, VT, GetZeroVector(), Src);
+      }
+    }
+
+    if (IsBuildVectorAllZeros(V1) && V2.getSimpleValueType() == VT &&
+        (VT == MVT::v8i8 || VT == MVT::v4i16)) {
+      unsigned SrcNumElts = NumElts / 2;
+      if (IsWidenHighMask(SrcNumElts)) {
+        Src = V2;
+        return DAG.getNode(RISCVISD::PZIP, DL, VT, GetZeroVector(), Src);
+      }
+    }
+
+    // Select an element reverse shuffle to VECTOR_REVERSE. The tablegen
+    // patterns select rev8/rev16/ppairoe.* from VECTOR_REVERSE.
     // Reverse of the low L lanes, higher lanes poison. L == NumElts is a plain
     // reverse; L == NumElts/2 is a widened RV64 v4i8/v2i16 reverse.
-    ArrayRef<int> Mask = SVN->getMask();
     auto IsLowReverse = [&](unsigned L) {
       return V2.isUndef() &&
              ShuffleVectorInst::isReverseMask(Mask.take_front(L), L) &&
diff --git a/llvm/test/CodeGen/RISCV/rvp-widening-convert.ll 
b/llvm/test/CodeGen/RISCV/rvp-widening-convert.ll
new file mode 100644
index 0000000000000..6f6775f180f25
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvp-widening-convert.ll
@@ -0,0 +1,139 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; This file covers packed widening conversions from the generic IR generated by
+; the C intrinsic header.
+; RUN: llc -mtriple=riscv32 -mattr=+experimental-p,+m,+zbb \
+; RUN:   -verify-machineinstrs < %s | \
+; RUN:   FileCheck %s --check-prefixes=CHECK,RV32
+; RUN: llc -mtriple=riscv64 -mattr=+experimental-p,+m,+zbb \
+; RUN:   -verify-machineinstrs < %s | \
+; RUN:   FileCheck %s --check-prefixes=CHECK,RV64
+
+define <4 x i16> @test_pwcvt_v4i8(<4 x i8> %a) {
+; RV32-LABEL: test_pwcvt_v4i8:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pwcvt.b a0, a0
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pwcvt_v4i8:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pwcvtu.wb a0, a0
+; RV64-NEXT:    psext.h.b a0, a0
+; RV64-NEXT:    ret
+  %res = sext <4 x i8> %a to <4 x i16>
+  ret <4 x i16> %res
+}
+
+define <2 x i32> @test_pwcvt_v2i16(<2 x i16> %a) {
+; RV32-LABEL: test_pwcvt_v2i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pwcvt.h a0, a0
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pwcvt_v2i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pwcvtu.wh a0, a0
+; RV64-NEXT:    psext.w.h a0, a0
+; RV64-NEXT:    ret
+  %res = sext <2 x i16> %a to <2 x i32>
+  ret <2 x i32> %res
+}
+
+define <4 x i16> @test_pwcvtu_v4i8(<4 x i8> %a) {
+; RV32-LABEL: test_pwcvtu_v4i8:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pwcvtu.b a0, a0
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pwcvtu_v4i8:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pwcvtu.wb a0, a0
+; RV64-NEXT:    ret
+  %res = zext <4 x i8> %a to <4 x i16>
+  ret <4 x i16> %res
+}
+
+define <2 x i32> @test_pwcvtu_v2i16(<2 x i16> %a) {
+; RV32-LABEL: test_pwcvtu_v2i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pwcvtu.h a0, a0
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pwcvtu_v2i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pwcvtu.wh a0, a0
+; RV64-NEXT:    ret
+  %res = zext <2 x i16> %a to <2 x i32>
+  ret <2 x i32> %res
+}
+
+define <4 x i16> @test_pwcvth_v4i8(<4 x i8> %a) {
+; RV32-LABEL: test_pwcvth_v4i8:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pwcvth.b a0, a0
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pwcvth_v4i8:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pwcvth.wb a0, a0
+; RV64-NEXT:    ret
+  %shuffle = shufflevector <4 x i8> zeroinitializer, <4 x i8> %a, <8 x i32> 
<i32 0, i32 4, i32 1, i32 5, i32 2, i32 6, i32 3, i32 7>
+  %res = bitcast <8 x i8> %shuffle to <4 x i16>
+  ret <4 x i16> %res
+}
+
+define <2 x i32> @test_pwcvth_v2i16(<2 x i16> %a) {
+; RV32-LABEL: test_pwcvth_v2i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pwcvth.h a0, a0
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pwcvth_v2i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pwcvth.wh a0, a0
+; RV64-NEXT:    ret
+  %shuffle = shufflevector <2 x i16> zeroinitializer, <2 x i16> %a, <4 x i32> 
<i32 0, i32 2, i32 1, i32 3>
+  %res = bitcast <4 x i16> %shuffle to <2 x i32>
+  ret <2 x i32> %res
+}
+
+define i64 @test_pwcvth_v4i8_abi(i32 %a) {
+; RV32-LABEL: test_pwcvth_v4i8_abi:
+; RV32:       # %bb.0:
+; RV32-NEXT:    addi sp, sp, -16
+; RV32-NEXT:    .cfi_def_cfa_offset 16
+; RV32-NEXT:    pwcvth.b a0, a0
+; RV32-NEXT:    addi sp, sp, 16
+; RV32-NEXT:    .cfi_def_cfa_offset 0
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pwcvth_v4i8_abi:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pwcvth.wb a0, a0
+; RV64-NEXT:    ret
+  %vec = bitcast i32 %a to <4 x i8>
+  %shuffle = shufflevector <4 x i8> zeroinitializer, <4 x i8> %vec, <8 x i32> 
<i32 0, i32 4, i32 1, i32 5, i32 2, i32 6, i32 3, i32 7>
+  %res = bitcast <8 x i8> %shuffle to i64
+  ret i64 %res
+}
+
+define i64 @test_pwcvth_v2i16_abi(i32 %a) {
+; RV32-LABEL: test_pwcvth_v2i16_abi:
+; RV32:       # %bb.0:
+; RV32-NEXT:    addi sp, sp, -16
+; RV32-NEXT:    .cfi_def_cfa_offset 16
+; RV32-NEXT:    pwcvth.h a0, a0
+; RV32-NEXT:    addi sp, sp, 16
+; RV32-NEXT:    .cfi_def_cfa_offset 0
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pwcvth_v2i16_abi:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pwcvth.wh a0, a0
+; RV64-NEXT:    ret
+  %vec = bitcast i32 %a to <2 x i16>
+  %shuffle = shufflevector <2 x i16> zeroinitializer, <2 x i16> %vec, <4 x 
i32> <i32 0, i32 2, i32 1, i32 3>
+  %res = bitcast <4 x i16> %shuffle to i64
+  ret i64 %res
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add 
tests below this line:
+; CHECK: {{.*}}

From a978bb47883c918acf01f33fe12634b6b373cc7a Mon Sep 17 00:00:00 2001
From: Michael-Chen-NJU <[email protected]>
Date: Fri, 10 Jul 2026 16:22:25 +0800
Subject: [PATCH 2/2] [RISCV][P-ext] Address widening convert review feedback

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   | 21 ++++------
 .../CodeGen/RISCV/rvp-widening-convert.ll     | 40 -------------------
 2 files changed, 8 insertions(+), 53 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp 
b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 14ed09815802d..be9cb57a0d87f 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -6377,28 +6377,22 @@ SDValue 
RISCVTargetLowering::lowerVECTOR_SHUFFLE(SDValue Op,
           return false;
       return true;
     };
-    auto GetZeroVector = [&]() { return DAG.getConstant(0, DL, VT); };
 
     SDValue Src = V2;
     if (V2.getOpcode() == ISD::CONCAT_VECTORS && V2.getOperand(1).isUndef())
       Src = V2.getOperand(0);
     MVT SrcVT = Src.getSimpleValueType();
-    if (IsBuildVectorAllZeros(V1) && SrcVT.isFixedLengthVector() &&
+    if (Subtarget.isRV32() && IsBuildVectorAllZeros(V1) &&
+        SrcVT.isFixedLengthVector() &&
         SrcVT.getVectorNumElements() * 2 == NumElts &&
         V2.getSimpleValueType().getVectorNumElements() == NumElts) {
       unsigned SrcNumElts = SrcVT.getVectorNumElements();
       if (IsWidenHighMask(SrcNumElts) &&
           (SrcVT == MVT::v4i8 || SrcVT == MVT::v2i16)) {
-        if (Subtarget.is64Bit()) {
-          MVT WideSrcVT = SrcVT == MVT::v4i8 ? MVT::v8i8 : MVT::v4i16;
-          SDValue WideSrc = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64,
-                                        DAG.getBitcast(MVT::i32, Src));
-          Src = DAG.getBitcast(WideSrcVT, WideSrc);
-        } else {
-          Src = DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, Src,
-                            DAG.getUNDEF(SrcVT));
-        }
-        return DAG.getNode(RISCVISD::PZIP, DL, VT, GetZeroVector(), Src);
+        Src = DAG.getNode(ISD::CONCAT_VECTORS, DL, VT, Src,
+                          DAG.getUNDEF(SrcVT));
+        return DAG.getNode(RISCVISD::PZIP, DL, VT,
+                           DAG.getConstant(0, DL, VT), Src);
       }
     }
 
@@ -6407,7 +6401,8 @@ SDValue RISCVTargetLowering::lowerVECTOR_SHUFFLE(SDValue 
Op,
       unsigned SrcNumElts = NumElts / 2;
       if (IsWidenHighMask(SrcNumElts)) {
         Src = V2;
-        return DAG.getNode(RISCVISD::PZIP, DL, VT, GetZeroVector(), Src);
+        return DAG.getNode(RISCVISD::PZIP, DL, VT,
+                           DAG.getConstant(0, DL, VT), Src);
       }
     }
 
diff --git a/llvm/test/CodeGen/RISCV/rvp-widening-convert.ll 
b/llvm/test/CodeGen/RISCV/rvp-widening-convert.ll
index 6f6775f180f25..e2f88d0757c00 100644
--- a/llvm/test/CodeGen/RISCV/rvp-widening-convert.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-widening-convert.ll
@@ -95,45 +95,5 @@ define <2 x i32> @test_pwcvth_v2i16(<2 x i16> %a) {
   %res = bitcast <4 x i16> %shuffle to <2 x i32>
   ret <2 x i32> %res
 }
-
-define i64 @test_pwcvth_v4i8_abi(i32 %a) {
-; RV32-LABEL: test_pwcvth_v4i8_abi:
-; RV32:       # %bb.0:
-; RV32-NEXT:    addi sp, sp, -16
-; RV32-NEXT:    .cfi_def_cfa_offset 16
-; RV32-NEXT:    pwcvth.b a0, a0
-; RV32-NEXT:    addi sp, sp, 16
-; RV32-NEXT:    .cfi_def_cfa_offset 0
-; RV32-NEXT:    ret
-;
-; RV64-LABEL: test_pwcvth_v4i8_abi:
-; RV64:       # %bb.0:
-; RV64-NEXT:    pwcvth.wb a0, a0
-; RV64-NEXT:    ret
-  %vec = bitcast i32 %a to <4 x i8>
-  %shuffle = shufflevector <4 x i8> zeroinitializer, <4 x i8> %vec, <8 x i32> 
<i32 0, i32 4, i32 1, i32 5, i32 2, i32 6, i32 3, i32 7>
-  %res = bitcast <8 x i8> %shuffle to i64
-  ret i64 %res
-}
-
-define i64 @test_pwcvth_v2i16_abi(i32 %a) {
-; RV32-LABEL: test_pwcvth_v2i16_abi:
-; RV32:       # %bb.0:
-; RV32-NEXT:    addi sp, sp, -16
-; RV32-NEXT:    .cfi_def_cfa_offset 16
-; RV32-NEXT:    pwcvth.h a0, a0
-; RV32-NEXT:    addi sp, sp, 16
-; RV32-NEXT:    .cfi_def_cfa_offset 0
-; RV32-NEXT:    ret
-;
-; RV64-LABEL: test_pwcvth_v2i16_abi:
-; RV64:       # %bb.0:
-; RV64-NEXT:    pwcvth.wh a0, a0
-; RV64-NEXT:    ret
-  %vec = bitcast i32 %a to <2 x i16>
-  %shuffle = shufflevector <2 x i16> zeroinitializer, <2 x i16> %vec, <4 x 
i32> <i32 0, i32 2, i32 1, i32 3>
-  %res = bitcast <4 x i16> %shuffle to i64
-  ret i64 %res
-}
 ;; NOTE: These prefixes are unused and the list is autogenerated. Do not add 
tests below this line:
 ; CHECK: {{.*}}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to