[v3,3/4] RISC-V: Fix incorrect code gen for scalar signed SAT_SUB [PR117688]

Message ID 20250127110744.3217923-3-pan2.li@intel.com
State Committed
Commit bfb57d62c743235284f9b31a88c6ceed9971d27a
Delegated to: Jeff Law
Headers
Series [v3,1/4] RISC-V: Refactor SAT_* operand rtx extend to reg help func [NFC] |

Checks

Context Check Description
rivoscibot/toolchain-ci-rivos-lint success Lint passed
rivoscibot/toolchain-ci-rivos-apply-patch success Patch applied
rivoscibot/toolchain-ci-rivos-build--newlib-rv64gcv-lp64d-multilib success Build passed
rivoscibot/toolchain-ci-rivos-build--linux-rv64gcv-lp64d-multilib success Build passed
rivoscibot/toolchain-ci-rivos-build--linux-rv64gc_zba_zbb_zbc_zbs-lp64d-multilib success Build passed
rivoscibot/toolchain-ci-rivos-test success Testing passed
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 success Test passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Test passed

Commit Message

Li, Pan2 Jan. 27, 2025, 11:07 a.m. UTC
  From: Pan Li <pan2.li@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.  Unfortunately we don't have sub/add for
non-Xmode like QImode in scalar, thus we need to sign extend to Xmode
to ensure we have the correct value before ALU like sub.  The gen_lowpart
will generate something like lbu which has all zero for highest bits.

For example, when 0xff(-1 for QImode) sub 0x1(1 for QImode), we actually
want to -1 - 1 = -2, but if there is no sign extend like lbu, we will get
0xff - 1 = 0xfe which is incorrect.  Thus, we have to sign extend 0xff(Qmode)
to 0xffffffffffffffff(assume XImode is DImode) before sub in Xmode.

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

	PR target/117688

gcc/ChangeLog:

	* config/riscv/riscv.cc (riscv_expand_sssub): Leverage the helper
	riscv_extend_to_xmode_reg with SIGN_EXTEND.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/pr117688.h: Add test helper macro.
	* gcc.target/riscv/pr117688-sub-run-1-s16.c: New test.
	* gcc.target/riscv/pr117688-sub-run-1-s32.c: New test.
	* gcc.target/riscv/pr117688-sub-run-1-s64.c: New test.
	* gcc.target/riscv/pr117688-sub-run-1-s8.c: New test.

Signed-off-by: Pan Li <pan2.li@intel.com>
---
 gcc/config/riscv/riscv.cc                     |  4 ++--
 .../gcc.target/riscv/pr117688-sub-run-1-s16.c |  6 ++++++
 .../gcc.target/riscv/pr117688-sub-run-1-s32.c |  6 ++++++
 .../gcc.target/riscv/pr117688-sub-run-1-s64.c |  6 ++++++
 .../gcc.target/riscv/pr117688-sub-run-1-s8.c  |  6 ++++++
 gcc/testsuite/gcc.target/riscv/pr117688.h     | 21 +++++++++++++++++++
 6 files changed, 47 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/pr117688-sub-run-1-s16.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/pr117688-sub-run-1-s32.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/pr117688-sub-run-1-s64.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/pr117688-sub-run-1-s8.c
  

Patch

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index b9fb3733b86..1e5de85e871 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -12919,8 +12919,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_extend_to_xmode_reg (x, mode, SIGN_EXTEND);
+  rtx xmode_y = riscv_extend_to_xmode_reg (y, mode, SIGN_EXTEND);
   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-sub-run-1-s16.c b/gcc/testsuite/gcc.target/riscv/pr117688-sub-run-1-s16.c
new file mode 100644
index 00000000000..7b375bb6c85
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr117688-sub-run-1-s16.c
@@ -0,0 +1,6 @@ 
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "pr117688.h"
+
+DEFINE_SIGNED_SAT_SUB_RUN(int16_t, INT16_MIN, INT16_MAX)
diff --git a/gcc/testsuite/gcc.target/riscv/pr117688-sub-run-1-s32.c b/gcc/testsuite/gcc.target/riscv/pr117688-sub-run-1-s32.c
new file mode 100644
index 00000000000..ba0e8fc8ea5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr117688-sub-run-1-s32.c
@@ -0,0 +1,6 @@ 
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "pr117688.h"
+
+DEFINE_SIGNED_SAT_SUB_RUN(int32_t, INT32_MIN, INT32_MAX)
diff --git a/gcc/testsuite/gcc.target/riscv/pr117688-sub-run-1-s64.c b/gcc/testsuite/gcc.target/riscv/pr117688-sub-run-1-s64.c
new file mode 100644
index 00000000000..c24c549af30
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr117688-sub-run-1-s64.c
@@ -0,0 +1,6 @@ 
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "pr117688.h"
+
+DEFINE_SIGNED_SAT_SUB_RUN(int64_t, INT64_MIN, INT64_MAX)
diff --git a/gcc/testsuite/gcc.target/riscv/pr117688-sub-run-1-s8.c b/gcc/testsuite/gcc.target/riscv/pr117688-sub-run-1-s8.c
new file mode 100644
index 00000000000..67f9df179a1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr117688-sub-run-1-s8.c
@@ -0,0 +1,6 @@ 
+/* { dg-do run { target { riscv_v } } } */
+/* { dg-additional-options "-std=c99" } */
+
+#include "pr117688.h"
+
+DEFINE_SIGNED_SAT_SUB_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
index 1013a8a8012..3b734ce62ed 100644
--- a/gcc/testsuite/gcc.target/riscv/pr117688.h
+++ b/gcc/testsuite/gcc.target/riscv/pr117688.h
@@ -24,4 +24,25 @@ 
     return 0;                                             \
   }
 
+#define DEFINE_SIGNED_SAT_SUB_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