From: Pan Li <[email protected]>
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 <[email protected]>
---
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