[clang] [llvm] [RISCV][P-ext] Support Packed Absolute Value and Absolute Difference (PR #203840)

via cfe-commits cfe-commits at lists.llvm.org
Mon Jun 15 00:58:56 PDT 2026


https://github.com/TelGome created https://github.com/llvm/llvm-project/pull/203840

This pr support RISC-V P extension intrinsics [Packed Absolute Value and Absolute Difference](https://github.com/riscv/riscv-p-spec/blob/master/P-ext-intrinsics.adoc#packed-absolute-value-and-absolute-difference)

>From ce5e68258f2c95f94ee964f8685208ddfd931c9c Mon Sep 17 00:00:00 2001
From: Dongyan Chen <chendongyan at isrc.iscas.ac.cn>
Date: Mon, 15 Jun 2026 07:37:49 +0000
Subject: [PATCH] [RISCV][P-ext] Support Packed Absolute Value and Absolute
 Difference

---
 clang/lib/Headers/riscv_packed_simd.h         |  30 ++++
 clang/test/CodeGen/RISCV/rvp-intrinsics.c     | 128 ++++++++++++++++++
 .../riscv_packed_simd.c                       |  70 ++++++++++
 3 files changed, 228 insertions(+)

diff --git a/clang/lib/Headers/riscv_packed_simd.h b/clang/lib/Headers/riscv_packed_simd.h
index 7e981c91ec3e1..e972272cc1d63 100644
--- a/clang/lib/Headers/riscv_packed_simd.h
+++ b/clang/lib/Headers/riscv_packed_simd.h
@@ -92,6 +92,18 @@ typedef uint32_t uint32x2_t __attribute__((__vector_size__(8)));
     return (rty)(__rs1 op __rs2);                                              \
   }
 
+#define __packed_pabs(name, ty, rty)                                           \
+  static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1) {          \
+    return (rty)__builtin_elementwise_abs(__rs1);                              \
+  }
+
+#define __packed_pabd(name, ty, rty)                                           \
+  static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1,            \
+                                                          ty __rs2) {          \
+    return (rty)(__builtin_elementwise_max(__rs1, __rs2) -                     \
+                 __builtin_elementwise_min(__rs1, __rs2));                     \
+  }
+
 // clang-format off: macro call sites have no trailing semicolons, which
 // confuses clang-format into a deeply nested expression.
 
@@ -375,6 +387,22 @@ __packed_binary_builtin(pasubu_u8x8, uint8x8_t, __builtin_riscv_pasubu_u8x8)
 __packed_binary_builtin(pasubu_u16x4, uint16x4_t, __builtin_riscv_pasubu_u16x4)
 __packed_binary_builtin(pasubu_u32x2, uint32x2_t, __builtin_riscv_pasubu_u32x2)
 
+/* Packed Absolute Value and Absolute Difference (32-bit) */
+__packed_pabs(pabs_i8x4, int8x4_t, uint8x4_t)
+__packed_pabs(pabs_i16x2, int16x2_t, uint16x2_t)
+__packed_pabd(pabd_i8x4, int8x4_t, uint8x4_t)
+__packed_pabd(pabd_i16x2, int16x2_t, uint16x2_t)
+__packed_pabd(pabdu_u8x4, uint8x4_t, uint8x4_t)
+__packed_pabd(pabdu_u16x2, uint16x2_t, uint16x2_t)
+
+/* Packed Absolute Value and Absolute Difference (64-bit) */
+__packed_pabs(pabs_i8x8, int8x8_t, uint8x8_t)
+__packed_pabs(pabs_i16x4, int16x4_t, uint16x4_t)
+__packed_pabd(pabd_i8x8, int8x8_t, uint8x8_t)
+__packed_pabd(pabd_i16x4, int16x4_t, uint16x4_t)
+__packed_pabd(pabdu_u8x8, uint8x8_t, uint8x8_t)
+__packed_pabd(pabdu_u16x4, uint16x4_t, uint16x4_t)
+
 // clang-format on
 
 #undef __packed_splat2
