llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-x86

Author: SiHuaN (sihuan)

<details>
<summary>Changes</summary>

Add Clang header intrinsics for the RISC-V P-extension packed widening
subtraction accumulate operations:

- __riscv_pwsuba_i16x4
- __riscv_pwsuba_i32x2
- __riscv_pwsubau_u16x4
- __riscv_pwsubau_u32x2

Each computes rd + (a - b). The header wrappers use generic LLVM IR: RV32
selects the direct `pwsuba.*` / `pwsubau.*` instructions, while RV64
lowers the generic IR to the decomposition specified by the P-extension
intrinsic spec.

The header emits `rd + cv(rs1) - cv(rs2)` (i.e. `(rd + a) - b`) rather
than `rd + (cv(rs1) - cv(rs2))`. The wrapper is shared by RV32 and RV64,
and the outer `sub` is the shape the RV32 patterns match; at -O0 there is
no reassociation to normalize it.

RV64 has no packed widening subtract-accumulate instruction, so a DAG
combine re-associates `sub(add(rd, ext a), ext b)` to
`rd + (ext a - ext b)`. This matches the spec's subtract-then-accumulate
order and keeps the widening subtract off the accumulator's dependency
chain. The signed halfword form uses a new `riscv_pm2suba_h` node
(`PM2SUBA.H`); the remaining forms reuse the existing binary widening
subtract.


---
Full diff: https://github.com/llvm/llvm-project/pull/225764.diff


6 Files Affected:

- (modified) clang/lib/Headers/riscv_packed_simd.h (+13) 
- (modified) clang/test/CodeGen/RISCV/rvp-intrinsics.c (+121) 
- (modified) cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c 
(+40) 
- (modified) llvm/lib/Target/RISCV/RISCVISelLowering.cpp (+58) 
- (modified) llvm/lib/Target/RISCV/RISCVInstrInfoP.td (+16) 
- (added) llvm/test/CodeGen/RISCV/rvp-widening-sub-acc.ll (+87) 


``````````diff
diff --git a/clang/lib/Headers/riscv_packed_simd.h 
b/clang/lib/Headers/riscv_packed_simd.h
index 2cee5987c1dac..11bd0d7048737 100644
--- a/clang/lib/Headers/riscv_packed_simd.h
+++ b/clang/lib/Headers/riscv_packed_simd.h
@@ -187,6 +187,12 @@ typedef uint32_t uint32x2_t 
__attribute__((__vector_size__(8)));
     return __rd op __builtin_convertvector(__rs1, rty)                         
\
         op __builtin_convertvector(__rs2, rty);                                
\
   }
+#define __packed_widen_sub_acc_op(name, rty, ty)                               
\
+  static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(rty __rd, ty __rs1,  
\
+                                                          ty __rs2) {          
\
+    return __rd + __builtin_convertvector(__rs1, rty) -                        
\
+           __builtin_convertvector(__rs2, rty);                                
\
+  }
 #define __packed_widen_mul(name, rty, ty)                                      
\
   static __inline__ rty __DEFAULT_FN_ATTRS __riscv_##name(ty __rs1,            
