diff mbox series

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

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

Commit Message

Li, Pan2 Aug. 3, 2024, 9:33 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.
	(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:
	* 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                     | 45 ++++++++++++++-
 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, 476 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. 3, 2024, 10:24 p.m. UTC | #1
On 8/3/24 3:33 AM, 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.
> 	(riscv_expand_ussub): Gen xmode reg for operand 1.
> 	* config/riscv/riscv.md: Allow const_int for operand 1.
 > +> +   1. Case 1:  .SAT_SUB (127, y) for QImode.
> +      The imm will be (const_int 127) after expand_expr_real_1,  thus we
> +      can just move the (const_int 127) to Xmode reg without any other insn.
> +
> +   2. Case 2:  .SAT_SUB (254, y) for QImode.
> +      The imm will be (const_int -2) after expand_expr_real_1,  thus we
> +      will have li a0, -2 (aka a0 = 0xfffffffffffffffe if RV64).  This is
> +      not what we want for the underlying insn like sltu.  So we need to
> +      clean the up highest 56 bits for a0 to get the real value (254, 0xfe).
 > +> +   This function would like to take care of above scenario and 
return the
> +   rtx reg which holds the x in Xmode.  */
What does this function do.  ie, what are the inputs, what are the 
outputs?  Without that core information it's hard to know if your 
implementation is correct.


If really looks like you're returning a reg in X mode.  In which case 
you can just gen_int_mode (constant, word_mode)

If the constant is 254, then that's going to load 0x00000000000000fe on 
rv64.

If the problem is that you have a target of SImode on RV64, then you do 
have a real problem.  The rv64 ABI mandates that a 32bit value be sign 
extended out to 64 bits.  And if this is the problem you're trying to 
solve, then it's a good indicator you've made a mistake elsewhere.


Anyway, it seems like you need to describe better where things are going 
wrong before we can ACK/NACK this patch.

jeff
Li, Pan2 Aug. 4, 2024, 2:13 a.m. UTC | #2
Thanks Jeff for comments, let me refine the comments in v2.

Pan

-----Original Message-----
From: Jeff Law <jeffreyalaw@gmail.com> 
Sent: Sunday, August 4, 2024 6:25 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 v1] RISC-V: Support IMM for operand 0 of ussub pattern



On 8/3/24 3:33 AM, 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.
> 	(riscv_expand_ussub): Gen xmode reg for operand 1.
> 	* config/riscv/riscv.md: Allow const_int for operand 1.
 > +> +   1. Case 1:  .SAT_SUB (127, y) for QImode.
> +      The imm will be (const_int 127) after expand_expr_real_1,  thus we
> +      can just move the (const_int 127) to Xmode reg without any other insn.
> +
> +   2. Case 2:  .SAT_SUB (254, y) for QImode.
> +      The imm will be (const_int -2) after expand_expr_real_1,  thus we
> +      will have li a0, -2 (aka a0 = 0xfffffffffffffffe if RV64).  This is
> +      not what we want for the underlying insn like sltu.  So we need to
> +      clean the up highest 56 bits for a0 to get the real value (254, 0xfe).
 > +> +   This function would like to take care of above scenario and 
return the
> +   rtx reg which holds the x in Xmode.  */
What does this function do.  ie, what are the inputs, what are the 
outputs?  Without that core information it's hard to know if your 
implementation is correct.


If really looks like you're returning a reg in X mode.  In which case 
you can just gen_int_mode (constant, word_mode)

If the constant is 254, then that's going to load 0x00000000000000fe on 
rv64.

If the problem is that you have a target of SImode on RV64, then you do 
have a real problem.  The rv64 ABI mandates that a 32bit value be sign 
extended out to 64 bits.  And if this is the problem you're trying to 
solve, then it's a good indicator you've made a mistake elsewhere.


Anyway, it seems like you need to describe better where things are going 
wrong before we can ACK/NACK this patch.

jeff
diff mbox series

Patch

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index b19d56149e7..90d95944ba4 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -11612,6 +11612,49 @@  riscv_expand_usadd (rtx dest, rtx x, rtx y)
   emit_move_insn (dest, gen_lowpart (mode, xmode_dest));
 }
 
+/* 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 we
+   may have some problem here when expanding unsigned pattern like ussub.
+
+   There are 2 cases here.  Take .SAT_SUB (imm, y) as example.
+
+   1. Case 1:  .SAT_SUB (127, y) for QImode.
+      The imm will be (const_int 127) after expand_expr_real_1,  thus we
+      can just move the (const_int 127) to Xmode reg without any other insn.
+
+   2. Case 2:  .SAT_SUB (254, y) for QImode.
+      The imm will be (const_int -2) after expand_expr_real_1,  thus we
+      will have li a0, -2 (aka a0 = 0xfffffffffffffffe if RV64).  This is
+      not what we want for the underlying insn like sltu.  So we need to
+      clean the up highest 56 bits for a0 to get the real value (254, 0xfe).
+
+   This function would like to take care of above scenario and return the
+   rtx reg which holds the x in Xmode.  */
+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);
+  HOST_WIDE_INT cst = INTVAL (x);
+
+  emit_move_insn (xmode_x, x);
+
+  int xmode_bits = GET_MODE_BITSIZE (Xmode);
+  int mode_bits = GET_MODE_BITSIZE (mode).to_constant ();
+
+  if (cst < 0 && mode_bits < xmode_bits)
+    {
+      int shift_bits = xmode_bits - mode_bits;
+
+       riscv_emit_binary (ASHIFT, xmode_x, xmode_x, GEN_INT (shift_bits));
+       riscv_emit_binary (LSHIFTRT, xmode_x, xmode_x, GEN_INT (shift_bits));
+    }
+
+  return xmode_x;
+}
+
 /* Implements the unsigned saturation sub standard name usadd for int mode.
 
    z = SAT_SUB(x, y).
@@ -11625,7 +11668,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 d9f6c1765d0..7f57c0c3c89 100644
--- a/gcc/config/riscv/riscv.md
+++ b/gcc/config/riscv/riscv.md
@@ -4306,7 +4306,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 37e0a60f21b..047dd40197c 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;
+}