diff mbox series

[v3] RISC-V: Support IMM for operand 0 of ussub pattern

Message ID 20240819052311.1681103-1-pan2.li@intel.com
State New
Headers show
Series [v3] RISC-V: Support IMM for operand 0 of ussub pattern | expand

Commit Message

Li, Pan2 Aug. 19, 2024, 5:23 a.m. UTC
From: Pan Li <pan2.li@intel.com>

This patch would like to allow IMM for the operand 0 of ussub pattern.
Aka .SAT_SUB(1023, y) as the below example.

Form 1:
  #define DEF_SAT_U_SUB_IMM_FMT_1(T, IMM) \
  T __attribute__((noinline))             \
  sat_u_sub_imm##IMM##_##T##_fmt_1 (T y)  \
  {                                       \
    return (T)IMM >= y ? (T)IMM - y : 0;  \
  }

DEF_SAT_U_SUB_IMM_FMT_1(uint64_t, 1023)

Before this patch:
  10   │ sat_u_sub_imm82_uint64_t_fmt_1:
  11   │     li  a5,82
  12   │     bgtu    a0,a5,.L3
  13   │     sub a0,a5,a0
  14   │     ret
  15   │ .L3:
  16   │     li  a0,0
  17   │     ret

After this patch:
  10   │ sat_u_sub_imm82_uint64_t_fmt_1:
  11   │     li  a5,82
  12   │     sltu    a4,a5,a0
  13   │     addi    a4,a4,-1
  14   │     sub a0,a5,a0
  15   │     and a0,a4,a0
  16   │     ret

The below test suites are passed for this patch:
1. The rv64gcv fully regression test.

gcc/ChangeLog:

	* config/riscv/riscv.cc (riscv_gen_unsigned_xmode_reg): Add new
	func impl to gen xmode rtx reg from operand rtx.
	(riscv_expand_ussub): Gen xmode reg for operand 1.
	* config/riscv/riscv.md: Allow const_int for operand 1.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/sat_arith.h: Add test helper macro.
	* gcc.target/riscv/sat_u_sub_imm-1.c: New test.
	* gcc.target/riscv/sat_u_sub_imm-1_1.c: New test.
	* gcc.target/riscv/sat_u_sub_imm-1_2.c: New test.
	* gcc.target/riscv/sat_u_sub_imm-2.c: New test.
	* gcc.target/riscv/sat_u_sub_imm-2_1.c: New test.
	* gcc.target/riscv/sat_u_sub_imm-2_2.c: New test.
	* gcc.target/riscv/sat_u_sub_imm-3.c: New test.
	* gcc.target/riscv/sat_u_sub_imm-3_1.c: New test.
	* gcc.target/riscv/sat_u_sub_imm-3_2.c: New test.
	* gcc.target/riscv/sat_u_sub_imm-4.c: New test.
	* gcc.target/riscv/sat_u_sub_imm-run-1.c: New test.
	* gcc.target/riscv/sat_u_sub_imm-run-2.c: New test.
	* gcc.target/riscv/sat_u_sub_imm-run-3.c: New test.
	* gcc.target/riscv/sat_u_sub_imm-run-4.c: New test.

Signed-off-by: Pan Li <pan2.li@intel.com>
---
 gcc/config/riscv/riscv.cc                     | 46 ++++++++++++++-
 gcc/config/riscv/riscv.md                     |  2 +-
 gcc/testsuite/gcc.target/riscv/sat_arith.h    | 10 ++++
 .../gcc.target/riscv/sat_u_sub_imm-1.c        | 20 +++++++
 .../gcc.target/riscv/sat_u_sub_imm-1_1.c      | 20 +++++++
 .../gcc.target/riscv/sat_u_sub_imm-1_2.c      | 20 +++++++
 .../gcc.target/riscv/sat_u_sub_imm-2.c        | 21 +++++++
 .../gcc.target/riscv/sat_u_sub_imm-2_1.c      | 21 +++++++
 .../gcc.target/riscv/sat_u_sub_imm-2_2.c      | 22 ++++++++
 .../gcc.target/riscv/sat_u_sub_imm-3.c        | 20 +++++++
 .../gcc.target/riscv/sat_u_sub_imm-3_1.c      | 21 +++++++
 .../gcc.target/riscv/sat_u_sub_imm-3_2.c      | 22 ++++++++
 .../gcc.target/riscv/sat_u_sub_imm-4.c        | 19 +++++++
 .../gcc.target/riscv/sat_u_sub_imm-run-1.c    | 56 +++++++++++++++++++
 .../gcc.target/riscv/sat_u_sub_imm-run-2.c    | 56 +++++++++++++++++++
 .../gcc.target/riscv/sat_u_sub_imm-run-3.c    | 55 ++++++++++++++++++
 .../gcc.target/riscv/sat_u_sub_imm-run-4.c    | 48 ++++++++++++++++
 17 files changed, 477 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-1_1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-1_2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-2_1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-2_2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-3_1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-3_2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-run-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-run-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-run-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-run-4.c

