diff mbox series

[v1] RISC-V: Make sure high bits of usadd operands is clean for HI/QI [PR116278]

Message ID 20240809031215.2623532-1-pan2.li@intel.com
State New
Headers show
Series [v1] RISC-V: Make sure high bits of usadd operands is clean for HI/QI [PR116278] | expand

Commit Message

Li, Pan2 Aug. 9, 2024, 3:12 a.m. UTC
From: Pan Li <pan2.li@intel.com>

For QI/HImode of .SAT_ADD,  the operands may be sign-extended and the
high bits of Xmode may be all 1 which is not expected.  For example as
below code.

signed char b[1];
unsigned short c;
signed char *d = b;
int main() {
  b[0] = -40;
  c = ({ (unsigned short)d[0] < 0xFFF6 ? (unsigned short)d[0] : 0xFFF6; }) + 9;
  __builtin_printf("%d\n", c);
}

After expanding we have:

;; _6 = .SAT_ADD (_3, 9);
(insn 8 7 9 (set (reg:DI 143)
        (high:DI (symbol_ref:DI ("d") [flags 0x86]  <var_decl d>)))
     (nil))
(insn 9 8 10 (set (reg/f:DI 142)
        (mem/f/c:DI (lo_sum:DI (reg:DI 143)
                (symbol_ref:DI ("d") [flags 0x86]  <var_decl d>)) [1 d+0 S8 A64]))
     (nil))
(insn 10 9 11 (set (reg:HI 144 [ _3 ])
        (sign_extend:HI (mem:QI (reg/f:DI 142) [0 *d.0_1+0 S1 A8]))) "test.c":7:10 -1
     (nil))

The convert from signed char to unsigned short will have sign_extend rtl
as above.  And finally become the lb insn as below:

lb      a1,0(a5)   // a1 is -40, aka 0xffffffffffffffd8
lui     a0,0x1a
addi    a5,a1,9
slli    a5,a5,0x30
srli    a5,a5,0x30 // a5 is 65505
sltu    a1,a5,a1   // compare 65505 and 0xffffffffffffffd8 => TRUE

The sltu try to compare 65505 and 0xffffffffffffffd8 here,  but we
actually want to compare 65505 and 65496 (0xffd8).  Thus we need to
clean up the high bits to ensure this.

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

	PR target/116278

gcc/ChangeLog:

	* config/riscv/riscv.cc (riscv_cleanup_rtx_high): Add new func
	impl to cleanup high bits of rtx.
	(riscv_expand_usadd): Leverage above func to cleanup operands
	and sum.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/sat_u_add-1.c: Adjust asm check.
	* gcc.target/riscv/sat_u_add-10.c: Ditto.
	* gcc.target/riscv/sat_u_add-13.c: Ditto.
	* gcc.target/riscv/sat_u_add-14.c: Ditto.
	* gcc.target/riscv/sat_u_add-17.c: Ditto.
	* gcc.target/riscv/sat_u_add-18.c: Ditto.
	* gcc.target/riscv/sat_u_add-2.c: Ditto.
	* gcc.target/riscv/sat_u_add-21.c: Ditto.
	* gcc.target/riscv/sat_u_add-22.c: Ditto.
	* gcc.target/riscv/sat_u_add-5.c: Ditto.
	* gcc.target/riscv/sat_u_add-6.c: Ditto.
	* gcc.target/riscv/sat_u_add-9.c: Ditto.
	* gcc.target/riscv/sat_u_add_imm-1.c: Ditto.
	* gcc.target/riscv/sat_u_add_imm-10.c: Ditto.
	* gcc.target/riscv/sat_u_add_imm-13.c: Ditto.
	* gcc.target/riscv/sat_u_add_imm-14.c: Ditto.
	* gcc.target/riscv/sat_u_add_imm-2.c: Ditto.
	* gcc.target/riscv/sat_u_add_imm-5.c: Ditto.
	* gcc.target/riscv/sat_u_add_imm-6.c: Ditto.
	* gcc.target/riscv/sat_u_add_imm-9.c: Ditto.
	* gcc.target/riscv/pr116278-run-1.c: New test.

