diff mbox series

[v3] RISC-V: Implement .SAT_SUB for unsigned scalar int

Message ID 20240607135100.4135976-1-pan2.li@intel.com
State New
Headers show
Series [v3] RISC-V: Implement .SAT_SUB for unsigned scalar int | expand

Commit Message

Li, Pan2 June 7, 2024, 1:51 p.m. UTC
From: Pan Li <pan2.li@intel.com>

As the middle support of .SAT_SUB committed,  implement the unsigned
scalar int of .SAT_SUB for the riscv backend.  Consider below example
code:

T __attribute__((noinline))        \
sat_u_sub_##T##_fmt_1 (T x, T y)   \
{                                  \
  return (x - y) & (-(T)(x >= y)); \
}

T __attribute__((noinline))       \
sat_u_sub_##T##_fmt_2 (T x, T y)  \
{                                 \
  return (x - y) & (-(T)(x > y)); \
}

DEF_SAT_U_SUB_FMT_1(uint64_t);
DEF_SAT_U_SUB_FMT_2(uint64_t);

Before this patch:
sat_u_sub_uint64_t_fmt_1:
        bltu    a0,a1,.L2
        sub     a0,a0,a1
        ret
.L2:
        li      a0,0
        ret

After this patch:
sat_u_sub_uint64_t_fmt_1:
        sltu    a5,a0,a1
        addi    a5,a5,-1
        sub     a0,a0,a1
        and     a0,a5,a0
        ret

ToDo:
Only above 2 forms of .SAT_SUB are support for now,  we will
support more forms of .SAT_SUB in the middle-end in short future.

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

gcc/ChangeLog:

	* config/riscv/riscv-protos.h (riscv_expand_ussub): Add new func
	decl for ussub expanding.
	* config/riscv/riscv.cc (riscv_expand_ussub): Ditto but for impl.
	* config/riscv/riscv.md (ussub<mode>3): Add new pattern ussub
	for scalar modes.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/sat_arith.h: Add test macros and comments.
	* gcc.target/riscv/sat_u_sub-1.c: New test.
	* gcc.target/riscv/sat_u_sub-2.c: New test.
	* gcc.target/riscv/sat_u_sub-3.c: New test.
	* gcc.target/riscv/sat_u_sub-4.c: New test.
	* gcc.target/riscv/sat_u_sub-5.c: New test.
	* gcc.target/riscv/sat_u_sub-6.c: New test.
	* gcc.target/riscv/sat_u_sub-7.c: New test.
	* gcc.target/riscv/sat_u_sub-8.c: New test.
	* gcc.target/riscv/sat_u_sub-run-1.c: New test.
	* gcc.target/riscv/sat_u_sub-run-2.c: New test.
	* gcc.target/riscv/sat_u_sub-run-3.c: New test.
	* gcc.target/riscv/sat_u_sub-run-4.c: New test.
	* gcc.target/riscv/sat_u_sub-run-5.c: New test.
	* gcc.target/riscv/sat_u_sub-run-6.c: New test.
	* gcc.target/riscv/sat_u_sub-run-7.c: New test.
	* gcc.target/riscv/sat_u_sub-run-8.c: New test.