Comments

Jeff Law Aug. 25, 2024, 3:22 p.m. UTC | #1
On 8/18/24 11:23 PM, pan2.li@intel.com wrote:
> From: Pan Li <pan2.li@intel.com>
> 
> This patch would like to allow IMM for the operand 0 of ussub pattern.
> Aka .SAT_SUB(1023, y) as the below example.
> 
> Form 1:
>    #define DEF_SAT_U_SUB_IMM_FMT_1(T, IMM) \
>    T __attribute__((noinline))             \
>    sat_u_sub_imm##IMM##_##T##_fmt_1 (T y)  \
>    {                                       \
>      return (T)IMM >= y ? (T)IMM - y : 0;  \
>    }
> 
> DEF_SAT_U_SUB_IMM_FMT_1(uint64_t, 1023)
> 
> Before this patch:
>    10   │ sat_u_sub_imm82_uint64_t_fmt_1:
>    11   │     li  a5,82
>    12   │     bgtu    a0,a5,.L3
>    13   │     sub a0,a5,a0
>    14   │     ret
>    15   │ .L3:
>    16   │     li  a0,0
>    17   │     ret
> 
> After this patch:
>    10   │ sat_u_sub_imm82_uint64_t_fmt_1:
>    11   │     li  a5,82
>    12   │     sltu    a4,a5,a0
>    13   │     addi    a4,a4,-1
>    14   │     sub a0,a5,a0
>    15   │     and a0,a4,a0
>    16   │     ret
> 
> The below test suites are passed for this patch:
> 1. The rv64gcv fully regression test.
> 
> gcc/ChangeLog:
> 
> 	* config/riscv/riscv.cc (riscv_gen_unsigned_xmode_reg): Add new
> 	func impl to gen xmode rtx reg from operand rtx.
> 	(riscv_expand_ussub): Gen xmode reg for operand 1.
> 	* config/riscv/riscv.md: Allow const_int for operand 1.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/sat_arith.h: Add test helper macro.
> 	* gcc.target/riscv/sat_u_sub_imm-1.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-1_1.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-1_2.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-2.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-2_1.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-2_2.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-3.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-3_1.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-3_2.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-4.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-run-1.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-run-2.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-run-3.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-run-4.c: New test.
OK.  I'm assuming we don't have to worry about the case where X is wider 
than Xmode?  ie, a DImode on rv32?


Jeff
Li, Pan2 Aug. 26, 2024, 1:35 a.m. UTC | #2
Thanks Jeff.

> OK.  I'm assuming we don't have to worry about the case where X is wider 
> than Xmode?  ie, a DImode on rv32?

Yes, the DImode is disabled by ANYI iterator for ussub pattern.

Pan

-----Original Message-----
From: Jeff Law <jeffreyalaw@gmail.com> 
Sent: Sunday, August 25, 2024 11:22 PM
To: Li, Pan2 <pan2.li@intel.com>; gcc-patches@gcc.gnu.org
Cc: juzhe.zhong@rivai.ai; kito.cheng@gmail.com; rdapp.gcc@gmail.com
Subject: Re: [PATCH v3] RISC-V: Support IMM for operand 0 of ussub pattern



