[clang] [RISCV][P-Ext] Unify pncvt(h) intrinsics between RV32 and RV64. (PR #210996)

Craig Topper via cfe-commits cfe-commits at lists.llvm.org
Sat Jul 25 12:07:28 PDT 2026


https://github.com/topperc updated https://github.com/llvm/llvm-project/pull/210996

>From 17529f487706ce7609e826aae4ebe1ff1533793f Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Tue, 21 Jul 2026 02:00:53 -0700
Subject: [PATCH] [RISCV][P-Ext] Unify pncvt(h) intrinsics between RV32 and
 RV64.

Use __builtin_convertvector for pncvt and __builtin_shufflevector
for pncvth.

Alternatively we could use shift+__builtin_convertvector for pncvth
but that requires combining psrl+unzip(8/16)p to unzip(8/16)hp. I'm
not sure which is better right now.
---
 clang/lib/Headers/riscv_packed_simd.h     | 23 +---------
 clang/test/CodeGen/RISCV/rvp-intrinsics.c | 52 +++++++++++------------
 2 files changed, 26 insertions(+), 49 deletions(-)

diff --git a/clang/lib/Headers/riscv_packed_simd.h b/clang/lib/Headers/riscv_packed_simd.h
index 7d40f046eba80..b8372cf0a0ac3 100644
--- a/clang/lib/Headers/riscv_packed_simd.h
+++ b/clang/lib/Headers/riscv_packed_simd.h
@@ -134,24 +134,6 @@ typedef uint32_t uint32x2_t __attribute__((__vector_size__(8)));
                                         7);                                    \
   }
 
-#if __riscv_xlen == 64
-#define __packed_narrow_even2(name, rty, ty, sty)                              \
-  static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1) {          \
-    return __builtin_shufflevector((sty)__rs1, (sty)__rs1, 0, 2);              \
-  }
-#define __packed_narrow_even4(name, rty, ty, sty)                              \
-  static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1) {          \
-    return __builtin_shufflevector((sty)__rs1, (sty)__rs1, 0, 2, 4, 6);        \
-  }
-#define __packed_narrow_odd2(name, rty, ty, sty, uty)                          \
-  static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1) {          \
-    return __builtin_shufflevector((sty)__rs1, (sty)__rs1, 1, 3);              \
-  }
-#define __packed_narrow_odd4(name, rty, ty, sty, uty)                          \
-  static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1) {          \
-    return __builtin_shufflevector((sty)__rs1, (sty)__rs1, 1, 3, 5, 7);        \
-  }
-#else
 #define __packed_narrow_even2(name, rty, ty, sty)                              \
   static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1) {          \
     return __builtin_convertvector(__rs1, rty);                                \
@@ -162,13 +144,12 @@ typedef uint32_t uint32x2_t __attribute__((__vector_size__(8)));
   }
 #define __packed_narrow_odd2(name, rty, ty, sty, uty)                          \
   static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1) {          \
-    return __builtin_convertvector(((uty)__rs1) >> 16, rty);                   \
+    return __builtin_shufflevector((sty)__rs1, (sty)__rs1, 1, 3);              \
   }
 #define __packed_narrow_odd4(name, rty, ty, sty, uty)                          \
   static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1) {          \
-    return __builtin_convertvector(((uty)__rs1) >> 8, rty);                    \
+    return __builtin_shufflevector((sty)__rs1, (sty)__rs1, 1, 3, 5, 7);        \
   }
-#endif
 
 /* Packed Reverse: reverse the order of the elements. Lowered to a single
  * rev8/rev16/ppairoe.* by the backend's packed reverse-shuffle handling. */