Signed-off-by: Pan Li <pan2.li@intel.com>
---
 gcc/config/riscv/riscv.cc                     | 30 ++++++++++++++-----
 .../gcc.target/riscv/pr116278-run-1.c         | 16 ++++++++++
 gcc/testsuite/gcc.target/riscv/sat_u_add-1.c  |  1 +
 gcc/testsuite/gcc.target/riscv/sat_u_add-10.c |  2 ++
 gcc/testsuite/gcc.target/riscv/sat_u_add-13.c |  1 +
 gcc/testsuite/gcc.target/riscv/sat_u_add-14.c |  2 ++
 gcc/testsuite/gcc.target/riscv/sat_u_add-17.c |  1 +
 gcc/testsuite/gcc.target/riscv/sat_u_add-18.c |  2 ++
 gcc/testsuite/gcc.target/riscv/sat_u_add-2.c  |  2 ++
 gcc/testsuite/gcc.target/riscv/sat_u_add-21.c |  1 +
 gcc/testsuite/gcc.target/riscv/sat_u_add-22.c |  2 ++
 gcc/testsuite/gcc.target/riscv/sat_u_add-5.c  |  1 +
 gcc/testsuite/gcc.target/riscv/sat_u_add-6.c  |  2 ++
 gcc/testsuite/gcc.target/riscv/sat_u_add-9.c  |  1 +
 .../gcc.target/riscv/sat_u_add_imm-1.c        |  1 +
 .../gcc.target/riscv/sat_u_add_imm-10.c       |  2 ++
 .../gcc.target/riscv/sat_u_add_imm-13.c       |  1 +
 .../gcc.target/riscv/sat_u_add_imm-14.c       |  2 ++
 .../gcc.target/riscv/sat_u_add_imm-2.c        |  2 ++
 .../gcc.target/riscv/sat_u_add_imm-5.c        |  1 +
 .../gcc.target/riscv/sat_u_add_imm-6.c        |  2 ++
 .../gcc.target/riscv/sat_u_add_imm-9.c        |  1 +
 22 files changed, 68 insertions(+), 8 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/pr116278-run-1.c

Comments

