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

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

>From 9c8e6b386e568b24b2387737f6ebfae522996bca Mon Sep 17 00:00:00 2001
From: Dongyan Chen <[email protected]>
Date: Tue, 7 Jul 2026 07:19:20 +0000
Subject: [PATCH] Support Packed Saturating Absolute Value

---
 clang/include/clang/Basic/BuiltinsRISCV.td    |  8 ++
 clang/lib/CodeGen/TargetBuiltins/RISCV.cpp    | 13 ++-
 clang/lib/Headers/riscv_packed_simd.h         | 14 ++++
 clang/test/CodeGen/RISCV/rvp-intrinsics.c     | 84 +++++++++++++++++++
 .../riscv_packed_simd.c                       | 18 ++++
 llvm/include/llvm/IR/IntrinsicsRISCV.td       |  7 ++
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   | 30 +++++--
 llvm/lib/Target/RISCV/RISCVInstrInfoP.td      | 20 +++++
 llvm/test/CodeGen/RISCV/rvp-simd-32.ll        | 19 +++++
 llvm/test/CodeGen/RISCV/rvp-simd-64.ll        | 29 +++++++
 10 files changed, 234 insertions(+), 8 deletions(-)

diff --git a/clang/include/clang/Basic/BuiltinsRISCV.td 
b/clang/include/clang/Basic/BuiltinsRISCV.td
index 785e41324ad78..fa71d244d5791 100644
--- a/clang/include/clang/Basic/BuiltinsRISCV.td
+++ b/clang/include/clang/Basic/BuiltinsRISCV.td
@@ -247,6 +247,14 @@ def pmerge_i16x4 : RISCVBuiltin<"_Vector<4, 
short>(_Vector<4, short>, _Vector<4,
 def pmerge_u32x2 : RISCVBuiltin<"_Vector<2, unsigned int>(_Vector<2, unsigned 
int>, _Vector<2, unsigned int>, _Vector<2, unsigned int>)">;
 def pmerge_i32x2 : RISCVBuiltin<"_Vector<2, int>(_Vector<2, int>, _Vector<2, 
int>, _Vector<2, unsigned int>)">;
 
+// Packed Saturating Absolute Value (32-bit)
+def psabs_i8x4 : RISCVBuiltin<"_Vector<4, signed char>(_Vector<4, signed 
char>)">;
+def psabs_i16x2 : RISCVBuiltin<"_Vector<2, short>(_Vector<2, short>)">;
+
+// Packed Saturating Absolute Value (64-bit)
+def psabs_i8x8 : RISCVBuiltin<"_Vector<8, signed char>(_Vector<8, signed 
char>)">;
+def psabs_i16x4 : RISCVBuiltin<"_Vector<4, short>(_Vector<4, short>)">;
+
 } // Features = "experimental-p"
 
 
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp 
b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
index 588e229499082..85c593e57b988 100644
--- a/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
@@ -1258,7 +1258,12 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned 
BuiltinID,
   case RISCV::BI__builtin_riscv_pmerge_u16x4:
   case RISCV::BI__builtin_riscv_pmerge_i16x4:
   case RISCV::BI__builtin_riscv_pmerge_u32x2:
-  case RISCV::BI__builtin_riscv_pmerge_i32x2: {
+  case RISCV::BI__builtin_riscv_pmerge_i32x2:
+  // Packed Saturating Absolute Value
+  case RISCV::BI__builtin_riscv_psabs_i8x4:
+  case RISCV::BI__builtin_riscv_psabs_i16x2:
+  case RISCV::BI__builtin_riscv_psabs_i8x8:
+  case RISCV::BI__builtin_riscv_psabs_i16x4: {
     switch (BuiltinID) {
     default:
       llvm_unreachable("unexpected builtin ID");
@@ -1344,6 +1349,12 @@ Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned 
BuiltinID,
     case RISCV::BI__builtin_riscv_pmerge_i32x2:
       ID = Intrinsic::riscv_pmerge;
       break;
+    case RISCV::BI__builtin_riscv_psabs_i8x4:
+    case RISCV::BI__builtin_riscv_psabs_i16x2:
+    case RISCV::BI__builtin_riscv_psabs_i8x8:
+    case RISCV::BI__builtin_riscv_psabs_i16x4:
+      ID = Intrinsic::riscv_psabs;
+      break;
     }
 
     IntrinsicTypes = {ResultType};
diff --git a/clang/lib/Headers/riscv_packed_simd.h 
b/clang/lib/Headers/riscv_packed_simd.h
index c5edc123f64fa..e735bf65ef8aa 100644
--- a/clang/lib/Headers/riscv_packed_simd.h
+++ b/clang/lib/Headers/riscv_packed_simd.h
@@ -115,6 +115,11 @@ typedef uint32_t uint32x2_t 
__attribute__((__vector_size__(8)));
     return (ty)builtin(__rs1, __rs2, __rd);                                    
\
   }
 
+#define __packed_psabs(name, ty, builtin)                                      
\
+  static __inline__ ty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1) {           
\
+    return builtin(__rs1);                                                     
\
+  }
+
 /* 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)                                            
\
@@ -497,6 +502,14 @@ __packed_merge_builtin(pmerge_i16x4, int16x4_t, 
uint16x4_t, __builtin_riscv_pmer
 __packed_merge_builtin(pmerge_u32x2, uint32x2_t, uint32x2_t, 
__builtin_riscv_pmerge_u32x2)
 __packed_merge_builtin(pmerge_i32x2, int32x2_t, uint32x2_t, 
__builtin_riscv_pmerge_i32x2)
 
+/* Packed Saturating Absolute Value (32-bit) */
+__packed_psabs(psabs_i8x4, int8x4_t, __builtin_riscv_psabs_i8x4)
+__packed_psabs(psabs_i16x2, int16x2_t, __builtin_riscv_psabs_i16x2)
+
+/* Packed Saturating Absolute Value (64-bit) */
+__packed_psabs(psabs_i8x8, int8x8_t, __builtin_riscv_psabs_i8x8)
+__packed_psabs(psabs_i16x4, int16x4_t, __builtin_riscv_psabs_i16x4)
+
 // clang-format on
 
 #undef __packed_splat2