Signed-off-by: Pan Li <pan2.li@intel.com>
---
 gcc/config/riscv/riscv-protos.h               |  1 +
 gcc/config/riscv/riscv.cc                     | 35 +++++++++++++++++++
 gcc/config/riscv/riscv.md                     | 11 ++++++
 gcc/testsuite/gcc.target/riscv/sat_arith.h    | 23 ++++++++++++
 gcc/testsuite/gcc.target/riscv/sat_u_sub-1.c  | 18 ++++++++++
 gcc/testsuite/gcc.target/riscv/sat_u_sub-2.c  | 19 ++++++++++
 gcc/testsuite/gcc.target/riscv/sat_u_sub-3.c  | 18 ++++++++++
 gcc/testsuite/gcc.target/riscv/sat_u_sub-4.c  | 17 +++++++++
 gcc/testsuite/gcc.target/riscv/sat_u_sub-5.c  | 18 ++++++++++
 gcc/testsuite/gcc.target/riscv/sat_u_sub-6.c  | 19 ++++++++++
 gcc/testsuite/gcc.target/riscv/sat_u_sub-7.c  | 18 ++++++++++
 gcc/testsuite/gcc.target/riscv/sat_u_sub-8.c  | 17 +++++++++
 .../gcc.target/riscv/sat_u_sub-run-1.c        | 25 +++++++++++++
 .../gcc.target/riscv/sat_u_sub-run-2.c        | 25 +++++++++++++
 .../gcc.target/riscv/sat_u_sub-run-3.c        | 25 +++++++++++++
 .../gcc.target/riscv/sat_u_sub-run-4.c        | 25 +++++++++++++
 .../gcc.target/riscv/sat_u_sub-run-5.c        | 25 +++++++++++++
 .../gcc.target/riscv/sat_u_sub-run-6.c        | 25 +++++++++++++
 .../gcc.target/riscv/sat_u_sub-run-7.c        | 25 +++++++++++++
 .../gcc.target/riscv/sat_u_sub-run-8.c        | 25 +++++++++++++
 20 files changed, 414 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub-5.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub-6.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub-7.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub-8.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub-run-1.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub-run-2.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub-run-3.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub-run-4.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub-run-5.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub-run-6.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub-run-7.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/sat_u_sub-run-8.c

Comments

Robin Dapp June 7, 2024, 1:57 p.m. UTC | #1
LGTM.

Let's keep in mind that min/max will save us two insns(?)
and a conditional move would save us one.

Regards
 Robin
Li, Pan2 June 8, 2024, 8:37 a.m. UTC | #2
> LGTM.

Committed, thanks Robin.

> Let's keep in mind that min/max will save us two insns(?)
> and a conditional move would save us one.

Got it, cmov is well designed for such case(s).

Pan


-----Original Message-----
From: Robin Dapp <rdapp.gcc@gmail.com> 
Sent: Friday, June 7, 2024 9:57 PM
To: Li, Pan2 <pan2.li@intel.com>; gcc-patches@gcc.gnu.org
Cc: rdapp.gcc@gmail.com; juzhe.zhong@rivai.ai; kito.cheng@gmail.com
Subject: Re: [PATCH v3] RISC-V: Implement .SAT_SUB for unsigned scalar int

LGTM.

Let's keep in mind that min/max will save us two insns(?)
and a conditional move would save us one.

Regards
 Robin
diff mbox series

Patch

diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 0704968561b..09eb3a574e3 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -134,6 +134,7 @@  extern bool
 riscv_zcmp_valid_stack_adj_bytes_p (HOST_WIDE_INT, int);
 extern void riscv_legitimize_poly_move (machine_mode, rtx, rtx, rtx);
 extern void riscv_expand_usadd (rtx, rtx, rtx);
+extern void riscv_expand_ussub (rtx, rtx, rtx);
 
 #ifdef RTX_CODE
 extern void riscv_expand_int_scc (rtx, enum rtx_code, rtx, rtx, bool *invert_ptr = 0);
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 9704ff9c6a0..95f3636f8e4 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -11612,6 +11612,41 @@  riscv_expand_usadd (rtx dest, rtx x, rtx y)
   emit_move_insn (dest, gen_lowpart (mode, xmode_dest));
 }
 