Jeff Law Aug. 10, 2024, 3:34 p.m. UTC | #1
On 8/8/24 9:12 PM, pan2.li@intel.com wrote:
> From: Pan Li <pan2.li@intel.com>
> 
> For QI/HImode of .SAT_ADD,  the operands may be sign-extended and the
> high bits of Xmode may be all 1 which is not expected.  For example as
> below code.
> 
> signed char b[1];
> unsigned short c;
> signed char *d = b;
> int main() {
>    b[0] = -40;
>    c = ({ (unsigned short)d[0] < 0xFFF6 ? (unsigned short)d[0] : 0xFFF6; }) + 9;
>    __builtin_printf("%d\n", c);
> }
> 
> After expanding we have:
> 
> ;; _6 = .SAT_ADD (_3, 9);
> (insn 8 7 9 (set (reg:DI 143)
>          (high:DI (symbol_ref:DI ("d") [flags 0x86]  <var_decl d>)))
>       (nil))
> (insn 9 8 10 (set (reg/f:DI 142)
>          (mem/f/c:DI (lo_sum:DI (reg:DI 143)
>                  (symbol_ref:DI ("d") [flags 0x86]  <var_decl d>)) [1 d+0 S8 A64]))
>       (nil))
> (insn 10 9 11 (set (reg:HI 144 [ _3 ])
>          (sign_extend:HI (mem:QI (reg/f:DI 142) [0 *d.0_1+0 S1 A8]))) "test.c":7:10 -1
>       (nil))
> 
> The convert from signed char to unsigned short will have sign_extend rtl
> as above.  And finally become the lb insn as below:
> 
> lb      a1,0(a5)   // a1 is -40, aka 0xffffffffffffffd8
> lui     a0,0x1a
> addi    a5,a1,9
> slli    a5,a5,0x30
> srli    a5,a5,0x30 // a5 is 65505
> sltu    a1,a5,a1   // compare 65505 and 0xffffffffffffffd8 => TRUE
> 
> The sltu try to compare 65505 and 0xffffffffffffffd8 here,  but we
> actually want to compare 65505 and 65496 (0xffd8).  Thus we need to
> clean up the high bits to ensure this.
> 
> The below test suites are passed for this patch:
> * The rv64gcv fully regression test.
> 
> 	PR target/116278
> 
> gcc/ChangeLog:
> 
> 	* config/riscv/riscv.cc (riscv_cleanup_rtx_high): Add new func
> 	impl to cleanup high bits of rtx.
> 	(riscv_expand_usadd): Leverage above func to cleanup operands
> 	and sum.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/sat_u_add-1.c: Adjust asm check.
> 	* gcc.target/riscv/sat_u_add-10.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-13.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-14.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-17.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-18.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-2.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-21.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-22.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-5.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-6.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-9.c: Ditto.
> 	* gcc.target/riscv/sat_u_add_imm-1.c: Ditto.
> 	* gcc.target/riscv/sat_u_add_imm-10.c: Ditto.
> 	* gcc.target/riscv/sat_u_add_imm-13.c: Ditto.
> 	* gcc.target/riscv/sat_u_add_imm-14.c: Ditto.
> 	* gcc.target/riscv/sat_u_add_imm-2.c: Ditto.
> 	* gcc.target/riscv/sat_u_add_imm-5.c: Ditto.
> 	* gcc.target/riscv/sat_u_add_imm-6.c: Ditto.
> 	* gcc.target/riscv/sat_u_add_imm-9.c: Ditto.
> 	* gcc.target/riscv/pr116278-run-1.c: New test.
> 
> Signed-off-by: Pan Li <pan2.li@intel.com>
> ---
>   gcc/config/riscv/riscv.cc                     | 30 ++++++++++++++-----
>   .../gcc.target/riscv/pr116278-run-1.c         | 16 ++++++++++
>   gcc/testsuite/gcc.target/riscv/sat_u_add-1.c  |  1 +
>   gcc/testsuite/gcc.target/riscv/sat_u_add-10.c |  2 ++
>   gcc/testsuite/gcc.target/riscv/sat_u_add-13.c |  1 +
>   gcc/testsuite/gcc.target/riscv/sat_u_add-14.c |  2 ++
>   gcc/testsuite/gcc.target/riscv/sat_u_add-17.c |  1 +
>   gcc/testsuite/gcc.target/riscv/sat_u_add-18.c |  2 ++
>   gcc/testsuite/gcc.target/riscv/sat_u_add-2.c  |  2 ++
>   gcc/testsuite/gcc.target/riscv/sat_u_add-21.c |  1 +
>   gcc/testsuite/gcc.target/riscv/sat_u_add-22.c |  2 ++
>   gcc/testsuite/gcc.target/riscv/sat_u_add-5.c  |  1 +
>   gcc/testsuite/gcc.target/riscv/sat_u_add-6.c  |  2 ++
>   gcc/testsuite/gcc.target/riscv/sat_u_add-9.c  |  1 +
>   .../gcc.target/riscv/sat_u_add_imm-1.c        |  1 +
>   .../gcc.target/riscv/sat_u_add_imm-10.c       |  2 ++
>   .../gcc.target/riscv/sat_u_add_imm-13.c       |  1 +
>   .../gcc.target/riscv/sat_u_add_imm-14.c       |  2 ++
>   .../gcc.target/riscv/sat_u_add_imm-2.c        |  2 ++
>   .../gcc.target/riscv/sat_u_add_imm-5.c        |  1 +
>   .../gcc.target/riscv/sat_u_add_imm-6.c        |  2 ++
>   .../gcc.target/riscv/sat_u_add_imm-9.c        |  1 +
>   22 files changed, 68 insertions(+), 8 deletions(-)
>   create mode 100644 gcc/testsuite/gcc.target/riscv/pr116278-run-1.c
> 
> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> index 5fe4273beb7..fb916217e5e 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -11564,6 +11564,24 @@ riscv_get_raw_result_mode (int regno)
>     return default_get_reg_raw_mode (regno);
>   }
>   
> +/* Cleanup the high bits of the RTX x and reserve the low bits.
> +   The reserved bitsize comes from the bitsize of reserved_mode.  */
> +
> +static void
> +riscv_cleanup_rtx_high (rtx x, machine_mode reserved_mode)
> +{
> +  machine_mode mode = GET_MODE (x);
> +  int reserved_bitsize = GET_MODE_BITSIZE (reserved_mode).to_constant ();
> +  int mode_bitsize = GET_MODE_BITSIZE (mode).to_constant ();
> +
> +  gcc_assert (mode_bitsize >= reserved_bitsize);
> +
> +  int shift_bitsize = mode_bitsize - reserved_bitsize;
> +
> +  riscv_emit_binary (ASHIFT, x, x, GEN_INT (shift_bitsize));
> +  riscv_emit_binary (LSHIFTRT, x, x, GEN_INT (shift_bitsize));
> +}
Isn't this just zero extension from a narrower mode to a wider mode? 
Why not just use zero_extend?  That will take advantage of existing 
expansion code to select an efficient extension approach at initial RTL 
generation rather than waiting for combine to clean things up.