@@ -392,6 +420,8 @@ __packed_binary_builtin(pasubu_u32x2, uint32x2_t, __builtin_riscv_pasubu_u32x2)
 #undef __packed_sh1add
 #undef __packed_sh1sadd
 #undef __packed_cmp
+#undef __packed_pabd
+#undef __packed_pabs
 #undef __DEFAULT_FN_ATTRS
 
 #if defined(__cplusplus)
diff --git a/clang/test/CodeGen/RISCV/rvp-intrinsics.c b/clang/test/CodeGen/RISCV/rvp-intrinsics.c
index 363bfa5f5d995..4c92be759be7f 100644
--- a/clang/test/CodeGen/RISCV/rvp-intrinsics.c
+++ b/clang/test/CodeGen/RISCV/rvp-intrinsics.c
@@ -5235,3 +5235,131 @@ uint16x4_t test_pasubu_u16x4(uint16x4_t rs1, uint16x4_t rs2) {
 uint32x2_t test_pasubu_u32x2(uint32x2_t rs1, uint32x2_t rs2) {
   return __riscv_pasubu_u32x2(rs1, rs2);
 }
+
+// RV32-LABEL: define dso_local i32 @test_pabs_i8x4(
+// RV32:         call <4 x i8> @llvm.abs.v4i8(<4 x i8>
+// RV64-LABEL: define dso_local i32 @test_pabs_i8x4(
+// RV64:         call <4 x i8> @llvm.abs.v4i8(<4 x i8>
+uint8x4_t test_pabs_i8x4(int8x4_t rs1) {
+  return __riscv_pabs_i8x4(rs1);
+}
+
+// RV32-LABEL: define dso_local i32 @test_pabs_i16x2(
+// RV32:         call <2 x i16> @llvm.abs.v2i16(<2 x i16>
+// RV64-LABEL: define dso_local i32 @test_pabs_i16x2(
+// RV64:         call <2 x i16> @llvm.abs.v2i16(<2 x i16>
+uint16x2_t test_pabs_i16x2(int16x2_t rs1) {
+  return __riscv_pabs_i16x2(rs1);
+}
+
+// RV32-LABEL: define dso_local i32 @test_pabd_i8x4(
+// RV32:         call <4 x i8> @llvm.smax.v4i8
+// RV32:         call <4 x i8> @llvm.smin.v4i8
+// RV32:         sub <4 x i8>
+// RV64-LABEL: define dso_local i32 @test_pabd_i8x4(
+// RV64:         call <4 x i8> @llvm.smax.v4i8
+// RV64:         call <4 x i8> @llvm.smin.v4i8
+// RV64:         sub <4 x i8>
+uint8x4_t test_pabd_i8x4(int8x4_t rs1, int8x4_t rs2) {
+  return __riscv_pabd_i8x4(rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i32 @test_pabd_i16x2(
+// RV32:         call <2 x i16> @llvm.smax.v2i16
+// RV32:         call <2 x i16> @llvm.smin.v2i16
+// RV32:         sub <2 x i16>
+// RV64-LABEL: define dso_local i32 @test_pabd_i16x2(
+// RV64:         call <2 x i16> @llvm.smax.v2i16
+// RV64:         call <2 x i16> @llvm.smin.v2i16
+// RV64:         sub <2 x i16>
+uint16x2_t test_pabd_i16x2(int16x2_t rs1, int16x2_t rs2) {
+  return __riscv_pabd_i16x2(rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i32 @test_pabdu_u8x4(
+// RV32:         call <4 x i8> @llvm.umax.v4i8
+// RV32:         call <4 x i8> @llvm.umin.v4i8
+// RV32:         sub <4 x i8>
+// RV64-LABEL: define dso_local i32 @test_pabdu_u8x4(
+// RV64:         call <4 x i8> @llvm.umax.v4i8
+// RV64:         call <4 x i8> @llvm.umin.v4i8
+// RV64:         sub <4 x i8>
+uint8x4_t test_pabdu_u8x4(uint8x4_t rs1, uint8x4_t rs2) {
+  return __riscv_pabdu_u8x4(rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i32 @test_pabdu_u16x2(
+// RV32:         call <2 x i16> @llvm.umax.v2i16
+// RV32:         call <2 x i16> @llvm.umin.v2i16
+// RV32:         sub <2 x i16>
+// RV64-LABEL: define dso_local i32 @test_pabdu_u16x2(
+// RV64:         call <2 x i16> @llvm.umax.v2i16
+// RV64:         call <2 x i16> @llvm.umin.v2i16
+// RV64:         sub <2 x i16>
+uint16x2_t test_pabdu_u16x2(uint16x2_t rs1, uint16x2_t rs2) {
+  return __riscv_pabdu_u16x2(rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pabs_i8x8(
+// RV32:         call <8 x i8> @llvm.abs.v8i8(<8 x i8>
+// RV64-LABEL: define dso_local i64 @test_pabs_i8x8(
+// RV64:         call <8 x i8> @llvm.abs.v8i8(<8 x i8>
+uint8x8_t test_pabs_i8x8(int8x8_t rs1) {
+  return __riscv_pabs_i8x8(rs1);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pabs_i16x4(
+// RV32:         call <4 x i16> @llvm.abs.v4i16(<4 x i16>
+// RV64-LABEL: define dso_local i64 @test_pabs_i16x4(
+// RV64:         call <4 x i16> @llvm.abs.v4i16(<4 x i16>
+uint16x4_t test_pabs_i16x4(int16x4_t rs1) {
+  return __riscv_pabs_i16x4(rs1);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pabd_i8x8(
+// RV32:         call <8 x i8> @llvm.smax.v8i8
+// RV32:         call <8 x i8> @llvm.smin.v8i8
+// RV32:         sub <8 x i8>
+// RV64-LABEL: define dso_local i64 @test_pabd_i8x8(
+// RV64:         call <8 x i8> @llvm.smax.v8i8
+// RV64:         call <8 x i8> @llvm.smin.v8i8
+// RV64:         sub <8 x i8>
+uint8x8_t test_pabd_i8x8(int8x8_t rs1, int8x8_t rs2) {
+  return __riscv_pabd_i8x8(rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pabd_i16x4(
+// RV32:         call <4 x i16> @llvm.smax.v4i16
+// RV32:         call <4 x i16> @llvm.smin.v4i16
+// RV32:         sub <4 x i16>
+// RV64-LABEL: define dso_local i64 @test_pabd_i16x4(
+// RV64:         call <4 x i16> @llvm.smax.v4i16
+// RV64:         call <4 x i16> @llvm.smin.v4i16
+// RV64:         sub <4 x i16>
+uint16x4_t test_pabd_i16x4(int16x4_t rs1, int16x4_t rs2) {
+  return __riscv_pabd_i16x4(rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pabdu_u8x8(
+// RV32:         call <8 x i8> @llvm.umax.v8i8
+// RV32:         call <8 x i8> @llvm.umin.v8i8
+// RV32:         sub <8 x i8>
+// RV64-LABEL: define dso_local i64 @test_pabdu_u8x8(
+// RV64:         call <8 x i8> @llvm.umax.v8i8
+// RV64:         call <8 x i8> @llvm.umin.v8i8
+// RV64:         sub <8 x i8>
+uint8x8_t test_pabdu_u8x8(uint8x8_t rs1, uint8x8_t rs2) {
+  return __riscv_pabdu_u8x8(rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pabdu_u16x4(
+// RV32:         call <4 x i16> @llvm.umax.v4i16
+// RV32:         call <4 x i16> @llvm.umin.v4i16
+// RV32:         sub <4 x i16>
+// RV64-LABEL: define dso_local i64 @test_pabdu_u16x4(
+// RV64:         call <4 x i16> @llvm.umax.v4i16
+// RV64:         call <4 x i16> @llvm.umin.v4i16
+// RV64:         sub <4 x i16>
+uint16x4_t test_pabdu_u16x4(uint16x4_t rs1, uint16x4_t rs2) {
+  return __riscv_pabdu_u16x4(rs1, rs2);
+}
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 edbc56ce0e199..e9f90fc17e23d 100644
--- a/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
+++ b/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
@@ -1772,3 +1772,73 @@ uint16x4_t test_pasubu_u16x4(uint16x4_t a, uint16x4_t b) {
 uint32x2_t test_pasubu_u32x2(uint32x2_t a, uint32x2_t b) {
   return __riscv_pasubu_u32x2(a, b);
 }
+
+// CHECK-LABEL: test_pabs_i8x4:
+// CHECK:       pabs.b
+uint8x4_t test_pabs_i8x4(int8x4_t a) { return __riscv_pabs_i8x4(a); }
+
+// CHECK-LABEL: test_pabs_i16x2:
+// CHECK:       pabs.h
+uint16x2_t test_pabs_i16x2(int16x2_t a) { return __riscv_pabs_i16x2(a); }
+
+// CHECK-LABEL: test_pabd_i8x4:
+// CHECK:       pabd.b
+uint8x4_t test_pabd_i8x4(int8x4_t a, int8x4_t b) {
+  return __riscv_pabd_i8x4(a, b);
+}
+
+// CHECK-LABEL: test_pabd_i16x2:
+// CHECK:       pabd.h
+uint16x2_t test_pabd_i16x2(int16x2_t a, int16x2_t b) {
+  return __riscv_pabd_i16x2(a, b);
+}
+
+// CHECK-LABEL: test_pabdu_u8x4:
+// CHECK:       pabdu.b
+uint8x4_t test_pabdu_u8x4(uint8x4_t a, uint8x4_t b) {
+  return __riscv_pabdu_u8x4(a, b);
+}
+
+// CHECK-LABEL: test_pabdu_u16x2:
+// CHECK:       pabdu.h
+uint16x2_t test_pabdu_u16x2(uint16x2_t a, uint16x2_t b) {
+  return __riscv_pabdu_u16x2(a, b);
+}
+
+// CHECK-LABEL: test_pabs_i8x8:
+// RV32:        pabs.db
+// RV64:        pabs.b
+uint8x8_t test_pabs_i8x8(int8x8_t a) { return __riscv_pabs_i8x8(a); }
+
+// CHECK-LABEL: test_pabs_i16x4:
+// RV32:        pabs.dh
+// RV64:        pabs.h
+uint16x4_t test_pabs_i16x4(int16x4_t a) { return __riscv_pabs_i16x4(a); }
+
+// CHECK-LABEL: test_pabd_i8x8:
+// RV32:        pabd.db
+// RV64:        pabd.b
+uint8x8_t test_pabd_i8x8(int8x8_t a, int8x8_t b) {
+  return __riscv_pabd_i8x8(a, b);
+}
+
+// CHECK-LABEL: test_pabd_i16x4:
+// RV32:        pabd.dh
+// RV64:        pabd.h
+uint16x4_t test_pabd_i16x4(int16x4_t a, int16x4_t b) {
+  return __riscv_pabd_i16x4(a, b);
+}
+
+// CHECK-LABEL: test_pabdu_u8x8:
+// RV32:        pabdu.db
+// RV64:        pabdu.b
+uint8x8_t test_pabdu_u8x8(uint8x8_t a, uint8x8_t b) {
+  return __riscv_pabdu_u8x8(a, b);
+}
+
+// CHECK-LABEL: test_pabdu_u16x4:
+// RV32:        pabdu.dh
+// RV64:        pabdu.h
+uint16x4_t test_pabdu_u16x4(uint16x4_t a, uint16x4_t b) {
+  return __riscv_pabdu_u16x4(a, b);
+}



More information about the cfe-commits mailing list