+/* Implements the unsigned saturation sub standard name usadd for int mode.
+
+   z = SAT_SUB(x, y).
+   =>
+   1. minus = x - y.
+   2. lt = x < y.
+   3. lt = lt - 1.
+   4. z = minus & lt.  */
+
+void
+riscv_expand_ussub (rtx dest, rtx x, rtx y)
+{
+  machine_mode mode = GET_MODE (dest);
+  rtx pmode_x = gen_lowpart (Pmode, x);
+  rtx pmode_y = gen_lowpart (Pmode, y);
+  rtx pmode_lt = gen_reg_rtx (Pmode);
+  rtx pmode_minus = gen_reg_rtx (Pmode);
+  rtx pmode_dest = gen_reg_rtx (Pmode);
+
+  /* Step-1: minus = x - y  */
+  riscv_emit_binary (MINUS, pmode_minus, pmode_x, pmode_y);
+
+  /* Step-2: lt = x < y  */
+  riscv_emit_binary (LTU, pmode_lt, pmode_x, pmode_y);
+
+  /* Step-3: lt = lt - 1 (lt + (-1))  */
+  riscv_emit_binary (PLUS, pmode_lt, pmode_lt, CONSTM1_RTX (Pmode));
+
+  /* Step-4: pmode_dest = minus & lt  */
+  riscv_emit_binary (AND, pmode_dest, pmode_lt, pmode_minus);
+
+  /* Step-5: dest = pmode_dest  */
+  emit_move_insn (dest, gen_lowpart (mode, pmode_dest));
+}
+
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_ALIGNED_HI_OP
 #define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md