jeff
Li, Pan2 Aug. 11, 2024, 1:13 a.m. UTC | #2
> Isn't this just zero extension from a narrower mode to a wider mode? 
> Why not just use zero_extend?  That will take advantage of existing 
> expansion code to select an efficient extension approach at initial RTL 
> generation rather than waiting for combine to clean things up.

Thanks Jeff, let me have a try in v2.

Pan

-----Original Message-----
From: Jeff Law <jeffreyalaw@gmail.com> 
Sent: Saturday, August 10, 2024 11:34 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 v1] RISC-V: Make sure high bits of usadd operands is clean for HI/QI [PR116278]



On 8/8/24 9:12 PM, pan2.li@intel.com wrote:
> From: Pan Li <pan2.li@intel.com>
> 
> For QI/HImode of .SAT_ADD,  the operands may be sign-extended and the
> high bits of Xmode may be all 1 which is not expected.  For example as
> below code.
> 
> signed char b[1];
> unsigned short c;
> signed char *d = b;
> int main() {
>    b[0] = -40;
>    c = ({ (unsigned short)d[0] < 0xFFF6 ? (unsigned short)d[0] : 0xFFF6; }) + 9;
>    __builtin_printf("%d\n", c);
> }
> 
> After expanding we have:
> 
> ;; _6 = .SAT_ADD (_3, 9);
> (insn 8 7 9 (set (reg:DI 143)
>          (high:DI (symbol_ref:DI ("d") [flags 0x86]  <var_decl d>)))
>       (nil))
> (insn 9 8 10 (set (reg/f:DI 142)
>          (mem/f/c:DI (lo_sum:DI (reg:DI 143)
>                  (symbol_ref:DI ("d") [flags 0x86]  <var_decl d>)) [1 d+0 S8 A64]))
>       (nil))
> (insn 10 9 11 (set (reg:HI 144 [ _3 ])
>          (sign_extend:HI (mem:QI (reg/f:DI 142) [0 *d.0_1+0 S1 A8]))) "test.c":7:10 -1
>       (nil))
> 
> The convert from signed char to unsigned short will have sign_extend rtl
> as above.  And finally become the lb insn as below:
> 
> lb      a1,0(a5)   // a1 is -40, aka 0xffffffffffffffd8
> lui     a0,0x1a
> addi    a5,a1,9
> slli    a5,a5,0x30
> srli    a5,a5,0x30 // a5 is 65505
> sltu    a1,a5,a1   // compare 65505 and 0xffffffffffffffd8 => TRUE
> 
> The sltu try to compare 65505 and 0xffffffffffffffd8 here,  but we
> actually want to compare 65505 and 65496 (0xffd8).  Thus we need to
> clean up the high bits to ensure this.
> 
> The below test suites are passed for this patch:
> * The rv64gcv fully regression test.
> 
> 	PR target/116278
> 
> gcc/ChangeLog:
> 
> 	* config/riscv/riscv.cc (riscv_cleanup_rtx_high): Add new func
> 	impl to cleanup high bits of rtx.
> 	(riscv_expand_usadd): Leverage above func to cleanup operands
> 	and sum.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/sat_u_add-1.c: Adjust asm check.
> 	* gcc.target/riscv/sat_u_add-10.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-13.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-14.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-17.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-18.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-2.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-21.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-22.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-5.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-6.c: Ditto.
> 	* gcc.target/riscv/sat_u_add-9.c: Ditto.
> 	* gcc.target/riscv/sat_u_add_imm-1.c: Ditto.
> 	* gcc.target/riscv/sat_u_add_imm-10.c: Ditto.
> 	* gcc.target/riscv/sat_u_add_imm-13.c: Ditto.
> 	* gcc.target/riscv/sat_u_add_imm-14.c: Ditto.
> 	* gcc.target/riscv/sat_u_add_imm-2.c: Ditto.
> 	* gcc.target/riscv/sat_u_add_imm-5.c: Ditto.
> 	* gcc.target/riscv/sat_u_add_imm-6.c: Ditto.
> 	* gcc.target/riscv/sat_u_add_imm-9.c: Ditto.
> 	* gcc.target/riscv/pr116278-run-1.c: New test.
> 
> Signed-off-by: Pan Li <pan2.li@intel.com>
> ---
>   gcc/config/riscv/riscv.cc                     | 30 ++++++++++++++-----
>   .../gcc.target/riscv/pr116278-run-1.c         | 16 ++++++++++
>   gcc/testsuite/gcc.target/riscv/sat_u_add-1.c  |  1 +
>   gcc/testsuite/gcc.target/riscv/sat_u_add-10.c |  2 ++
>   gcc/testsuite/gcc.target/riscv/sat_u_add-13.c |  1 +
>   gcc/testsuite/gcc.target/riscv/sat_u_add-14.c |  2 ++
>   gcc/testsuite/gcc.target/riscv/sat_u_add-17.c |  1 +
>   gcc/testsuite/gcc.target/riscv/sat_u_add-18.c |  2 ++
>   gcc/testsuite/gcc.target/riscv/sat_u_add-2.c  |  2 ++
>   gcc/testsuite/gcc.target/riscv/sat_u_add-21.c |  1 +
>   gcc/testsuite/gcc.target/riscv/sat_u_add-22.c |  2 ++
>   gcc/testsuite/gcc.target/riscv/sat_u_add-5.c  |  1 +
>   gcc/testsuite/gcc.target/riscv/sat_u_add-6.c  |  2 ++
>   gcc/testsuite/gcc.target/riscv/sat_u_add-9.c  |  1 +
>   .../gcc.target/riscv/sat_u_add_imm-1.c        |  1 +
>   .../gcc.target/riscv/sat_u_add_imm-10.c       |  2 ++
>   .../gcc.target/riscv/sat_u_add_imm-13.c       |  1 +
>   .../gcc.target/riscv/sat_u_add_imm-14.c       |  2 ++
>   .../gcc.target/riscv/sat_u_add_imm-2.c        |  2 ++
>   .../gcc.target/riscv/sat_u_add_imm-5.c        |  1 +
>   .../gcc.target/riscv/sat_u_add_imm-6.c        |  2 ++
>   .../gcc.target/riscv/sat_u_add_imm-9.c        |  1 +
>   22 files changed, 68 insertions(+), 8 deletions(-)
>   create mode 100644 gcc/testsuite/gcc.target/riscv/pr116278-run-1.c
> 
> diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
> index 5fe4273beb7..fb916217e5e 100644
> --- a/gcc/config/riscv/riscv.cc
> +++ b/gcc/config/riscv/riscv.cc
> @@ -11564,6 +11564,24 @@ riscv_get_raw_result_mode (int regno)
>     return default_get_reg_raw_mode (regno);
>   }
>   
> +/* Cleanup the high bits of the RTX x and reserve the low bits.
> +   The reserved bitsize comes from the bitsize of reserved_mode.  */
> +
> +static void
> +riscv_cleanup_rtx_high (rtx x, machine_mode reserved_mode)
> +{
> +  machine_mode mode = GET_MODE (x);
> +  int reserved_bitsize = GET_MODE_BITSIZE (reserved_mode).to_constant ();
> +  int mode_bitsize = GET_MODE_BITSIZE (mode).to_constant ();
> +
> +  gcc_assert (mode_bitsize >= reserved_bitsize);
> +
> +  int shift_bitsize = mode_bitsize - reserved_bitsize;
> +
> +  riscv_emit_binary (ASHIFT, x, x, GEN_INT (shift_bitsize));
> +  riscv_emit_binary (LSHIFTRT, x, x, GEN_INT (shift_bitsize));
> +}
Isn't this just zero extension from a narrower mode to a wider mode? 
Why not just use zero_extend?  That will take advantage of existing 
expansion code to select an efficient extension approach at initial RTL 
generation rather than waiting for combine to clean things up.