diff --git a/clang/test/CodeGen/RISCV/rvp-intrinsics.c b/clang/test/CodeGen/RISCV/rvp-intrinsics.c
index 816409268ce02..5b2d081603019 100644
--- a/clang/test/CodeGen/RISCV/rvp-intrinsics.c
+++ b/clang/test/CodeGen/RISCV/rvp-intrinsics.c
@@ -7207,9 +7207,9 @@ uint32x2_t test_pwcvth_u32x2(uint16x2_t rs1) {
 // RV64-LABEL: define dso_local i32 @test_pncvt_i8x4(
 // RV64-SAME: i64 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
 // RV64-NEXT:  [[ENTRY:.*:]]
-// RV64-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <8 x i8>
-// RV64-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <8 x i8> [[TMP0]], <8 x i8> poison, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
-// RV64-NEXT:    [[TMP1:%.*]] = bitcast <4 x i8> [[SHUFFLE_I]] to i32
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
+// RV64-NEXT:    [[CONV_I:%.*]] = trunc <4 x i16> [[TMP0]] to <4 x i8>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <4 x i8> [[CONV_I]] to i32
 // RV64-NEXT:    ret i32 [[TMP1]]
 //
 int8x4_t test_pncvt_i8x4(int16x4_t rs1) { return __riscv_pncvt_i8x4(rs1); }
@@ -7225,9 +7225,9 @@ int8x4_t test_pncvt_i8x4(int16x4_t rs1) { return __riscv_pncvt_i8x4(rs1); }
 // RV64-LABEL: define dso_local i32 @test_pncvt_u8x4(
 // RV64-SAME: i64 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
 // RV64-NEXT:  [[ENTRY:.*:]]
-// RV64-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <8 x i8>
-// RV64-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <8 x i8> [[TMP0]], <8 x i8> poison, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
-// RV64-NEXT:    [[TMP1:%.*]] = bitcast <4 x i8> [[SHUFFLE_I]] to i32
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
+// RV64-NEXT:    [[CONV_I:%.*]] = trunc <4 x i16> [[TMP0]] to <4 x i8>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <4 x i8> [[CONV_I]] to i32
 // RV64-NEXT:    ret i32 [[TMP1]]
 //
 uint8x4_t test_pncvt_u8x4(uint16x4_t rs1) { return __riscv_pncvt_u8x4(rs1); }
@@ -7243,9 +7243,9 @@ uint8x4_t test_pncvt_u8x4(uint16x4_t rs1) { return __riscv_pncvt_u8x4(rs1); }
 // RV64-LABEL: define dso_local i32 @test_pncvt_i16x2(
 // RV64-SAME: i64 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
 // RV64-NEXT:  [[ENTRY:.*:]]
-// RV64-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
-// RV64-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <4 x i16> [[TMP0]], <4 x i16> poison, <2 x i32> <i32 0, i32 2>
-// RV64-NEXT:    [[TMP1:%.*]] = bitcast <2 x i16> [[SHUFFLE_I]] to i32
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <2 x i32>
+// RV64-NEXT:    [[CONV_I:%.*]] = trunc <2 x i32> [[TMP0]] to <2 x i16>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <2 x i16> [[CONV_I]] to i32
 // RV64-NEXT:    ret i32 [[TMP1]]
 //
 int16x2_t test_pncvt_i16x2(int32x2_t rs1) { return __riscv_pncvt_i16x2(rs1); }
@@ -7261,9 +7261,9 @@ int16x2_t test_pncvt_i16x2(int32x2_t rs1) { return __riscv_pncvt_i16x2(rs1); }
 // RV64-LABEL: define dso_local i32 @test_pncvt_u16x2(
 // RV64-SAME: i64 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
 // RV64-NEXT:  [[ENTRY:.*:]]
-// RV64-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
-// RV64-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <4 x i16> [[TMP0]], <4 x i16> poison, <2 x i32> <i32 0, i32 2>
-// RV64-NEXT:    [[TMP1:%.*]] = bitcast <2 x i16> [[SHUFFLE_I]] to i32
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <2 x i32>
+// RV64-NEXT:    [[CONV_I:%.*]] = trunc <2 x i32> [[TMP0]] to <2 x i16>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast <2 x i16> [[CONV_I]] to i32
 // RV64-NEXT:    ret i32 [[TMP1]]
 //
 uint16x2_t test_pncvt_u16x2(uint32x2_t rs1) {
@@ -7273,10 +7273,9 @@ uint16x2_t test_pncvt_u16x2(uint32x2_t rs1) {
 // RV32-LABEL: define dso_local i32 @test_pncvth_i8x4(
 // RV32-SAME: i64 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
 // RV32-NEXT:  [[ENTRY:.*:]]
-// RV32-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
-// RV32-NEXT:    [[SHR_I:%.*]] = lshr <4 x i16> [[TMP0]], splat (i16 8)
-// RV32-NEXT:    [[CONV_I:%.*]] = trunc nuw <4 x i16> [[SHR_I]] to <4 x i8>
-// RV32-NEXT:    [[TMP1:%.*]] = bitcast <4 x i8> [[CONV_I]] to i32
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <8 x i8>
+// RV32-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <8 x i8> [[TMP0]], <8 x i8> poison, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <4 x i8> [[SHUFFLE_I]] to i32
 // RV32-NEXT:    ret i32 [[TMP1]]
 //
 // RV64-LABEL: define dso_local i32 @test_pncvth_i8x4(
@@ -7292,10 +7291,9 @@ int8x4_t test_pncvth_i8x4(int16x4_t rs1) { return __riscv_pncvth_i8x4(rs1); }
 // RV32-LABEL: define dso_local i32 @test_pncvth_u8x4(
 // RV32-SAME: i64 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
 // RV32-NEXT:  [[ENTRY:.*:]]
-// RV32-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
-// RV32-NEXT:    [[SHR_I:%.*]] = lshr <4 x i16> [[TMP0]], splat (i16 8)
-// RV32-NEXT:    [[CONV_I:%.*]] = trunc nuw <4 x i16> [[SHR_I]] to <4 x i8>
-// RV32-NEXT:    [[TMP1:%.*]] = bitcast <4 x i8> [[CONV_I]] to i32
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <8 x i8>
+// RV32-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <8 x i8> [[TMP0]], <8 x i8> poison, <4 x i32> <i32 1, i32 3, i32 5, i32 7>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <4 x i8> [[SHUFFLE_I]] to i32
 // RV32-NEXT:    ret i32 [[TMP1]]
 //
 // RV64-LABEL: define dso_local i32 @test_pncvth_u8x4(
@@ -7313,10 +7311,9 @@ uint8x4_t test_pncvth_u8x4(uint16x4_t rs1) {
 // RV32-LABEL: define dso_local i32 @test_pncvth_i16x2(
 // RV32-SAME: i64 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
 // RV32-NEXT:  [[ENTRY:.*:]]
-// RV32-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <2 x i32>
-// RV32-NEXT:    [[SHR_I:%.*]] = lshr <2 x i32> [[TMP0]], splat (i32 16)
-// RV32-NEXT:    [[CONV_I:%.*]] = trunc nuw <2 x i32> [[SHR_I]] to <2 x i16>
-// RV32-NEXT:    [[TMP1:%.*]] = bitcast <2 x i16> [[CONV_I]] to i32
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
+// RV32-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <4 x i16> [[TMP0]], <4 x i16> poison, <2 x i32> <i32 1, i32 3>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <2 x i16> [[SHUFFLE_I]] to i32
 // RV32-NEXT:    ret i32 [[TMP1]]
 //
 // RV64-LABEL: define dso_local i32 @test_pncvth_i16x2(
@@ -7334,10 +7331,9 @@ int16x2_t test_pncvth_i16x2(int32x2_t rs1) {
 // RV32-LABEL: define dso_local i32 @test_pncvth_u16x2(
 // RV32-SAME: i64 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
 // RV32-NEXT:  [[ENTRY:.*:]]
-// RV32-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <2 x i32>
-// RV32-NEXT:    [[SHR_I:%.*]] = lshr <2 x i32> [[TMP0]], splat (i32 16)
-// RV32-NEXT:    [[CONV_I:%.*]] = trunc nuw <2 x i32> [[SHR_I]] to <2 x i16>
-// RV32-NEXT:    [[TMP1:%.*]] = bitcast <2 x i16> [[CONV_I]] to i32
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
+// RV32-NEXT:    [[SHUFFLE_I:%.*]] = shufflevector <4 x i16> [[TMP0]], <4 x i16> poison, <2 x i32> <i32 1, i32 3>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast <2 x i16> [[SHUFFLE_I]] to i32
 // RV32-NEXT:    ret i32 [[TMP1]]
 //
 // RV64-LABEL: define dso_local i32 @test_pncvth_u16x2(



More information about the cfe-commits mailing list