On 8/18/24 11:23 PM, pan2.li@intel.com wrote:
> From: Pan Li <pan2.li@intel.com>
> 
> This patch would like to allow IMM for the operand 0 of ussub pattern.
> Aka .SAT_SUB(1023, y) as the below example.
> 
> Form 1:
>    #define DEF_SAT_U_SUB_IMM_FMT_1(T, IMM) \
>    T __attribute__((noinline))             \
>    sat_u_sub_imm##IMM##_##T##_fmt_1 (T y)  \
>    {                                       \
>      return (T)IMM >= y ? (T)IMM - y : 0;  \
>    }
> 
> DEF_SAT_U_SUB_IMM_FMT_1(uint64_t, 1023)
> 
> Before this patch:
>    10   │ sat_u_sub_imm82_uint64_t_fmt_1:
>    11   │     li  a5,82
>    12   │     bgtu    a0,a5,.L3
>    13   │     sub a0,a5,a0
>    14   │     ret
>    15   │ .L3:
>    16   │     li  a0,0
>    17   │     ret
> 
> After this patch:
>    10   │ sat_u_sub_imm82_uint64_t_fmt_1:
>    11   │     li  a5,82
>    12   │     sltu    a4,a5,a0
>    13   │     addi    a4,a4,-1
>    14   │     sub a0,a5,a0
>    15   │     and a0,a4,a0
>    16   │     ret
> 
> The below test suites are passed for this patch:
> 1. The rv64gcv fully regression test.
> 
> gcc/ChangeLog:
> 
> 	* config/riscv/riscv.cc (riscv_gen_unsigned_xmode_reg): Add new
> 	func impl to gen xmode rtx reg from operand rtx.
> 	(riscv_expand_ussub): Gen xmode reg for operand 1.
> 	* config/riscv/riscv.md: Allow const_int for operand 1.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/sat_arith.h: Add test helper macro.
> 	* gcc.target/riscv/sat_u_sub_imm-1.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-1_1.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-1_2.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-2.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-2_1.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-2_2.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-3.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-3_1.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-3_2.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-4.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-run-1.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-run-2.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-run-3.c: New test.
> 	* gcc.target/riscv/sat_u_sub_imm-run-4.c: New test.
OK.  I'm assuming we don't have to worry about the case where X is wider 
than Xmode?  ie, a DImode on rv32?


Jeff
Jeff Law Aug. 26, 2024, 2:20 a.m. UTC | #3
On 8/25/24 7:35 PM, Li, Pan2 wrote:
> Thanks Jeff.
> 
>> OK.  I'm assuming we don't have to worry about the case where X is wider
>> than Xmode?  ie, a DImode on rv32?
> 
> Yes, the DImode is disabled by ANYI iterator for ussub pattern.
Thanks.  Just wanted to make sure.  And for the avoidance of doubt, this 
patch is fine for the trunk.

jeff
Li, Pan2 Aug. 26, 2024, 2:42 a.m. UTC | #4
Got it, thanks Jeff.

Pan

-----Original Message-----
From: Jeff Law <jeffreyalaw@gmail.com> 
Sent: Monday, August 26, 2024 10:21 AM
To: Li, Pan2 <pan2.li@intel.com>; gcc-patches@gcc.gnu.org
Cc: juzhe.zhong@rivai.ai; kito.cheng@gmail.com; rdapp.gcc@gmail.com
Subject: Re: [PATCH v3] RISC-V: Support IMM for operand 0 of ussub pattern



On 8/25/24 7:35 PM, Li, Pan2 wrote:
> Thanks Jeff.
> 
>> OK.  I'm assuming we don't have to worry about the case where X is wider
>> than Xmode?  ie, a DImode on rv32?
> 
> Yes, the DImode is disabled by ANYI iterator for ussub pattern.
Thanks.  Just wanted to make sure.  And for the avoidance of doubt, this 
patch is fine for the trunk.

jeff
diff mbox series

Patch

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index f266c45ed4d..5e6f3ba10e4 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -11893,6 +11893,50 @@  riscv_expand_usadd (rtx dest, rtx x, rtx y)
   emit_move_insn (dest, gen_lowpart (mode, xmode_dest));
 }
 