jeff
diff mbox series

Patch

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 5fe4273beb7..fb916217e5e 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -11564,6 +11564,24 @@  riscv_get_raw_result_mode (int regno)
   return default_get_reg_raw_mode (regno);
 }
 
+/* Cleanup the high bits of the RTX x and reserve the low bits.
+   The reserved bitsize comes from the bitsize of reserved_mode.  */
+
+static void
+riscv_cleanup_rtx_high (rtx x, machine_mode reserved_mode)
+{
+  machine_mode mode = GET_MODE (x);
+  int reserved_bitsize = GET_MODE_BITSIZE (reserved_mode).to_constant ();
+  int mode_bitsize = GET_MODE_BITSIZE (mode).to_constant ();
+
+  gcc_assert (mode_bitsize >= reserved_bitsize);
+
+  int shift_bitsize = mode_bitsize - reserved_bitsize;
+
+  riscv_emit_binary (ASHIFT, x, x, GEN_INT (shift_bitsize));
+  riscv_emit_binary (LSHIFTRT, x, x, GEN_INT (shift_bitsize));
+}
+
 /* Implements the unsigned saturation add standard name usadd for int mode.
 
    z = SAT_ADD(x, y).
@@ -11594,16 +11612,12 @@  riscv_expand_usadd (rtx dest, rtx x, rtx y)
   else
     riscv_emit_binary (PLUS, xmode_sum, xmode_x, xmode_y);
 
-  /* Step-1.1: truncate sum for HI and QI as we have no insn for add QI/HI.  */
+  /* Step-1.1: truncate sum for HI and QI as we have no insn for add QI/HI.
+	       truncate x for HI and QI as it may be sign-extended.  */
   if (mode == HImode || mode == QImode)
     {
-      int shift_bits = GET_MODE_BITSIZE (Xmode)
-	- GET_MODE_BITSIZE (mode).to_constant ();
-
-      gcc_assert (shift_bits > 0);
-
-      riscv_emit_binary (ASHIFT, xmode_sum, xmode_sum, GEN_INT (shift_bits));
-      riscv_emit_binary (LSHIFTRT, xmode_sum, xmode_sum, GEN_INT (shift_bits));
+      riscv_cleanup_rtx_high (xmode_sum, mode);
+      riscv_cleanup_rtx_high (xmode_x, mode);
     }
 
   /* Step-2: lt = sum < x  */