\
                                                           ty __rs2) {          
\
@@ -746,6 +752,12 @@ __packed_widen_binary_acc_op(pwadda_i32x2, int32x2_t, 
int16x2_t, +)
 __packed_widen_binary_acc_op(pwaddau_u16x4, uint16x4_t, uint8x4_t, +)
 __packed_widen_binary_acc_op(pwaddau_u32x2, uint32x2_t, uint16x2_t, +)
 
+/* Packed Widening Subtraction Accumulate */
+__packed_widen_sub_acc_op(pwsuba_i16x4, int16x4_t, int8x4_t)
+__packed_widen_sub_acc_op(pwsuba_i32x2, int32x2_t, int16x2_t)
+__packed_widen_sub_acc_op(pwsubau_u16x4, uint16x4_t, uint8x4_t)
+__packed_widen_sub_acc_op(pwsubau_u32x2, uint32x2_t, uint16x2_t)
+
 /* Packed Widening Multiply (32-bit) */
 __packed_widen_mul(pwmul_i16x4, int16x4_t, int8x4_t)
 __packed_widen_mul(pwmul_i32x2, int32x2_t, int16x2_t)
@@ -1336,6 +1348,7 @@ __packed_reinterpret(u32x2_i32x2, int32x2_t, uint32x2_t)
 #undef __packed_widen_convert
 #undef __packed_widen_binary_op
 #undef __packed_widen_binary_acc_op
+#undef __packed_widen_sub_acc_op
 #undef __packed_widen_mul
 #undef __packed_widen_mulsu
 #undef __packed_widen_high2
diff --git a/clang/test/CodeGen/RISCV/rvp-intrinsics.c 
b/clang/test/CodeGen/RISCV/rvp-intrinsics.c
index 0792df58dbfb4..cce290b938856 100644
--- a/clang/test/CodeGen/RISCV/rvp-intrinsics.c
+++ b/clang/test/CodeGen/RISCV/rvp-intrinsics.c
@@ -8384,6 +8384,127 @@ uint32x2_t test_pwaddau_u32x2(uint32x2_t rd, uint16x2_t 
rs1,
   return __riscv_pwaddau_u32x2(rd, rs1, rs2);
 }
 
+// RV32-LABEL: define dso_local i64 @test_pwsuba_i16x4(
+// RV32-SAME: i64 noundef [[RD_COERCE:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <4 x i16>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[TMP2:%.*]] = bitcast i32 [[RS2_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[CONV_I:%.*]] = sext <4 x i8> [[TMP1]] to <4 x i16>
+// RV32-NEXT:    [[ADD_I:%.*]] = add <4 x i16> [[TMP0]], [[CONV_I]]
+// RV32-NEXT:    [[CONV4_I:%.*]] = sext <4 x i8> [[TMP2]] to <4 x i16>
+// RV32-NEXT:    [[SUB_I:%.*]] = sub <4 x i16> [[ADD_I]], [[CONV4_I]]
+// RV32-NEXT:    [[TMP3:%.*]] = bitcast <4 x i16> [[SUB_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP3]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwsuba_i16x4(
+// RV64-SAME: i64 noundef [[RD_COERCE:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <4 x i16>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[TMP2:%.*]] = bitcast i32 [[RS2_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[CONV_I:%.*]] = sext <4 x i8> [[TMP1]] to <4 x i16>
+// RV64-NEXT:    [[ADD_I:%.*]] = add <4 x i16> [[TMP0]], [[CONV_I]]
+// RV64-NEXT:    [[CONV4_I:%.*]] = sext <4 x i8> [[TMP2]] to <4 x i16>
+// RV64-NEXT:    [[SUB_I:%.*]] = sub <4 x i16> [[ADD_I]], [[CONV4_I]]
+// RV64-NEXT:    [[TMP3:%.*]] = bitcast <4 x i16> [[SUB_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP3]]
+//
+int16x4_t test_pwsuba_i16x4(int16x4_t rd, int8x4_t rs1, int8x4_t rs2) {
+  return __riscv_pwsuba_i16x4(rd, rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pwsuba_i32x2(
+// RV32-SAME: i64 noundef [[RD_COERCE:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <2 x i32>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP2:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[CONV_I:%.*]] = sext <2 x i16> [[TMP1]] to <2 x i32>
+// RV32-NEXT:    [[ADD_I:%.*]] = add <2 x i32> [[TMP0]], [[CONV_I]]
+// RV32-NEXT:    [[CONV4_I:%.*]] = sext <2 x i16> [[TMP2]] to <2 x i32>
+// RV32-NEXT:    [[SUB_I:%.*]] = sub <2 x i32> [[ADD_I]], [[CONV4_I]]
+// RV32-NEXT:    [[TMP3:%.*]] = bitcast <2 x i32> [[SUB_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP3]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwsuba_i32x2(
+// RV64-SAME: i64 noundef [[RD_COERCE:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <2 x i32>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP2:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[CONV_I:%.*]] = sext <2 x i16> [[TMP1]] to <2 x i32>
+// RV64-NEXT:    [[ADD_I:%.*]] = add <2 x i32> [[TMP0]], [[CONV_I]]
+// RV64-NEXT:    [[CONV4_I:%.*]] = sext <2 x i16> [[TMP2]] to <2 x i32>
+// RV64-NEXT:    [[SUB_I:%.*]] = sub <2 x i32> [[ADD_I]], [[CONV4_I]]
+// RV64-NEXT:    [[TMP3:%.*]] = bitcast <2 x i32> [[SUB_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP3]]
+//
+int32x2_t test_pwsuba_i32x2(int32x2_t rd, int16x2_t rs1, int16x2_t rs2) {
+  return __riscv_pwsuba_i32x2(rd, rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pwsubau_u16x4(
+// RV32-SAME: i64 noundef [[RD_COERCE:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <4 x i16>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[TMP2:%.*]] = bitcast i32 [[RS2_COERCE]] to <4 x i8>
+// RV32-NEXT:    [[CONV_I:%.*]] = zext <4 x i8> [[TMP1]] to <4 x i16>
+// RV32-NEXT:    [[ADD_I:%.*]] = add <4 x i16> [[TMP0]], [[CONV_I]]
+// RV32-NEXT:    [[CONV4_I:%.*]] = zext <4 x i8> [[TMP2]] to <4 x i16>
+// RV32-NEXT:    [[SUB_I:%.*]] = sub <4 x i16> [[ADD_I]], [[CONV4_I]]
+// RV32-NEXT:    [[TMP3:%.*]] = bitcast <4 x i16> [[SUB_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP3]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwsubau_u16x4(
+// RV64-SAME: i64 noundef [[RD_COERCE:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <4 x i16>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS1_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[TMP2:%.*]] = bitcast i32 [[RS2_COERCE]] to <4 x i8>
+// RV64-NEXT:    [[CONV_I:%.*]] = zext <4 x i8> [[TMP1]] to <4 x i16>
+// RV64-NEXT:    [[ADD_I:%.*]] = add <4 x i16> [[TMP0]], [[CONV_I]]
+// RV64-NEXT:    [[CONV4_I:%.*]] = zext <4 x i8> [[TMP2]] to <4 x i16>
+// RV64-NEXT:    [[SUB_I:%.*]] = sub <4 x i16> [[ADD_I]], [[CONV4_I]]
+// RV64-NEXT:    [[TMP3:%.*]] = bitcast <4 x i16> [[SUB_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP3]]
+//
+uint16x4_t test_pwsubau_u16x4(uint16x4_t rd, uint8x4_t rs1, uint8x4_t rs2) {
+  return __riscv_pwsubau_u16x4(rd, rs1, rs2);
+}
+
+// RV32-LABEL: define dso_local i64 @test_pwsubau_u32x2(
+// RV32-SAME: i64 noundef [[RD_COERCE:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV32-NEXT:  [[ENTRY:.*:]]
+// RV32-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <2 x i32>
+// RV32-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[TMP2:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV32-NEXT:    [[CONV_I:%.*]] = zext <2 x i16> [[TMP1]] to <2 x i32>
+// RV32-NEXT:    [[ADD_I:%.*]] = add <2 x i32> [[TMP0]], [[CONV_I]]
+// RV32-NEXT:    [[CONV4_I:%.*]] = zext <2 x i16> [[TMP2]] to <2 x i32>
+// RV32-NEXT:    [[SUB_I:%.*]] = sub <2 x i32> [[ADD_I]], [[CONV4_I]]
+// RV32-NEXT:    [[TMP3:%.*]] = bitcast <2 x i32> [[SUB_I]] to i64
+// RV32-NEXT:    ret i64 [[TMP3]]
+//
+// RV64-LABEL: define dso_local i64 @test_pwsubau_u32x2(
+// RV64-SAME: i64 noundef [[RD_COERCE:%.*]], i32 noundef [[RS1_COERCE:%.*]], 
i32 noundef [[RS2_COERCE:%.*]]) #[[ATTR0]] {
+// RV64-NEXT:  [[ENTRY:.*:]]
+// RV64-NEXT:    [[TMP0:%.*]] = bitcast i64 [[RD_COERCE]] to <2 x i32>
+// RV64-NEXT:    [[TMP1:%.*]] = bitcast i32 [[RS1_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[TMP2:%.*]] = bitcast i32 [[RS2_COERCE]] to <2 x i16>
+// RV64-NEXT:    [[CONV_I:%.*]] = zext <2 x i16> [[TMP1]] to <2 x i32>
+// RV64-NEXT:    [[ADD_I:%.*]] = add <2 x i32> [[TMP0]], [[CONV_I]]
+// RV64-NEXT:    [[CONV4_I:%.*]] = zext <2 x i16> [[TMP2]] to <2 x i32>
+// RV64-NEXT:    [[SUB_I:%.*]] = sub <2 x i32> [[ADD_I]], [[CONV4_I]]
+// RV64-NEXT:    [[TMP3:%.*]] = bitcast <2 x i32> [[SUB_I]] to i64
+// RV64-NEXT:    ret i64 [[TMP3]]
+//
+uint32x2_t test_pwsubau_u32x2(uint32x2_t rd, uint16x2_t rs1,
+                              uint16x2_t rs2) {
+  return __riscv_pwsubau_u32x2(rd, rs1, rs2);
+}
+
 // RV32-LABEL: define dso_local i64 @test_pwsub_i16x4(
 // RV32-SAME: i32 noundef [[RS1_COERCE:%.*]], i32 noundef [[RS2_COERCE:%.*]]) 
#[[ATTR0]] {
 // RV32-NEXT:  [[ENTRY:.*:]]
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 37314589eef93..da2d4c046091a 100644
--- a/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
+++ b/cross-project-tests/intrinsic-header-tests/riscv_packed_simd.c
@@ -2430,6 +2430,46 @@ uint32x2_t test_pwaddau_u32x2(uint32x2_t rd, uint16x2_t 
rs1, uint16x2_t rs2) {
   return __riscv_pwaddau_u32x2(rd, rs1, rs2);
 }
 
+// CHECK-LABEL: test_pwsuba_i16x4:
+// RV32:        pwsuba.b
+// RV64:        zip8p
+// RV64:        psrai.h
+// RV64:        psext.h.b
+// RV64:        psub.h
+// RV64:        padd.h
+int16x4_t test_pwsuba_i16x4(int16x4_t rd, int8x4_t rs1, int8x4_t rs2) {
+  return __riscv_pwsuba_i16x4(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: test_pwsuba_i32x2:
+// RV32:        pwsuba.h
+// RV64:        zip16p
+// RV64:        pli.h
+// RV64:        pm2suba.h
+int32x2_t test_pwsuba_i32x2(int32x2_t rd, int16x2_t rs1, int16x2_t rs2) {
+  return __riscv_pwsuba_i32x2(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: test_pwsubau_u16x4:
+// RV32:        pwsubau.b
+// RV64:        pwcvtu.wb
+// RV64:        pwcvtu.wb
+// RV64:        psub.h
+// RV64:        padd.h
+uint16x4_t test_pwsubau_u16x4(uint16x4_t rd, uint8x4_t rs1, uint8x4_t rs2) {
+  return __riscv_pwsubau_u16x4(rd, rs1, rs2);
+}
+
+// CHECK-LABEL: test_pwsubau_u32x2:
+// RV32:        pwsubau.h
+// RV64:        pwcvtu.wh
+// RV64:        pwcvtu.wh
+// RV64:        psub.w
+// RV64:        padd.w
+uint32x2_t test_pwsubau_u32x2(uint32x2_t rd, uint16x2_t rs1, uint16x2_t rs2) {
+  return __riscv_pwsubau_u32x2(rd, rs1, rs2);
+}
+
 // CHECK-LABEL: test_pwcvth_i16x4:
 // RV32:        pwcvth.b
 // RV64:        pwcvth.wb
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp 
b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 5534eac885d9e..c60012237e93f 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -18956,6 +18956,62 @@ static SDValue combinePExtWideningAddAcc(SDNode *N, 
SelectionDAG &DAG,
   return DAG.getNode(Opc, DL, VT, Acc, Zip, Ones);
 }
 
+// Fold sub(add(Acc, ext A), ext B) to Acc + (A - B), where ext is sext/zext.
+static SDValue combinePExtWideningSubAcc(SDNode *N, SelectionDAG &DAG,
+                                         const RISCVSubtarget &Subtarget) {
+  using namespace SDPatternMatch;
+
+  if (!Subtarget.hasStdExtP() || !Subtarget.is64Bit())
+    return SDValue();
+
+  if (N->getOpcode() != ISD::SUB)
+    return SDValue();
+
+  MVT VT = N->getSimpleValueType(0);
+  if (VT != MVT::v4i16 && VT != MVT::v2i32)
+    return SDValue();
+
+  MVT SrcVT = VT == MVT::v4i16 ? MVT::v4i8 : MVT::v2i16;
+  auto Extend = [&](SDValue &Ext, SDValue &Src) {
+    return m_Value(
+        Ext, m_OneUse(m_AnyOf(
+                 m_Node(ISD::SIGN_EXTEND, m_Value(Src, m_SpecificVT(SrcVT))),
+                 m_Node(ISD::ZERO_EXTEND, m_Value(Src, 
m_SpecificVT(SrcVT))))));
+  };
+
+  SDValue Acc, ExtA, A, ExtB, B;
+  if (!sd_match(N, m_Sub(m_OneUse(m_Add(m_Value(Acc), Extend(ExtA, A))),
+                         Extend(ExtB, B))) ||
+      ExtA.getOpcode() != ExtB.getOpcode())
+    return SDValue();
+
+  SDLoc DL(N);
+  if (ExtA.getOpcode() == ISD::ZERO_EXTEND) {
+    // No unsigned PM2 accumulate-subtract; keep the binary widening subtract
+    // off the accumulator's dependency chain.
+    return DAG.getNode(ISD::ADD, DL, VT, Acc,
+                       DAG.getNode(ISD::SUB, DL, VT, ExtA, ExtB));
+  }
+
+  MVT LegalSrcVT = VT == MVT::v4i16 ? MVT::v8i8 : MVT::v4i16;
+  A = DAG.getNode(ISD::CONCAT_VECTORS, DL, LegalSrcVT, A, DAG.getUNDEF(SrcVT));
+  B = DAG.getNode(ISD::CONCAT_VECTORS, DL, LegalSrcVT, B, DAG.getUNDEF(SrcVT));
+
+  SDValue Zip = DAG.getNode(RISCVISD::PZIP, DL, LegalSrcVT, A, B);
+  if (VT == MVT::v4i16) {
+    SDValue ZipAsVT = DAG.getBitcast(VT, Zip);
+    SDValue Low = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, VT, ZipAsVT,
+                              DAG.getValueType(MVT::v4i8));
+    SDValue High = DAG.getNode(RISCVISD::PSRA, DL, VT, ZipAsVT,
+                               DAG.getConstant(8, DL, MVT::i64));
+    return DAG.getNode(ISD::ADD, DL, VT, Acc,
+                       DAG.getNode(ISD::SUB, DL, VT, Low, High));
+  }
+
+  SDValue Ones = DAG.getConstant(1, DL, LegalSrcVT);
+  return DAG.getNode(RISCVISD::PM2SUBA_H, DL, VT, Acc, Zip, Ones);
+}
+
 static SDValue performADDCombine(SDNode *N,
                                  TargetLowering::DAGCombinerInfo &DCI,
                                  const RISCVSubtarget &Subtarget) {
@@ -19109,6 +19165,8 @@ static SDValue performSUBCombine(SDNode *N, 
SelectionDAG &DAG,
     }
   }
 
+  if (SDValue V = combinePExtWideningSubAcc(N, DAG, Subtarget))
+    return V;
   if (SDValue V = combinePExtWideningAddSub(N, DAG, Subtarget))
     return V;
   if (SDValue V = combineBinOpOfZExt(N, DAG))
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td 
b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
index 24096ab7d4a50..7ebd186f96e75 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -1952,6 +1952,7 @@ def SDT_RISCVPM2HalfwordAcc
                            SDTCisVT<2, v4i16>, SDTCisSameAs<2, 3>]>;
 def riscv_pm2adda_h : RVSDNode<"PM2ADDA_H", SDT_RISCVPM2HalfwordAcc>;
 def riscv_pm2addau_h : RVSDNode<"PM2ADDAU_H", SDT_RISCVPM2HalfwordAcc>;
+def riscv_pm2suba_h : RVSDNode<"PM2SUBA_H", SDT_RISCVPM2HalfwordAcc>;
 
 def SDT_RISCVWideningMulAccByHalves
     : SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>,
@@ -2616,6 +2617,18 @@ let append Predicates = [IsRV32] in {
   def : Pat<(v2i32 (add (add GPRPair:$rd, (zext (v2i16 GPR:$rs1))),
                         (zext (v2i16 GPR:$rs2)))),
             (PWADDAU_H GPRPair:$rd, GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(v4i16 (sub (add GPRPair:$rd, (sext (v4i8 GPR:$rs1))),
+                        (sext (v4i8 GPR:$rs2)))),
+            (PWSUBA_B GPRPair:$rd, GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(v2i32 (sub (add GPRPair:$rd, (sext (v2i16 GPR:$rs1))),
+                        (sext (v2i16 GPR:$rs2)))),
+            (PWSUBA_H GPRPair:$rd, GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(v4i16 (sub (add GPRPair:$rd, (zext (v4i8 GPR:$rs1))),
+                        (zext (v4i8 GPR:$rs2)))),
+            (PWSUBAU_B GPRPair:$rd, GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(v2i32 (sub (add GPRPair:$rd, (zext (v2i16 GPR:$rs1))),
+                        (zext (v2i16 GPR:$rs2)))),
+            (PWSUBAU_H GPRPair:$rd, GPR:$rs1, GPR:$rs2)>;
   def : Pat<(v4i16 (sub (sext (v4i8 GPR:$rs1)), (sext (v4i8 GPR:$rs2)))),
             (PWSUB_B GPR:$rs1, GPR:$rs2)>;
   def : Pat<(v2i32 (sub (sext (v2i16 GPR:$rs1)), (sext (v2i16 GPR:$rs2)))),
@@ -3310,6 +3323,9 @@ let append Predicates = [IsRV64] in {
   def : Pat<(v2i32 (riscv_pm2addau_h (v2i32 GPR:$rd), (v4i16 GPR:$rs1),
                                      (v4i16 GPR:$rs2))),
             (PM2ADDAU_H GPR:$rd, GPR:$rs1, GPR:$rs2)>;
+  def : Pat<(v2i32 (riscv_pm2suba_h (v2i32 GPR:$rd), (v4i16 GPR:$rs1),
+                                    (v4i16 GPR:$rs2))),
+            (PM2SUBA_H GPR:$rd, GPR:$rs1, GPR:$rs2)>;
 
   // 32-bit logical shift left/right patterns
   def : PatGprImm<riscv_pshl, PSLLI_W, uimm5, v2i32>;
diff --git a/llvm/test/CodeGen/RISCV/rvp-widening-sub-acc.ll 
b/llvm/test/CodeGen/RISCV/rvp-widening-sub-acc.ll
new file mode 100644
index 0000000000000..44e840eeffe0e
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvp-widening-sub-acc.ll
@@ -0,0 +1,87 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 
UTC_ARGS: --version 6
+; RUN: llc -mtriple=riscv32 -mattr=+experimental-p -verify-machineinstrs < %s 
| \
+; RUN:   FileCheck %s --check-prefixes=CHECK,RV32
+; RUN: llc -mtriple=riscv64 -mattr=+experimental-p -verify-machineinstrs < %s 
| \
+; RUN:   FileCheck %s --check-prefixes=CHECK,RV64
+
+define <4 x i16> @test_pwsuba_v4i8(<4 x i16> %rd, <4 x i8> %a, <4 x i8> %b) {
+; RV32-LABEL: test_pwsuba_v4i8:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pwsuba.b a0, a2, a3
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pwsuba_v4i8:
+; RV64:       # %bb.0:
+; RV64-NEXT:    zip8p a1, a1, a2
+; RV64-NEXT:    psrai.h a2, a1, 8
+; RV64-NEXT:    psext.h.b a1, a1
+; RV64-NEXT:    psub.h a1, a1, a2
+; RV64-NEXT:    padd.h a0, a0, a1
+; RV64-NEXT:    ret
+  %ext.a = sext <4 x i8> %a to <4 x i16>
+  %ext.b = sext <4 x i8> %b to <4 x i16>
+  %sum.a = add <4 x i16> %rd, %ext.a
+  %sum.b = sub <4 x i16> %sum.a, %ext.b
+  ret <4 x i16> %sum.b
+}
+
+define <2 x i32> @test_pwsuba_v2i16(<2 x i32> %rd, <2 x i16> %a, <2 x i16> %b) 
{
+; RV32-LABEL: test_pwsuba_v2i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pwsuba.h a0, a2, a3
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pwsuba_v2i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    zip16p a1, a1, a2
+; RV64-NEXT:    pli.h a2, 1
+; RV64-NEXT:    pm2suba.h a0, a1, a2
+; RV64-NEXT:    ret
+  %ext.a = sext <2 x i16> %a to <2 x i32>
+  %ext.b = sext <2 x i16> %b to <2 x i32>
+  %sum.a = add <2 x i32> %rd, %ext.a
+  %sum.b = sub <2 x i32> %sum.a, %ext.b
+  ret <2 x i32> %sum.b
+}
+
+define <4 x i16> @test_pwsubau_v4i8(<4 x i16> %rd, <4 x i8> %a, <4 x i8> %b) {
+; RV32-LABEL: test_pwsubau_v4i8:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pwsubau.b a0, a2, a3
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pwsubau_v4i8:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pwcvtu.wb a1, a1
+; RV64-NEXT:    pwcvtu.wb a2, a2
+; RV64-NEXT:    psub.h a1, a1, a2
+; RV64-NEXT:    padd.h a0, a0, a1
+; RV64-NEXT:    ret
+  %ext.a = zext <4 x i8> %a to <4 x i16>
+  %ext.b = zext <4 x i8> %b to <4 x i16>
+  %sum.a = add <4 x i16> %rd, %ext.a
+  %sum.b = sub <4 x i16> %sum.a, %ext.b
+  ret <4 x i16> %sum.b
+}
+
+define <2 x i32> @test_pwsubau_v2i16(<2 x i32> %rd, <2 x i16> %a, <2 x i16> 
%b) {
+; RV32-LABEL: test_pwsubau_v2i16:
+; RV32:       # %bb.0:
+; RV32-NEXT:    pwsubau.h a0, a2, a3
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: test_pwsubau_v2i16:
+; RV64:       # %bb.0:
+; RV64-NEXT:    pwcvtu.wh a1, a1
+; RV64-NEXT:    pwcvtu.wh a2, a2
+; RV64-NEXT:    psub.w a1, a1, a2
+; RV64-NEXT:    padd.w a0, a0, a1
+; RV64-NEXT:    ret
+  %ext.a = zext <2 x i16> %a to <2 x i32>
+  %ext.b = zext <2 x i16> %b to <2 x i32>
+  %sum.a = add <2 x i32> %rd, %ext.a
+  %sum.b = sub <2 x i32> %sum.a, %ext.b
+  ret <2 x i32> %sum.b
+}
+;; NOTE: These prefixes are unused and the list is autogenerated. Do not add 
tests below this line:
+; CHECK: {{.*}}

``````````

</details>


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

Reply via email to