index e57bfcf616a..7a9454de430 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -4228,6 +4228,17 @@  (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 2 "register_operand")]
+  ""
+  {
+    riscv_expand_ussub (operands[0], operands[1], operands[2]);
+    DONE;
+  }
+)
+
 ;; These are forms of (x << C1) + C2, potentially canonicalized from
 ;; ((x + C2') << C1.  Depending on the cost to load C2 vs C2' we may
 ;; want to go ahead and recognize this form as C2 may be cheaper to
diff --git a/gcc/testsuite/gcc.target/riscv/sat_arith.h b/gcc/testsuite/gcc.target/riscv/sat_arith.h
index 976ef1c44c1..9c60ac09f41 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_arith.h
+++ b/gcc/testsuite/gcc.target/riscv/sat_arith.h
@@ -3,6 +3,9 @@ 
 
 #include <stdint-gcc.h>
 
+/******************************************************************************/
+/* Saturation Add (unsigned and signed)                                       */
+/******************************************************************************/
 #define DEF_SAT_U_ADD_FMT_1(T)             \
 T __attribute__((noinline))                \
 sat_u_add_##T##_fmt_1 (T x, T y)           \
@@ -72,4 +75,24 @@  vec_sat_u_add_##T##_fmt_1 (T *out, T *op_1, T *op_2, unsigned limit) \
 #define RUN_VEC_SAT_U_ADD_FMT_1(T, out, op_1, op_2, N) \
   vec_sat_u_add_##T##_fmt_1(out, op_1, op_2, N)
 
+/******************************************************************************/
+/* Saturation Sub (Unsigned and Signed)                                       */
+/******************************************************************************/
+#define DEF_SAT_U_SUB_FMT_1(T)     \
+T __attribute__((noinline))        \
+sat_u_sub_##T##_fmt_1 (T x, T y)   \
+{                                  \
+  return (x - y) & (-(T)(x >= y)); \
+}
+
+#define DEF_SAT_U_SUB_FMT_2(T)    \
+T __attribute__((noinline))       \
+sat_u_sub_##T##_fmt_2 (T x, T y)  \
+{                                 \
+  return (x - y) & (-(T)(x > y)); \
+}
+
+#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)
+
 #endif
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub-1.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub-1.c
new file mode 100644
index 00000000000..73be7d59422
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub-1.c
@@ -0,0 +1,18 @@ 
+/* { 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_uint8_t_fmt_1:
+** sub\s+[atx][0-9]+,\s*a0,\s*a1
+** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
+** addi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*-1
+** and\s+a0,\s*a0,\s*[atx][0-9]+
+** andi\s+a0,\s*a0,\s*0xff
+** ret
+*/
+DEF_SAT_U_SUB_FMT_1(uint8_t)
+
+/* { dg-final { scan-rtl-dump-times ".SAT_SUB " 2 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub-2.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub-2.c
new file mode 100644
index 00000000000..7bd5efcd9d9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub-2.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_uint16_t_fmt_1:
+** sub\s+[atx][0-9]+,\s*a0,\s*a1
+** sltu\s+[atx][0-9]+,\s*a0,\s*a1
+** addi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*-1
+** and\s+a0,\s*[atx][0-9]+,\s*[atx][0-9]+
+** slli\s+a0,\s*a0,\s*48
+** srli\s+a0,\s*a0,\s*48
+** ret
+*/
+DEF_SAT_U_SUB_FMT_1(uint16_t)
+
+/* { dg-final { scan-rtl-dump-times ".SAT_SUB " 2 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub-3.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub-3.c
new file mode 100644
index 00000000000..a60fc9ba71e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub-3.c
@@ -0,0 +1,18 @@ 
+/* { 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_uint32_t_fmt_1:
+** sub\s+[atx][0-9]+,\s*a0,\s*a1
+** sltu\s+[atx][0-9]+,\s*a0,\s*a1
+** addi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*-1
+** and\s+a0,\s*[atx][0-9]+,\s*[atx][0-9]+
+** sext.w\s+a0,\s*a0
+** ret
+*/
+DEF_SAT_U_SUB_FMT_1(uint32_t)
+
+/* { dg-final { scan-rtl-dump-times ".SAT_SUB " 2 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub-4.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub-4.c
new file mode 100644
index 00000000000..bae46a0bd83
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub-4.c
@@ -0,0 +1,17 @@ 
+/* { 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_uint64_t_fmt_1:
+** sub\s+[atx][0-9]+,\s*a0,\s*a1
+** sltu\s+[atx][0-9]+,\s*a0,\s*a1
+** addi\s+a0,\s*[atx][0-9]+,\s*-1
+** and\s+a0,\s*[atx][0-9]+,\s*[atx][0-9]+
+** ret
+*/
+DEF_SAT_U_SUB_FMT_1(uint64_t)
+
+/* { dg-final { scan-rtl-dump-times ".SAT_SUB " 2 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub-5.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub-5.c
new file mode 100644
index 00000000000..e917487a640
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub-5.c
@@ -0,0 +1,18 @@ 
+/* { 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_uint8_t_fmt_2:
+** sub\s+[atx][0-9]+,\s*a0,\s*a1
+** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
+** addi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*-1
+** and\s+a0,\s*a0,\s*[atx][0-9]+
+** andi\s+a0,\s*a0,\s*0xff
+** ret
+*/
+DEF_SAT_U_SUB_FMT_2(uint8_t)
+
+/* { dg-final { scan-rtl-dump-times ".SAT_SUB " 2 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub-6.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub-6.c
new file mode 100644
index 00000000000..4e3c91d205d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub-6.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_uint16_t_fmt_2:
+** sub\s+[atx][0-9]+,\s*a0,\s*a1
+** sltu\s+[atx][0-9]+,\s*a0,\s*a1
+** addi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*-1
+** and\s+a0,\s*[atx][0-9]+,\s*[atx][0-9]+
+** slli\s+a0,\s*a0,\s*48
+** srli\s+a0,\s*a0,\s*48
+** ret
+*/
+DEF_SAT_U_SUB_FMT_2(uint16_t)
+
+/* { dg-final { scan-rtl-dump-times ".SAT_SUB " 2 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub-7.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub-7.c
new file mode 100644
index 00000000000..e1b0eaccf95
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub-7.c
@@ -0,0 +1,18 @@ 
+/* { 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_uint32_t_fmt_2:
+** sub\s+[atx][0-9]+,\s*a0,\s*a1
+** sltu\s+[atx][0-9]+,\s*a0,\s*a1
+** addi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*-1
+** and\s+a0,\s*[atx][0-9]+,\s*[atx][0-9]+
+** sext.w\s+a0,\s*a0
+** ret
+*/
+DEF_SAT_U_SUB_FMT_2(uint32_t)
+
+/* { dg-final { scan-rtl-dump-times ".SAT_SUB " 2 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub-8.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub-8.c
new file mode 100644
index 00000000000..d73f00fcf02
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub-8.c
@@ -0,0 +1,17 @@ 
+/* { 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_uint64_t_fmt_2:
+** sub\s+[atx][0-9]+,\s*a0,\s*a1
+** sltu\s+[atx][0-9]+,\s*a0,\s*a1
+** addi\s+a0,\s*[atx][0-9]+,\s*-1
+** and\s+a0,\s*[atx][0-9]+,\s*[atx][0-9]+
+** ret
+*/
+DEF_SAT_U_SUB_FMT_2(uint64_t)
+
+/* { dg-final { scan-rtl-dump-times ".SAT_SUB " 2 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-1.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-1.c
new file mode 100644
index 00000000000..931420a3098
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-1.c
@@ -0,0 +1,25 @@ 
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+
+#define T              uint8_t
+#define RUN_SAT_BINARY RUN_SAT_U_SUB_FMT_1
+
+DEF_SAT_U_SUB_FMT_1(T)
+
+T test_data[][3] = {
+  /* arg_0, arg_1, expect */
+  {      0,     0,      0, },
+  {      0,     1,      0, },
+  {      1,     1,      0, },
+  {    255,   254,      1, },
+  {    255,   255,      0, },
+  {    254,   255,      0, },
+  {    253,   254,      0, },
+  {      0,   255,      0, },
+  {      1,   255,      0, },
+  {     32,     5,     27, },
+};
+
+#include "scalar_sat_binary.h"
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-2.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-2.c
new file mode 100644
index 00000000000..1534cf99827
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-2.c
@@ -0,0 +1,25 @@ 
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+
+#define T              uint16_t
+#define RUN_SAT_BINARY RUN_SAT_U_SUB_FMT_1
+
+DEF_SAT_U_SUB_FMT_1(T)
+
+T test_data[][3] = {
+  /* arg_0, arg_1, expect */
+  {      0,     0,      0, },
+  {      0,     1,      0, },
+  {      1,     1,      0, },
+  {  65535, 65534,      1, },
+  {  65535, 65535,      0, },
+  {  65534, 65535,      0, },
+  {  65533, 65534,      0, },
+  {      0, 65535,      0, },
+  {      1, 65535,      0, },
+  {     35,     5,     30, },
+};
+
+#include "scalar_sat_binary.h"
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-3.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-3.c
new file mode 100644
index 00000000000..5c60d28997f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-3.c
@@ -0,0 +1,25 @@ 
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+
+#define T              uint32_t
+#define RUN_SAT_BINARY RUN_SAT_U_SUB_FMT_1
+
+DEF_SAT_U_SUB_FMT_1(T)
+
+T test_data[][3] = {
+  /*     arg_0,      arg_1,      expect */
+  {          0,          0,           0, },
+  {          0,          1,           0, },
+  {          1,          1,           0, },
+  { 4294967295, 4294967294,           1, },
+  { 4294967295, 4294967295,           0, },
+  { 4294967294, 4294967295,           0, },
+  { 4294967293, 4294967294,           0, },
+  {          1, 4294967295,           0, },
+  {          2, 4294967295,           0, },
+  {          5,          1,           4, },
+};
+
+#include "scalar_sat_binary.h"
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-4.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-4.c
new file mode 100644
index 00000000000..403764c8568
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-4.c
@@ -0,0 +1,25 @@ 
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+
+#define T              uint64_t
+#define RUN_SAT_BINARY RUN_SAT_U_SUB_FMT_1
+
+DEF_SAT_U_SUB_FMT_1(T)
+
+T test_data[][3] = {
+  /*                arg_0,                 arg_1,                 expect */
+  {                     0,                     0,                      0, },
+  {                     0,                     1,                      0, },
+  {                     1,                     1,                      0, },
+  { 18446744073709551615u, 18446744073709551614u,                      1, },
+  { 18446744073709551615u, 18446744073709551615u,                      0, },
+  { 18446744073709551614u, 18446744073709551615u,                      0, },
+  { 18446744073709551613u, 18446744073709551614u,                      0, },
+  {                     0, 18446744073709551615u,                      0, },
+  {                     1, 18446744073709551615u,                      0, },
+  {                    43,                    11,                     32, },
+};
+
+#include "scalar_sat_binary.h"
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-5.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-5.c
new file mode 100644
index 00000000000..6fa44ca323b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-5.c
@@ -0,0 +1,25 @@ 
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+
+#define T              uint8_t
+#define RUN_SAT_BINARY RUN_SAT_U_SUB_FMT_2
+
+DEF_SAT_U_SUB_FMT_2(T)
+
+T test_data[][3] = {
+  /* arg_0, arg_1, expect */
+  {      0,     0,      0, },
+  {      0,     1,      0, },
+  {      1,     1,      0, },
+  {    255,   254,      1, },
+  {    255,   255,      0, },
+  {    254,   255,      0, },
+  {    253,   254,      0, },
+  {      0,   255,      0, },
+  {      1,   255,      0, },
+  {     32,     5,     27, },
+};
+
+#include "scalar_sat_binary.h"
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-6.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-6.c
new file mode 100644
index 00000000000..7deaae9a5fd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-6.c
@@ -0,0 +1,25 @@ 
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+
+#define T              uint16_t
+#define RUN_SAT_BINARY RUN_SAT_U_SUB_FMT_2
+
+DEF_SAT_U_SUB_FMT_2(T)
+
+T test_data[][3] = {
+  /* arg_0, arg_1, expect */
+  {      0,     0,      0, },
+  {      0,     1,      0, },
+  {      1,     1,      0, },
+  {  65535, 65534,      1, },
+  {  65535, 65535,      0, },
+  {  65534, 65535,      0, },
+  {  65533, 65534,      0, },
+  {      0, 65535,      0, },
+  {      1, 65535,      0, },
+  {     35,     5,     30, },
+};
+
+#include "scalar_sat_binary.h"
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-7.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-7.c
new file mode 100644
index 00000000000..d9b1d5cbfe2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-7.c
@@ -0,0 +1,25 @@ 
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+
+#define T              uint32_t
+#define RUN_SAT_BINARY RUN_SAT_U_SUB_FMT_2
+
+DEF_SAT_U_SUB_FMT_2(T)
+
+T test_data[][3] = {
+  /*     arg_0,      arg_1,      expect */
+  {          0,          0,           0, },
+  {          0,          1,           0, },
+  {          1,          1,           0, },
+  { 4294967295, 4294967294,           1, },
+  { 4294967295, 4294967295,           0, },
+  { 4294967294, 4294967295,           0, },
+  { 4294967293, 4294967294,           0, },
+  {          1, 4294967295,           0, },
+  {          2, 4294967295,           0, },
+  {          5,          1,           4, },
+};
+
+#include "scalar_sat_binary.h"
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-8.c b/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-8.c
new file mode 100644
index 00000000000..2774c235cc3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_sub-run-8.c
@@ -0,0 +1,25 @@ 
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "sat_arith.h"
+
+#define T              uint64_t
+#define RUN_SAT_BINARY RUN_SAT_U_SUB_FMT_2
+
+DEF_SAT_U_SUB_FMT_2(T)
+
+T test_data[][3] = {
+  /*                arg_0,                 arg_1,                 expect */
+  {                     0,                     0,                      0, },
+  {                     0,                     1,                      0, },
+  {                     1,                     1,                      0, },
+  { 18446744073709551615u, 18446744073709551614u,                      1, },
+  { 18446744073709551615u, 18446744073709551615u,                      0, },
+  { 18446744073709551614u, 18446744073709551615u,                      0, },
+  { 18446744073709551613u, 18446744073709551614u,                      0, },
+  {                     0, 18446744073709551615u,                      0, },
+  {                     1, 18446744073709551615u,                      0, },
+  {                    43,                    11,                     32, },
+};
+
+#include "scalar_sat_binary.h"