diff --git a/gcc/testsuite/gcc.target/riscv/pr116278-run-1.c b/gcc/testsuite/gcc.target/riscv/pr116278-run-1.c
new file mode 100644
index 00000000000..f6268e290ec
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr116278-run-1.c
@@ -0,0 +1,16 @@ 
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+signed char b[1];
+int c;
+signed char *d = b;
+
+int main() {
+  b[0] = -40;
+  c = ({
+    (unsigned short)d[0] < 0xFFF6 ? (unsigned short)d[0] : 0xFFF6;
+  }) + 9;
+
+  if (c != 65505)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add-1.c b/gcc/testsuite/gcc.target/riscv/sat_u_add-1.c
index 609e1ea343b..c1951004ed1 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add-1.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add-1.c
@@ -8,6 +8,7 @@ 
 ** sat_u_add_uint8_t_fmt_1:
 ** add\s+[atx][0-9]+,\s*a0,\s*a1
 ** andi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*0xff
+** andi\s+a0,\s*a0,\s*0xff
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add-10.c b/gcc/testsuite/gcc.target/riscv/sat_u_add-10.c
index 3f627ef80b1..b9b756294a8 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add-10.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add-10.c
@@ -9,6 +9,8 @@ 
 ** add\s+[atx][0-9]+,\s*a0,\s*a1
 ** slli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
 ** srli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
+** slli\s+a0,\s*a0+,\s*48
+** srli\s+a0,\s*a0+,\s*48
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add-13.c b/gcc/testsuite/gcc.target/riscv/sat_u_add-13.c
index b2d93f29f48..87334732573 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add-13.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add-13.c
@@ -8,6 +8,7 @@ 
 ** sat_u_add_uint8_t_fmt_4:
 ** add\s+[atx][0-9]+,\s*a0,\s*a1
 ** andi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*0xff
+** andi\s+a0,\s*a0,\s*0xff
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add-14.c b/gcc/testsuite/gcc.target/riscv/sat_u_add-14.c
index eafc578aafa..993c332a462 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add-14.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add-14.c
@@ -9,6 +9,8 @@ 
 ** add\s+[atx][0-9]+,\s*a0,\s*a1
 ** slli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
 ** srli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
+** slli\s+a0,\s*a0,\s*48
+** srli\s+a0,\s*a0,\s*48
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add-17.c b/gcc/testsuite/gcc.target/riscv/sat_u_add-17.c
index 7085ac835f7..d71faf08f32 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add-17.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add-17.c
@@ -8,6 +8,7 @@ 
 ** sat_u_add_uint8_t_fmt_5:
 ** add\s+[atx][0-9]+,\s*a0,\s*a1
 ** andi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*0xff
+** andi\s+a0,\s*a0+,\s*0xff
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add-18.c b/gcc/testsuite/gcc.target/riscv/sat_u_add-18.c
index 355ff8ba4ef..6ebc12cf10d 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add-18.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add-18.c
@@ -9,6 +9,8 @@ 
 ** add\s+[atx][0-9]+,\s*a0,\s*a1
 ** slli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
 ** srli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
+** slli\s+a0,\s*a0+,\s*48
+** srli\s+a0,\s*a0+,\s*48
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add-2.c b/gcc/testsuite/gcc.target/riscv/sat_u_add-2.c
index d30436c782a..bdc1591214e 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add-2.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add-2.c
@@ -9,6 +9,8 @@ 
 ** add\s+[atx][0-9]+,\s*a0,\s*a1
 ** slli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
 ** srli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
+** slli\s+a0,\s*a0+,\s*48
+** srli\s+a0,\s*a0+,\s*48
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add-21.c b/gcc/testsuite/gcc.target/riscv/sat_u_add-21.c
index f75e35a5fa9..543a0436663 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add-21.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add-21.c
@@ -8,6 +8,7 @@ 
 ** sat_u_add_uint8_t_fmt_6:
 ** add\s+[atx][0-9]+,\s*a0,\s*a1
 ** andi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*0xff
+** andi\s+a0,\s*a0,\s*0xff
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add-22.c b/gcc/testsuite/gcc.target/riscv/sat_u_add-22.c
index ad957a061f4..2db186f86b0 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add-22.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add-22.c
@@ -9,6 +9,8 @@ 
 ** add\s+[atx][0-9]+,\s*a0,\s*a1
 ** slli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
 ** srli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
+** slli\s+a0,\s*a0+,\s*48
+** srli\s+a0,\s*a0+,\s*48
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add-5.c b/gcc/testsuite/gcc.target/riscv/sat_u_add-5.c
index 4c73c7f8a21..0e487257dbb 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add-5.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add-5.c
@@ -8,6 +8,7 @@ 
 ** sat_u_add_uint8_t_fmt_2:
 ** add\s+[atx][0-9]+,\s*a0,\s*a1
 ** andi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*0xff
+** andi\s+a0,\s*a0,\s*0xff
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add-6.c b/gcc/testsuite/gcc.target/riscv/sat_u_add-6.c
index 0d64f5631bb..f47398459f9 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add-6.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add-6.c
@@ -9,6 +9,8 @@ 
 ** add\s+[atx][0-9]+,\s*a0,\s*a1
 ** slli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
 ** srli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
+** slli\s+a0,\s*a0+,\s*48
+** srli\s+a0,\s*a0+,\s*48
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add-9.c b/gcc/testsuite/gcc.target/riscv/sat_u_add-9.c
index eac6707a407..082b4b0bd4d 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add-9.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add-9.c
@@ -8,6 +8,7 @@ 
 ** sat_u_add_uint8_t_fmt_3:
 ** add\s+[atx][0-9]+,\s*a0,\s*a1
 ** andi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*0xff
+** andi\s+a0,\s*a0,\s*0xff
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-1.c b/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-1.c
index 14e9b7595a8..edaa86f69aa 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-1.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-1.c
@@ -8,6 +8,7 @@ 
 ** sat_u_add_imm9_uint8_t_fmt_1:
 ** addi\s+[atx][0-9]+,\s*a0,\s*9
 ** andi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*0xff
+** andi\s+a0,\s*a0,\s*0xff
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-10.c b/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-10.c
index 24cdd267cca..84cc521c1d3 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-10.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-10.c
@@ -9,6 +9,8 @@ 
 ** addi\s+[atx][0-9]+,\s*a0,\s*3
 ** slli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
 ** srli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
+** slli\s+a0,\s*a0,\s*48
+** srli\s+a0,\s*a0,\s*48
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-13.c b/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-13.c
index a3b2679233c..3f8f59eb8cd 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-13.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-13.c
@@ -8,6 +8,7 @@ 
 ** sat_u_add_imm9_uint8_t_fmt_4:
 ** addi\s+[atx][0-9]+,\s*a0,\s*9
 ** andi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*0xff
+** andi\s+a0,\s*a0,\s*0xff
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-14.c b/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-14.c
index 968534b74da..3e7dc0a3c4c 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-14.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-14.c
@@ -9,6 +9,8 @@ 
 ** addi\s+[atx][0-9]+,\s*a0,\s*3
 ** slli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
 ** srli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
+** slli\s+a0,\s*a0,\s*48
+** srli\s+a0,\s*a0,\s*48
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-2.c b/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-2.c
index c1a3c6ff21d..7232a37d9c5 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-2.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-2.c
@@ -9,6 +9,8 @@ 
 ** addi\s+[atx][0-9]+,\s*a0,\s*3
 ** slli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
 ** srli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
+** slli\s+a0,\s*a0,\s*48
+** srli\s+a0,\s*a0,\s*48
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-5.c b/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-5.c
index 19b502db6c9..522afaf481f 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-5.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-5.c
@@ -8,6 +8,7 @@ 
 ** sat_u_add_imm9_uint8_t_fmt_2:
 ** addi\s+[atx][0-9]+,\s*a0,\s*9
 ** andi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*0xff
+** andi\s+a0,\s*a0,\s*0xff
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-6.c b/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-6.c
index 0317370b67e..12b7bfe3a70 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-6.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-6.c
@@ -9,6 +9,8 @@ 
 ** addi\s+[atx][0-9]+,\s*a0,\s*3
 ** slli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
 ** srli\s+[atx][0-9]+,\s*[atx][0-9]+,\s*48
+** slli\s+a0,\s*a0,\s*48
+** srli\s+a0,\s*a0,\s*48
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
diff --git a/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-9.c b/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-9.c
index 5fcd6d71a26..e53a459c021 100644
--- a/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-9.c
+++ b/gcc/testsuite/gcc.target/riscv/sat_u_add_imm-9.c
@@ -8,6 +8,7 @@ 
 ** sat_u_add_imm9_uint8_t_fmt_3:
 ** addi\s+[atx][0-9]+,\s*a0,\s*9
 ** andi\s+[atx][0-9]+,\s*[atx][0-9]+,\s*0xff
+** andi\s+a0,\s*a0,\s*0xff
 ** sltu\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+
 ** neg\s+[atx][0-9]+,\s*[atx][0-9]+
 ** or\s+[atx][0-9]+,\s*[atx][0-9]+,\s*[atx][0-9]+