From: Pan Li <pan2...@intel.com> This patch would like to fix the wroing code generation for the scalar signed SAT_SUB. The input can be QI/HI/SI/DI while the alu like sub can only work on Xmode, thus we need to make sure the value of input are well signed-extended at first. But the gen_lowpart will generate something like lbu which will perform the zero extended.
The below test suites are passed for this patch. * The rv64gcv fully regression test. Note we also notice some refinement like to support const_int for input or similar issue for ssadd and/or sstruct. But we would like to fix it by another patch(es). PR target/117688 gcc/ChangeLog: * config/riscv/riscv.cc (riscv_gen_sign_extend_rtx): Add new func to make sure the op is signed extended to Xmode. (riscv_expand_sssub): Leverage above func to perform sign extend if not Xmode. gcc/testsuite/ChangeLog: * gcc.target/riscv/pr117688-run-1-s16.c: New test. * gcc.target/riscv/pr117688-run-1-s32.c: New test. * gcc.target/riscv/pr117688-run-1-s8.c: New test. * gcc.target/riscv/pr117688.h: New test. Signed-off-by: Pan Li <pan2...@intel.com> --- gcc/config/riscv/riscv.cc | 28 +++++++++++++++++-- .../gcc.target/riscv/pr117688-run-1-s16.c | 6 ++++ .../gcc.target/riscv/pr117688-run-1-s32.c | 6 ++++ .../gcc.target/riscv/pr117688-run-1-s8.c | 6 ++++ gcc/testsuite/gcc.target/riscv/pr117688.h | 27 ++++++++++++++++++ 5 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/pr117688-run-1-s16.c create mode 100644 gcc/testsuite/gcc.target/riscv/pr117688-run-1-s32.c create mode 100644 gcc/testsuite/gcc.target/riscv/pr117688-run-1-s8.c create mode 100644 gcc/testsuite/gcc.target/riscv/pr117688.h diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index f5e672bb7f5..e38a246f669 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -12693,6 +12693,30 @@ riscv_gen_zero_extend_rtx (rtx x, machine_mode mode) return xmode_reg; } +/* Generate a REG rtx of Xmode from the given rtx and mode. + The rtx x can be REG (QI/HI/SI/DI). + The machine_mode mode is the original mode from define pattern. + + If rtx is REG and Xmode, the RTX x will be returned directly. + + If rtx is REG and non-Xmode, the sign extended to new REG of Xmode will be + returned. + + 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_sign_extend_rtx (rtx x, machine_mode mode) +{ + if (mode == Xmode) + return x; + + rtx xmode_reg = gen_reg_rtx (Xmode); + riscv_emit_unary (SIGN_EXTEND, xmode_reg, x); + + return xmode_reg; +} + /* Implements the unsigned saturation add standard name usadd for int mode. z = SAT_ADD(x, y). @@ -12892,8 +12916,8 @@ riscv_expand_sssub (rtx dest, rtx x, rtx y) machine_mode mode = GET_MODE (dest); unsigned bitsize = GET_MODE_BITSIZE (mode).to_constant (); rtx shift_bits = GEN_INT (bitsize - 1); - rtx xmode_x = gen_lowpart (Xmode, x); - rtx xmode_y = gen_lowpart (Xmode, y); + rtx xmode_x = riscv_gen_sign_extend_rtx (x, mode); + rtx xmode_y = riscv_gen_sign_extend_rtx (y, mode); rtx xmode_minus = gen_reg_rtx (Xmode); rtx xmode_xor_0 = gen_reg_rtx (Xmode); rtx xmode_xor_1 = gen_reg_rtx (Xmode); diff --git a/gcc/testsuite/gcc.target/riscv/pr117688-run-1-s16.c b/gcc/testsuite/gcc.target/riscv/pr117688-run-1-s16.c new file mode 100644 index 00000000000..b63f00e100b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pr117688-run-1-s16.c @@ -0,0 +1,6 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99" } */ + +#include "pr117688.h" + +DEFINE_PR117688_RUN(int16_t, INT16_MIN, INT16_MAX) diff --git a/gcc/testsuite/gcc.target/riscv/pr117688-run-1-s32.c b/gcc/testsuite/gcc.target/riscv/pr117688-run-1-s32.c new file mode 100644 index 00000000000..852285aa882 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pr117688-run-1-s32.c @@ -0,0 +1,6 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99" } */ + +#include "pr117688.h" + +DEFINE_PR117688_RUN(int32_t, INT32_MIN, INT32_MAX) diff --git a/gcc/testsuite/gcc.target/riscv/pr117688-run-1-s8.c b/gcc/testsuite/gcc.target/riscv/pr117688-run-1-s8.c new file mode 100644 index 00000000000..1e4914ebc40 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pr117688-run-1-s8.c @@ -0,0 +1,6 @@ +/* { dg-do run { target { riscv_v } } } */ +/* { dg-additional-options "-std=c99" } */ + +#include "pr117688.h" + +DEFINE_PR117688_RUN(int8_t, INT8_MIN, INT8_MAX) diff --git a/gcc/testsuite/gcc.target/riscv/pr117688.h b/gcc/testsuite/gcc.target/riscv/pr117688.h new file mode 100644 index 00000000000..97c67837ebf --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/pr117688.h @@ -0,0 +1,27 @@ +#ifndef HAVE_DEFINED_PR117688_H +#define HAVE_DEFINED_PR117688_H + +#include <stdint.h> + +#define DEFINE_PR117688_RUN(T, MIN, MAX) \ + T x, y, result; \ + \ + __attribute__ ((noipa)) void \ + foo () \ + { \ + T minus; \ + _Bool overflow = __builtin_sub_overflow (x, y, &minus); \ + result = overflow ? (x < 0 ? MIN : MAX) : minus; \ + } \ + \ + int main () \ + { \ + x = MIN; \ + y = 0x1; \ + foo(); \ + if (result != (T)MIN) \ + __builtin_abort (); \ + return 0; \ + } + +#endif -- 2.43.0