+/* Generate a REG rtx of Xmode from the given rtx and mode.
+   The rtx x can be REG (QI/HI/SI/DI) or const_int.
+   The machine_mode mode is the original mode from define pattern.
+
+   If rtx is REG,  the gen_lowpart of Xmode will be returned.
+
+   If rtx is const_int,  a new REG rtx will be created to hold the value of
+   const_int and then returned.
+
+   According to the gccint doc, the constants generated for modes with fewer
+   bits than in HOST_WIDE_INT must be sign extended to full width.  Thus there
+   will be two cases here,  take QImode as example.
+
+   For .SAT_SUB (127, y) in QImode, we have (const_int 127) and one simple
+   mov from const_int to the new REG rtx is good enough here.
+
+   For .SAT_SUB (254, y) in QImode, we have (const_int -2) after define_expand.
+   Aka 0xfffffffffffffffe in Xmode of RV64 but we actually need 0xfe in Xmode
+   of RV64.  So we need to cleanup the highest 56 bits of the new REG rtx moved
+   from the (const_int -2).
+
+   Then the underlying expanding can perform the code generation based on
+   the REG rtx of Xmode,  instead of taking care of these in expand func.  */
+
+static rtx
+riscv_gen_unsigned_xmode_reg (rtx x, machine_mode mode)
+{
+  if (!CONST_INT_P (x))
+    return gen_lowpart (Xmode, x);
+
+  rtx xmode_x = gen_reg_rtx (Xmode);
+
+  if (mode == Xmode)
+    emit_move_insn (xmode_x, x);
+  else
+    {
+      rtx reg_x = gen_reg_rtx (mode);
+      emit_move_insn (reg_x, x);
+      riscv_emit_unary (ZERO_EXTEND, xmode_x, reg_x);
+    }
+
+  return xmode_x;
+}
+
 /* Implements the unsigned saturation sub standard name usadd for int mode.
 
    z = SAT_SUB(x, y).
@@ -11906,7 +11950,7 @@  void
 riscv_expand_ussub (rtx dest, rtx x, rtx y)
 {
   machine_mode mode = GET_MODE (dest);
-  rtx xmode_x = gen_lowpart (Xmode, x);
+  rtx xmode_x = riscv_gen_unsigned_xmode_reg (x, mode);
   rtx xmode_y = gen_lowpart (Xmode, y);
   rtx xmode_lt = gen_reg_rtx (Xmode);
   rtx xmode_minus = gen_reg_rtx (Xmode);
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index a9cbcca9bd4..a94705a8e7c 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -4369,7 +4369,7 @@  (define_expand "usadd<mode>3"
 
 (define_expand "ussub<mode>3"
   [(match_operand:ANYI 0 "register_operand")
-   (match_operand:ANYI 1 "register_operand")
+   (match_operand:ANYI 1 "reg_or_int_operand")
    (match_operand:ANYI 2 "register_operand")]
   ""
   {
diff --git a/gcc/testsuite/gcc.target/riscv/sat_arith.h b/gcc/testsuite/gcc.target/riscv/sat_arith.h
index cf055410fd1..29e45152847 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_arith.h
+++ b/gcc/testsuite/gcc.target/riscv/sat_arith.h
@@ -201,6 +201,13 @@  sat_u_sub_##T##_fmt_12 (T x, T y)                      \
   return !overflow ? ret : 0;                          \
 }
 
+#define DEF_SAT_U_SUB_IMM_FMT_1(T, IMM) \
+T __attribute__((noinline))             \
+sat_u_sub_imm##IMM##_##T##_fmt_1 (T y)  \
+{                                       \
+  return (T)IMM >= y ? (T)IMM - y : 0;  \
+}
+
 #define RUN_SAT_U_SUB_FMT_1(T, x, y) sat_u_sub_##T##_fmt_1(x, y)
 #define RUN_SAT_U_SUB_FMT_2(T, x, y) sat_u_sub_##T##_fmt_2(x, y)
 #define RUN_SAT_U_SUB_FMT_3(T, x, y) sat_u_sub_##T##_fmt_3(x, y)
@@ -214,6 +221,9 @@  sat_u_sub_##T##_fmt_12 (T x, T y)                      \
 #define RUN_SAT_U_SUB_FMT_11(T, x, y) sat_u_sub_##T##_fmt_11(x, y)
 #define RUN_SAT_U_SUB_FMT_12(T, x, y) sat_u_sub_##T##_fmt_12(x, y)
 
+#define RUN_SAT_U_SUB_IMM_FMT_1(T, IMM, y, expect) \
+  if (sat_u_sub_imm##IMM##_##T##_fmt_1(y) != expect) __builtin_abort ()
+
 /******************************************************************************/
 /* Saturation Truncate (unsigned and signed)                                  */
 /******************************************************************************/
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-1.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-1.c
new file mode 100644
index 00000000000..3e6fbfe6aca
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-1.c
@@ -0,0 +1,20 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -O3 -fdump-rtl-expand-details -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "sat_arith.h"
+
+/*
+** sat_u_sub_imm11_uint8_t_fmt_1:
+** li\s+[atx][0-9]+,\s*11
+** sub\s+[atx][0-9]+,\s*[atx][0-9]+,\s*a0
+** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
+** addi\s+a0,\s*a0,\s*-1
+** and\s+a0,\s*a0,\s*[atx][0-9]+
+** andi\s+a0,\s*a0,\s*0xff
+** ret
+*/
+
+DEF_SAT_U_SUB_IMM_FMT_1(uint8_t, 11)
+
+/* { dg-final { scan-rtl-dump-times ".SAT_SUB " 2 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-1_1.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-1_1.c
new file mode 100644
index 00000000000..586f58a93fc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-1_1.c
@@ -0,0 +1,20 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -O3 -fdump-rtl-expand-details -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "sat_arith.h"
+
+/*
+** sat_u_sub_imm128_uint8_t_fmt_1:
+** li\s+[atx][0-9]+,\s*128
+** sub\s+[atx][0-9]+,\s*[atx][0-9]+,\s*a0
+** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
+** addi\s+a0,\s*a0,\s*-1
+** and\s+a0,\s*a0,\s*[atx][0-9]+
+** andi\s+a0,\s*a0,\s*0xff
+** ret
+*/
+
+DEF_SAT_U_SUB_IMM_FMT_1(uint8_t, 128)
+
+/* { dg-final { scan-rtl-dump-times ".SAT_SUB " 2 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-1_2.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-1_2.c
new file mode 100644
index 00000000000..463a3ad9578
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-1_2.c
@@ -0,0 +1,20 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -O3 -fdump-rtl-expand-details -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "sat_arith.h"
+
+/*
+** sat_u_sub_imm253_uint8_t_fmt_1:
+** li\s+[atx][0-9]+,\s*253
+** sub\s+[atx][0-9]+,\s*[atx][0-9]+,\s*a0
+** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
+** addi\s+a0,\s*a0,\s*-1
+** and\s+a0,\s*a0,\s*[atx][0-9]+
+** andi\s+a0,\s*a0,\s*0xff
+** ret
+*/
+
+DEF_SAT_U_SUB_IMM_FMT_1(uint8_t, 253)
+
+/* { dg-final { scan-rtl-dump-times ".SAT_SUB " 2 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-2.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-2.c
new file mode 100644
index 00000000000..df38e126277
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-2.c
@@ -0,0 +1,21 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -O3 -fdump-rtl-expand-details -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "sat_arith.h"
+
+/*
+** sat_u_sub_imm6_uint16_t_fmt_1:
+** li\s+[atx][0-9]+,\s*6
+** sub\s+[atx][0-9]+,\s*[atx][0-9]+,\s*a0
+** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
+** addi\s+a0,\s*a0,\s*-1
+** and\s+a0,\s*a0,\s*[atx][0-9]+
+** slli\s+a0,\s*a0,\s*48
+** srli\s+a0,\s*a0,\s*48
+** ret
+*/
+
+DEF_SAT_U_SUB_IMM_FMT_1(uint16_t, 6)
+
+/* { dg-final { scan-rtl-dump-times ".SAT_SUB " 2 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-2_1.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-2_1.c
new file mode 100644
index 00000000000..b714e46300b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-2_1.c
@@ -0,0 +1,21 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -O3 -fdump-rtl-expand-details -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "sat_arith.h"
+
+/*
+** sat_u_sub_imm32768_uint16_t_fmt_1:
+** li\s+[atx][0-9]+,\s*32768
+** sub\s+[atx][0-9]+,\s*[atx][0-9]+,\s*a0
+** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
+** addi\s+a0,\s*a0,\s*-1
+** and\s+a0,\s*a0,\s*[atx][0-9]+
+** slli\s+a0,\s*a0,\s*48
+** srli\s+a0,\s*a0,\s*48
+** ret
+*/
+
+DEF_SAT_U_SUB_IMM_FMT_1(uint16_t, 32768)
+
+/* { dg-final { scan-rtl-dump-times ".SAT_SUB " 2 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-2_2.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-2_2.c
new file mode 100644
index 00000000000..55fe313868e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-2_2.c
@@ -0,0 +1,22 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -O3 -fdump-rtl-expand-details -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "sat_arith.h"
+
+/*
+** sat_u_sub_imm65533_uint16_t_fmt_1:
+** li\s+[atx][0-9]+,\s*65536
+** addi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*-3
+** sub\s+[atx][0-9]+,\s*[atx][0-9]+,\s*a0
+** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
+** addi\s+a0,\s*a0,\s*-1
+** and\s+a0,\s*a0,\s*[atx][0-9]+
+** slli\s+a0,\s*a0,\s*48
+** srli\s+a0,\s*a0,\s*48
+** ret
+*/
+
+DEF_SAT_U_SUB_IMM_FMT_1(uint16_t, 65533)
+
+/* { dg-final { scan-rtl-dump-times ".SAT_SUB " 2 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-3.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-3.c
new file mode 100644
index 00000000000..b5c31625868
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-3.c
@@ -0,0 +1,20 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -O3 -fdump-rtl-expand-details -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "sat_arith.h"
+
+/*
+** sat_u_sub_imm255_uint32_t_fmt_1:
+** li\s+[atx][0-9]+,\s*255
+** sub\s+[atx][0-9]+,\s*[atx][0-9]+,\s*a0
+** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
+** addi\s+a0,\s*a0,\s*-1
+** and\s+a0,\s*a0,\s*[atx][0-9]+
+** sext\.w\s+a0,\s*a0
+** ret
+*/
+
+DEF_SAT_U_SUB_IMM_FMT_1(uint32_t, 255)
+
+/* { dg-final { scan-rtl-dump-times ".SAT_SUB " 2 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-3_1.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-3_1.c
new file mode 100644
index 00000000000..9762a1fad6d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-3_1.c
@@ -0,0 +1,21 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -O3 -fdump-rtl-expand-details -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "sat_arith.h"
+
+/*
+** sat_u_sub_imm2147483648_uint32_t_fmt_1:
+** li\s+[atx][0-9]+,\s*1
+** slli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*31
+** sub\s+[atx][0-9]+,\s*[atx][0-9]+,\s*a0
+** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
+** addi\s+a0,\s*a0,\s*-1
+** and\s+a0,\s*a0,\s*[atx][0-9]+
+** sext\.w\s+a0,\s*a0
+** ret
+*/
+
+DEF_SAT_U_SUB_IMM_FMT_1(uint32_t, 2147483648)
+
+/* { dg-final { scan-rtl-dump-times ".SAT_SUB " 2 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-3_2.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-3_2.c
new file mode 100644
index 00000000000..bd140d22ec0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-3_2.c
@@ -0,0 +1,22 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -O3 -fdump-rtl-expand-details -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "sat_arith.h"
+
+/*
+** sat_u_sub_imm68719476732_uint32_t_fmt_1:
+** li\s+[atx][0-9]+,\s*1
+** slli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*32
+** addi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*-4
+** sub\s+[atx][0-9]+,\s*[atx][0-9]+,\s*a0
+** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
+** addi\s+a0,\s*a0,\s*-1
+** and\s+a0,\s*a0,\s*[atx][0-9]+
+** sext\.w\s+a0,\s*a0
+** ret
+*/
+
+DEF_SAT_U_SUB_IMM_FMT_1(uint32_t, 68719476732)
+
+/* { dg-final { scan-rtl-dump-times ".SAT_SUB " 2 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-4.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-4.c
new file mode 100644
index 00000000000..b9f796bb9aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-4.c
@@ -0,0 +1,19 @@ 
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc -mabi=lp64d -O3 -fdump-rtl-expand-details -fno-schedule-insns -fno-schedule-insns2" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include "sat_arith.h"
+
+/*
+** sat_u_sub_imm82_uint64_t_fmt_1:
+** li\s+[atx][0-9]+,\s*82
+** sub\s+[atx][0-9]+,\s*[atx][0-9]+,\s*a0
+** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
+** addi\s+a0,\s*a0,\s*-1
+** and\s+a0,\s*a0,\s*[atx][0-9]+
+** ret
+*/
+
+DEF_SAT_U_SUB_IMM_FMT_1(uint64_t, 82)
+
+/* { dg-final { scan-rtl-dump-times ".SAT_SUB " 2 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-run-1.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-run-1.c
new file mode 100644
index 00000000000..5091872d208
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-run-1.c
@@ -0,0 +1,56 @@ 
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+
+DEF_SAT_U_SUB_IMM_FMT_1(uint8_t, 0)
+DEF_SAT_U_SUB_IMM_FMT_1(uint8_t, 1)
+DEF_SAT_U_SUB_IMM_FMT_1(uint8_t, 5)
+DEF_SAT_U_SUB_IMM_FMT_1(uint8_t, 127)
+DEF_SAT_U_SUB_IMM_FMT_1(uint8_t, 128)
+DEF_SAT_U_SUB_IMM_FMT_1(uint8_t, 254)
+DEF_SAT_U_SUB_IMM_FMT_1(uint8_t, 255)
+
+#define T                       uint8_t
+#define RUN(T, imm, op, expect) RUN_SAT_U_SUB_IMM_FMT_1(T, imm, op, expect)
+
+T d[][3] = {
+  /* arg_0, arg_1, expect */
+  {      0,     0,      0, },
+  {      1,     0,      1, },
+  {      1,   255,      0, },
+  {    254,   254,      0, },
+  {    254,   255,      0, },
+  {    254,     2,    252, },
+  {    255,   254,      1, },
+  {    255,     0,    255, },
+  {      5,     2,      3, },
+  {      5,     6,      0, },
+  {    127,     0,    127, },
+  {    128,   129,      0, },
+};
+
+int
+main ()
+{
+  RUN (T,   0, d[0][1], d[0][2]);
+
+  RUN (T,   1, d[1][1], d[1][2]);
+  RUN (T,   1, d[2][1], d[2][2]);
+
+  RUN (T, 254, d[3][1], d[3][2]);
+  RUN (T, 254, d[4][1], d[4][2]);
+  RUN (T, 254, d[5][1], d[5][2]);
+
+  RUN (T, 255, d[6][1], d[6][2]);
+  RUN (T, 255, d[7][1], d[7][2]);
+
+  RUN (T,   5, d[8][1], d[8][2]);
+  RUN (T,   5, d[9][1], d[9][2]);
+
+  RUN (T, 127, d[10][1], d[10][2]);
+
+  RUN (T, 128, d[11][1], d[11][2]);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-run-2.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-run-2.c
new file mode 100644
index 00000000000..2bc3be3efc5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-run-2.c
@@ -0,0 +1,56 @@ 
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+
+DEF_SAT_U_SUB_IMM_FMT_1(uint16_t, 0)
+DEF_SAT_U_SUB_IMM_FMT_1(uint16_t, 1)
+DEF_SAT_U_SUB_IMM_FMT_1(uint16_t, 5)
+DEF_SAT_U_SUB_IMM_FMT_1(uint16_t, 32767)
+DEF_SAT_U_SUB_IMM_FMT_1(uint16_t, 32768)
+DEF_SAT_U_SUB_IMM_FMT_1(uint16_t, 65534)
+DEF_SAT_U_SUB_IMM_FMT_1(uint16_t, 65535)
+
+#define T                       uint16_t
+#define RUN(T, imm, op, expect) RUN_SAT_U_SUB_IMM_FMT_1(T, imm, op, expect)
+
+T d[][3] = {
+  /* arg_0, arg_1, expect */
+  {        0,     0,      0, },
+  {        1,     0,      1, },
+  {        1, 65535,      0, },
+  {    65534, 65534,      0, },
+  {    65534, 65535,      0, },
+  {    65534,     2,  65532, },
+  {    65535, 65534,      1, },
+  {    65535,     0,  65535, },
+  {        5,     2,      3, },
+  {        5,     6,      0, },
+  {    32767,     0,  32767, },
+  {    32768, 32767,      1, },
+};
+
+int
+main ()
+{
+  RUN (T,     0, d[0][1], d[0][2]);
+
+  RUN (T,     1, d[1][1], d[1][2]);
+  RUN (T,     1, d[2][1], d[2][2]);
+
+  RUN (T, 65534, d[3][1], d[3][2]);
+  RUN (T, 65534, d[4][1], d[4][2]);
+  RUN (T, 65534, d[5][1], d[5][2]);
+
+  RUN (T, 65535, d[6][1], d[6][2]);
+  RUN (T, 65535, d[7][1], d[7][2]);
+
+  RUN (T,     5, d[8][1], d[8][2]);
+  RUN (T,     5, d[9][1], d[9][2]);
+
+  RUN (T, 32767, d[10][1], d[10][2]);
+
+  RUN (T, 32768, d[11][1], d[11][2]);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-run-3.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-run-3.c
new file mode 100644
index 00000000000..b1d1ee33135
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-run-3.c
@@ -0,0 +1,55 @@ 
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+
+DEF_SAT_U_SUB_IMM_FMT_1(uint32_t, 0)
+DEF_SAT_U_SUB_IMM_FMT_1(uint32_t, 1)
+DEF_SAT_U_SUB_IMM_FMT_1(uint32_t, 5)
+DEF_SAT_U_SUB_IMM_FMT_1(uint32_t, 2147483647)
+DEF_SAT_U_SUB_IMM_FMT_1(uint32_t, 2147483648)
+DEF_SAT_U_SUB_IMM_FMT_1(uint32_t, 4294967294)
+DEF_SAT_U_SUB_IMM_FMT_1(uint32_t, 4294967295)
+
+#define T                       uint32_t
+#define RUN(T, imm, op, expect) RUN_SAT_U_SUB_IMM_FMT_1(T, imm, op, expect)
+
+T d[][3] = {
+  /* arg_0, arg_1, expect */
+  {          0,          0,          0, },
+  {          1,          0,          1, },
+  {          1, 4294967295,          0, },
+  { 4294967294, 4294967294,          0, },
+  { 4294967294, 4294967295,          0, },
+  { 4294967294,          2, 4294967292, },
+  { 4294967295, 4294967294,          1, },
+  { 4294967295,          0, 4294967295, },
+  {          5,          2,          3, },
+  {          5,          6,          0, },
+  { 2147483647,          0, 2147483647, },
+  { 2147483648, 2147483647,          1, },
+};
+
+int
+main ()
+{
+  RUN (T,          0, d[0][1], d[0][2]);
+
+  RUN (T,          1, d[1][1], d[1][2]);
+  RUN (T,          1, d[2][1], d[2][2]);
+
+  RUN (T, 4294967294, d[3][1], d[3][2]);
+  RUN (T, 4294967294, d[4][1], d[4][2]);
+  RUN (T, 4294967294, d[5][1], d[5][2]);
+
+  RUN (T, 4294967295, d[6][1], d[6][2]);
+  RUN (T, 4294967295, d[7][1], d[7][2]);
+
+  RUN (T,          5, d[8][1], d[8][2]);
+  RUN (T,          5, d[9][1], d[9][2]);
+
+  RUN (T, 2147483647, d[10][1], d[10][2]);
+  RUN (T, 2147483648, d[11][1], d[11][2]);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-run-4.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-run-4.c
new file mode 100644
index 00000000000..2539d753c11
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub_imm-run-4.c
@@ -0,0 +1,48 @@ 
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+
+DEF_SAT_U_SUB_IMM_FMT_1(uint64_t, 0)
+DEF_SAT_U_SUB_IMM_FMT_1(uint64_t, 1)
+DEF_SAT_U_SUB_IMM_FMT_1(uint64_t, 5)
+DEF_SAT_U_SUB_IMM_FMT_1(uint64_t, 18446744073709551614u)
+DEF_SAT_U_SUB_IMM_FMT_1(uint64_t, 18446744073709551615u)
+
+#define T                       uint64_t
+#define RUN(T, imm, op, expect) RUN_SAT_U_SUB_IMM_FMT_1(T, imm, op, expect)
+
+T d[][3] = {
+  /* arg_0, arg_1, expect */
+  {                     0,                     0,                     0, },
+  {                     1,                     0,                     1, },
+  {                     1, 18446744073709551615u,                     0, },
+  { 18446744073709551614u, 18446744073709551614u,                     0, },
+  { 18446744073709551614u, 18446744073709551615u,                     0, },
+  { 18446744073709551614u,                     2, 18446744073709551612u, },
+  { 18446744073709551615u, 18446744073709551614u,                     1, },
+  { 18446744073709551615u,                     0, 18446744073709551615u, },
+  {                     5,                     2,                     3, },
+  {                     5,                     6,                     0, },
+};
+
+int
+main ()
+{
+  RUN (T,                     0, d[0][1], d[0][2]);
+
+  RUN (T,                     1, d[1][1], d[1][2]);
+  RUN (T,                     1, d[2][1], d[2][2]);
+
+  RUN (T, 18446744073709551614u, d[3][1], d[3][2]);
+  RUN (T, 18446744073709551614u, d[4][1], d[4][2]);
+  RUN (T, 18446744073709551614u, d[5][1], d[5][2]);
+
+  RUN (T, 18446744073709551615u, d[6][1], d[6][2]);
+  RUN (T, 18446744073709551615u, d[7][1], d[7][2]);
+
+  RUN (T,                     5, d[8][1], d[8][2]);
+  RUN (T,                     5, d[9][1], d[9][2]);
+
+  return 0;
+}