@@ -518,6 +531,7 @@ __packed_merge_builtin(pmerge_i32x2, int32x2_t, uint32x2_t, 
__builtin_riscv_pmer
 #undef __packed_binary_builtin_cast
 #undef __packed_reduction
 #undef __packed_merge_builtin
+#undef __packed_psabs
 #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 3791b0ddf508d..2b881c00f3d0b 100644
--- a/clang/test/CodeGen/RISCV/rvp-intrinsics.c
+++ b/clang/test/CodeGen/RISCV/rvp-intrinsics.c
@@ -6575,3 +6575,87 @@ int32x2_t test_prev_i32x2(int32x2_t rs1) {
 uint32x2_t test_prev_u32x2(uint32x2_t rs1) {
   return __riscv_prev_u32x2(rs1);
 }
+
+/* Packed Saturating Absolute Value (32-bit) */
+
+// RV32-LABEL: define dso_local i32 @test_psabs_i8x4(
+// RV32-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[TMP1:%.*]] = call <4 x i8> @llvm.riscv.psabs.v4i8(<4 x i8> 
[[TMP0]])
+// RV32-NEXT:    [[TMP2:%.*]] = bitcast <4 x i8> [[TMP1]] to i32
+// RV32-NEXT:    ret i32 [[TMP2]]
+//
+// RV64-LABEL: define dso_local i32 @test_psabs_i8x4(
+// RV64-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[TMP1:%.*]] = call <4 x i8> @llvm.riscv.psabs.v4i8(<4 x i8> 
[[TMP0]])
+// RV64-NEXT:    [[TMP2:%.*]] = bitcast <4 x i8> [[TMP1]] to i32
+// RV64-NEXT:    ret i32 [[TMP2]]
+//
+int8x4_t test_psabs_i8x4(int8x4_t rs1) {
+  return __riscv_psabs_i8x4(rs1);
+}
+
+// RV32-LABEL: define dso_local i32 @test_psabs_i16x2(
+// RV32-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP1:%.*]] = call <2 x i16> @llvm.riscv.psabs.v2i16(<2 x 
i16> [[TMP0]])
+// RV32-NEXT:    [[TMP2:%.*]] = bitcast <2 x i16> [[TMP1]] to i32
+// RV32-NEXT:    ret i32 [[TMP2]]
+//
+// RV64-LABEL: define dso_local i32 @test_psabs_i16x2(
+// RV64-SAME: i32 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP1:%.*]] = call <2 x i16> @llvm.riscv.psabs.v2i16(<2 x 
i16> [[TMP0]])
+// RV64-NEXT:    [[TMP2:%.*]] = bitcast <2 x i16> [[TMP1]] to i32
+// RV64-NEXT:    ret i32 [[TMP2]]
+//
+int16x2_t test_psabs_i16x2(int16x2_t rs1) {
+  return __riscv_psabs_i16x2(rs1);
+}
+
+/* Packed Saturating Absolute Value (64-bit) */
+
+// RV32-LABEL: define dso_local i64 @test_psabs_i8x8(
+// RV32-SAME: i64 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <8 x i8>
+// RV32-NEXT:    [[TMP1:%.*]] = call <8 x i8> @llvm.riscv.psabs.v8i8(<8 x i8> 
[[TMP0]])
+// RV32-NEXT:    [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to i64
+// RV32-NEXT:    ret i64 [[TMP2]]
+//
+// RV64-LABEL: define dso_local i64 @test_psabs_i8x8(
+// RV64-SAME: i64 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <8 x i8>
+// RV64-NEXT:    [[TMP1:%.*]] = call <8 x i8> @llvm.riscv.psabs.v8i8(<8 x i8> 
[[TMP0]])
+// RV64-NEXT:    [[TMP2:%.*]] = bitcast <8 x i8> [[TMP1]] to i64
+// RV64-NEXT:    ret i64 [[TMP2]]
+//
+int8x8_t test_psabs_i8x8(int8x8_t rs1) {
+  return __riscv_psabs_i8x8(rs1);
+}
+
+// RV32-LABEL: define dso_local i64 @test_psabs_i16x4(
+// RV32-SAME: i64 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
+// RV32-NEXT:    [[TMP1:%.*]] = call <4 x i16> @llvm.riscv.psabs.v4i16(<4 x 
i16> [[TMP0]])
+// RV32-NEXT:    [[TMP2:%.*]] = bitcast <4 x i16> [[TMP1]] to i64
+// RV32-NEXT:    ret i64 [[TMP2]]
+//
+// RV64-LABEL: define dso_local i64 @test_psabs_i16x4(
+// RV64-SAME: i64 noundef [[RS1_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RS1_COERCE]] to <4 x i16>
+// RV64-NEXT:    [[TMP1:%.*]] = call <4 x i16> @llvm.riscv.psabs.v4i16(<4 x 
i16> [[TMP0]])
+// RV64-NEXT:    [[TMP2:%.*]] = bitcast <4 x i16> [[TMP1]] to i64
+// RV64-NEXT:    ret i64 [[TMP2]]
+//
+int16x4_t test_psabs_i16x4(int16x4_t rs1) {
+  return __riscv_psabs_i16x4(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 5460f1a4e65ba..8a85d0475c31d 100644
--- a/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
+++ b/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
@@ -2289,3 +2289,21 @@ int32x2_t test_pmerge_mvm_i32x2(int32x2_t rs1, 
uint32x2_t rd, int32x2_t rs2) {
 int32x2_t test_pmerge_mvmn_i32x2(int32x2_t rs2, int32x2_t rs1, uint32x2_t rd) {
   return __riscv_pmerge_i32x2(rs1, rs2, rd);
 }
+
+// CHECK-LABEL: test_psabs_i8x4:
+// CHECK:       psabs.b
+int8x4_t test_psabs_i8x4(int8x4_t a) { return __riscv_psabs_i8x4(a); }
+
+// CHECK-LABEL: test_psabs_i16x2:
+// CHECK:       psabs.h
+int16x2_t test_psabs_i16x2(int16x2_t a) { return __riscv_psabs_i16x2(a); }
+
+// CHECK-LABEL: test_psabs_i8x8:
+// RV32:        psabs.db
+// RV64:        psabs.b
+int8x8_t test_psabs_i8x8(int8x8_t a) { return __riscv_psabs_i8x8(a); }
+
+// CHECK-LABEL: test_psabs_i16x4:
+// RV32:        psabs.dh
+// RV64:        psabs.h
+int16x4_t test_psabs_i16x4(int16x4_t a) { return __riscv_psabs_i16x4(a); }
diff --git a/llvm/include/llvm/IR/IntrinsicsRISCV.td 
b/llvm/include/llvm/IR/IntrinsicsRISCV.td
index c7f33f30ace58..28cde8111241c 100644
--- a/llvm/include/llvm/IR/IntrinsicsRISCV.td
+++ b/llvm/include/llvm/IR/IntrinsicsRISCV.td
@@ -2095,6 +2095,13 @@ class RVPBinaryIntrinsic
                               [LLVMMatchType<0>, llvm_anyvector_ty,
                                LLVMMatchType<1>],
                               [IntrNoMem, IntrSpeculatable]>;
+
+  // Packed Saturating Absolute Value
+  class RVPUnaryIntrinsic
+      : DefaultAttrsIntrinsic<[llvm_anyvector_ty],
+                              [LLVMMatchType<0>],
+                              [IntrNoMem, IntrSpeculatable]>;
+  def int_riscv_psabs : RVPUnaryIntrinsic;
 } // TargetPrefix = "riscv"
 
 
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp 
b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 77b9b9d6bc3c4..b3a7c68931743 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -11825,7 +11825,8 @@ SDValue 
RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
   case Intrinsic::riscv_pasub:
   case Intrinsic::riscv_pasubu:
   case Intrinsic::riscv_pabd:
-  case Intrinsic::riscv_pabdu: {
+  case Intrinsic::riscv_pabdu:
+  case Intrinsic::riscv_psabs: {
     unsigned Opc;
     switch (IntNo) {
     case Intrinsic::riscv_paadd:
@@ -11846,8 +11847,14 @@ SDValue 
RISCVTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op,
     case Intrinsic::riscv_pabdu:
       Opc = ISD::ABDU;
       break;
+    case Intrinsic::riscv_psabs:
+      Opc = RISCVISD::PSABS;
+      break;
     }
 
+    if (IntNo == Intrinsic::riscv_psabs)
+      return DAG.getNode(Opc, DL, Op.getValueType(), Op.getOperand(1));
+
     return DAG.getNode(Opc, DL, Op.getValueType(), Op.getOperand(1),
                        Op.getOperand(2));
   }
@@ -15832,7 +15839,8 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
     case Intrinsic::riscv_pssa:
     case Intrinsic::riscv_paas:
     case Intrinsic::riscv_pasa:
-    case Intrinsic::riscv_pmerge: {
+    case Intrinsic::riscv_pmerge:
+    case Intrinsic::riscv_psabs: {
       EVT VT = N->getValueType(0);
       if (!Subtarget.is64Bit() || (VT != MVT::v4i8 && VT != MVT::v2i16))
         return;
@@ -15857,6 +15865,9 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode *N,
       case Intrinsic::riscv_pabdu:
         Opc = ISD::ABDU;
         break;
+      case Intrinsic::riscv_psabs:
+        Opc = RISCVISD::PSABS;
+        break;
       default:
         // pas/psa/psas/pssa/paas/pasa and pmerge: re-emit at the widened type
         // rather than lowering to a generic node.
@@ -15868,20 +15879,25 @@ void RISCVTargetLowering::ReplaceNodeResults(SDNode 
*N,
       SDValue Undef = DAG.getUNDEF(VT);
       SDValue Op0 =
           DAG.getNode(ISD::CONCAT_VECTORS, DL, WideVT, N->getOperand(1), 
Undef);
-      SDValue Op1 =
-          DAG.getNode(ISD::CONCAT_VECTORS, DL, WideVT, N->getOperand(2), 
Undef);
       SDValue Res;
-      if (Opc == ISD::INTRINSIC_WO_CHAIN) {
+      if (IntNo == Intrinsic::riscv_psabs) {
+        // Unary: v4i8/v2i16 is illegal on RV64, so perform the operation on
+        // the widened (legal) type v8i8/v4i16, then extract the low half.
+        Res = DAG.getNode(Opc, DL, WideVT, Op0);
+      } else if (Opc == ISD::INTRINSIC_WO_CHAIN) {
         SmallVector<SDValue, 5> Ops;
         Ops.push_back(N->getOperand(0));
         Ops.push_back(Op0);
-        Ops.push_back(Op1);
+        Ops.push_back(DAG.getNode(ISD::CONCAT_VECTORS, DL, WideVT,
+                                  N->getOperand(2), Undef));
         if (N->getNumOperands() > 3)
           Ops.push_back(DAG.getNode(ISD::CONCAT_VECTORS, DL, WideVT,
                                     N->getOperand(3), Undef));
         Res = DAG.getNode(Opc, DL, WideVT, Ops);
       } else {
-        Res = DAG.getNode(Opc, DL, WideVT, Op0, Op1);
+        Res = DAG.getNode(Opc, DL, WideVT, Op0,
+                          DAG.getNode(ISD::CONCAT_VECTORS, DL, WideVT,
+                                      N->getOperand(2), Undef));
       }
       Results.push_back(DAG.getNode(ISD::EXTRACT_SUBVECTOR, DL, VT, Res,
                                     DAG.getVectorIdxConstant(0, DL)));
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td 
b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
index 4cd978108be0e..0c2dc9a0010f0 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -1754,6 +1754,11 @@ class PatGprPairGprPair<SDPatternOperator OpNode, RVInst 
Inst, ValueType vt>
     : Pat<(vt (OpNode (vt GPRPair:$rs1), (vt GPRPair:$rs2))),
           (Inst GPRPair:$rs1, GPRPair:$rs2)>;
 
+// Unary GPRPair operation, one source register pair.
+class PatGprPair<SDPatternOperator OpNode, RVInst Inst, ValueType vt>
+    : Pat<(vt (OpNode (vt GPRPair:$rs1))),
+          (Inst GPRPair:$rs1)>;
+
 // Reduction sum. PatRedSum is the single-GPR source (predsum.bs/hs/ws), result
 // XLenVT; PatRedSumPair is the RV32 paired source (predsum.dbs/dhs), result 
i32.
 // Target-illegal results (i32 accumulator on RV64, i64 on RV32) don't reach
@@ -1898,6 +1903,11 @@ def SDT_RISCVPPairE_DB : SDTypeProfile<2, 4, 
[SDTCisVT<0, v4i8>,
                                               SDTCisSameAs<0, 5>]>;
 def riscv_ppaire_db : RVSDNode<"PPAIRE_DB", SDT_RISCVPPairE_DB>;
 
+// signed-saturating abs of each lane; an INT_MIN lane maps to INT_MAX.
+def SDT_RISCVPackedUnary : SDTypeProfile<1, 1, [SDTCisVec<0>,
+                                                SDTCisSameAs<0, 1>]>;
+def riscv_psabs : RVSDNode<"PSABS", SDT_RISCVPackedUnary>;
+
 // Add one to the immediate. Used by RISCVISD::SATI.
 def IncImm : SDNodeXForm<imm, [{
     return CurDAG->getTargetConstant(N->getZExtValue() + 1, SDLoc(N),
@@ -2118,6 +2128,10 @@ let Predicates = [HasStdExtP] in {
   def : PatGprGpr<smax, PMAX_H, XLenVecI16VT>;
   def : PatGprGpr<umax, PMAXU_H, XLenVecI16VT>;
 
+  // 8/16-bit saturating absolute value patterns
+  def : PatGpr<riscv_psabs, PSABS_B, XLenVecI8VT>;
+  def : PatGpr<riscv_psabs, PSABS_H, XLenVecI16VT>;
+
   // 8/16-bit vselect patterns
   def : Pat<(XLenVecI8VT (vselect (XLenVecI8VT GPR:$mask), GPR:$true_v, 
GPR:$false_v)),
             (MERGE GPR:$mask, GPR:$false_v, GPR:$true_v)>;
@@ -2444,6 +2458,10 @@ let append Predicates = [IsRV32] in {
   def : PatGprPairGprPair<smax, PMAX_DW, v2i32>;
   def : PatGprPairGprPair<umax, PMAXU_DW, v2i32>;
 
+  // 8/16-bit saturating absolute value patterns
+  def : PatGprPair<riscv_psabs, PSABS_DB, v8i8>;
+  def : PatGprPair<riscv_psabs, PSABS_DH, v4i16>;
+
   // 16-bit bswap patterns
   def : Pat<(v4i16 (bswap GPRPair:$rs)),
             (PPAIROE_DB GPRPair:$rs, GPRPair:$rs)>;
@@ -2500,6 +2518,7 @@ let append Predicates = [IsRV32] in {
             (EXTRACT_SUBREG GPRPair:$vec, sub_gpr_even)>;
   def : Pat<(i32 (extractelt (v2i32 GPRPair:$vec), (i32 1))),
             (EXTRACT_SUBREG GPRPair:$vec, sub_gpr_odd)>;
+
 } // append Predicates = [IsRV32]
 
 let append Predicates = [IsRV64] in {
@@ -2725,4 +2744,5 @@ let append Predicates = [IsRV64] in {
   def : Pat<(v4i16 (sext_inreg GPR:$rs1, v4i8)), (PSEXT_H_B GPR:$rs1)>;
   def : Pat<(v2i32 (sext_inreg GPR:$rs1, v2i16)), (PSEXT_W_H GPR:$rs1)>;
 } // append Predicates = [IsRV64]
+
 } // Predicates = [HasStdExtP]
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-32.ll 
b/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
index 6b11524a700ae..48c7b3b14847e 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-32.ll
@@ -2664,3 +2664,22 @@ define i32 @test_pabdsumau_u8x4_u32(i32 %rd, <4 x i8> 
%a, <4 x i8> %b) {
   %res = call i32 @llvm.riscv.pabdsumau.i32.v4i8(i32 %rd, <4 x i8> %a, <4 x 
i8> %b)
   ret i32 %res
 }
+
+; Packed Saturating Absolute Value
+define <4 x i8> @test_psabs_v4i8(<4 x i8> %a) {
+; CHECK-LABEL: test_psabs_v4i8:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    psabs.b a0, a0
+; CHECK-NEXT:    ret
+  %res = call <4 x i8> @llvm.riscv.psabs.v4i8(<4 x i8> %a)
+  ret <4 x i8> %res
+}
+
+define <2 x i16> @test_psabs_v2i16(<2 x i16> %a) {
+; CHECK-LABEL: test_psabs_v2i16:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    psabs.h a0, a0
+; CHECK-NEXT:    ret
+  %res = call <2 x i16> @llvm.riscv.psabs.v2i16(<2 x i16> %a)
+  ret <2 x i16> %res
+}
diff --git a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll 
b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
index 1f41bdf730910..9cbd64717c1d5 100644
--- a/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
+++ b/llvm/test/CodeGen/RISCV/rvp-simd-64.ll
@@ -5817,3 +5817,32 @@ define i64 @test_pabdsumau_u8x8_u64(i64 %rd, <8 x i8> 
%a, <8 x i8> %b) {
   %res = call i64 @llvm.riscv.pabdsumau.i64.v8i8(i64 %rd, <8 x i8> %a, <8 x 
i8> %b)
   ret i64 %res
 }
+
+; Packed Saturating Absolute Value
+define <8 x i8> @test_psabs_v8i8(<8 x i8> %a) {
+; RV32-LABEL: test_psabs_v8i8:
+; RV32:       # %bb.0:
+; RV32-NEXT:    psabs.db a0, a0
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_psabs_v8i8:
+; RV64:       # %bb.0:
+; RV64-NEXT:    psabs.b a0, a0
+; RV64-NEXT:    ret
+  %res = call <8 x i8> @llvm.riscv.psabs.v8i8(<8 x i8> %a)
+  ret <8 x i8> %res
+}
+
+define <4 x i16> @test_psabs_v4i16(<4 x i16> %a) {
+; RV32-LABEL: test_psabs_v4i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    psabs.dh a0, a0
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_psabs_v4i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    psabs.h a0, a0
+; RV64-NEXT:    ret
+  %res = call <4 x i16> @llvm.riscv.psabs.v4i16(<4 x i16> %a)
+  ret <4 x i16> %res
+}
\ No newline at end of file

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

Reply via email to