From: Pan Li <pan2...@intel.com>

This patch would like to refactor the helper function of the SAT_*
scalar.  The helper function will convert the define_pattern ops
to the xmode reg for the underlying code-gen.  This patch add
new parameter for ZERO_EXTEND or SIGN_EXTEND if the input is const_int
or the mode is non-Xmode.

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

gcc/ChangeLog:

        * config/riscv/riscv.cc (riscv_gen_zero_extend_rtx): Rename from ...
        (riscv_extend_to_xmode_reg): Rename to and add rtx_code for
        zero/sign extend if non-Xmode.
        (riscv_expand_usadd): Leverage the renamed function with ZERO_EXTEND.
        (riscv_expand_ussub): Ditto.

Signed-off-by: Pan Li <pan2...@intel.com>
---
 gcc/config/riscv/riscv.cc | 77 ++++++++++++++++++++++++---------------
 1 file changed, 48 insertions(+), 29 deletions(-)

diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index dd50fe4eddf..34f0a888c5c 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -12644,14 +12644,26 @@ riscv_get_raw_result_mode (int regno)
 /* Generate a REG rtx of Xmode from the given rtx and mode.
    The rtx x can be REG (QI/HI/SI/DI) or const_int.
    The machine_mode mode is the original mode from define pattern.
+   The rtx_code can be ZERO_EXTEND or SIGN_EXTEND.
 
-   If rtx is REG and Xmode, the RTX x will be returned directly.
+   If rtx is REG:
 
-   If rtx is REG and non-Xmode, the zero extended to new REG of Xmode will be
-   returned.
+   1.  If rtx Xmode, the RTX x will be returned directly.
+   2.  If rtx non-Xmode, the extended to new REG of Xmode will be returned.
 
-   If rtx is const_int, a new REG rtx will be created to hold the value of
-   const_int and then returned.
+   The scalar ALU like add don't support non-Xmode like QI/HI.  Then the
+   gen_lowpart will have problem here.  For example, when we would like
+   to add -1 (0xff if QImode) and 2 (0x2 if QImode).  The 0xff and 0x2 will
+   be loaded to register for adding.  Aka:
+
+   0xff + 0x2 = 0x101 instead of -1 + 2 = 1.
+
+   Thus we need to sign extend 0xff to 0xffffffffffffffff if Xmode is DImode
+   for correctness.  Similar the unsigned also need zero extend.
+
+   If rtx is const_int:
+
+   1.  A new REG rtx will be created to hold the value of const_int.
 
    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 there
@@ -12669,34 +12681,41 @@ riscv_get_raw_result_mode (int regno)
    the REG rtx of Xmode, instead of taking care of these in expand func.  */
 
 static rtx
-riscv_gen_zero_extend_rtx (rtx x, machine_mode mode)
+riscv_extend_to_xmode_reg (rtx x, machine_mode mode, enum rtx_code rcode)
 {
+  gcc_assert (rcode == ZERO_EXTEND || rcode == SIGN_EXTEND);
+
   rtx xmode_reg = gen_reg_rtx (Xmode);
 
-  if (!CONST_INT_P (x))
+  if (CONST_INT_P (x))
     {
       if (mode == Xmode)
-       return x;
-
-      riscv_emit_unary (ZERO_EXTEND, xmode_reg, x);
-      return xmode_reg;
-    }
-
-  if (mode == Xmode)
-    emit_move_insn (xmode_reg, x);
-  else
-    {
-      /* Combine deliberately does not simplify extensions of constants
-        (long story).  So try to generate the zero extended constant
-        efficiently.
+       emit_move_insn (xmode_reg, x);
+      else if (rcode == ZERO_EXTEND)
+       {
+         /* Combine deliberately does not simplify extensions of constants
+            (long story).  So try to generate the zero extended constant
+            efficiently.
 
-        First extract the constant and mask off all the bits not in MODE.  */
-      HOST_WIDE_INT val = INTVAL (x);
-      val &= GET_MODE_MASK (mode);
+            First extract the constant and mask off all the bits not in
+            MODE.  */
+         HOST_WIDE_INT val = INTVAL (x);
+         val &= GET_MODE_MASK (mode);
 
-      /* X may need synthesis, so do not blindly copy it.  */
-      xmode_reg = force_reg (Xmode, gen_int_mode (val, Xmode));
+         /* X may need synthesis, so do not blindly copy it.  */
+         xmode_reg = force_reg (Xmode, gen_int_mode (val, Xmode));
+       }
+      else /* SIGN_EXTEND.  */
+       {
+         rtx x_reg = gen_reg_rtx (mode);
+         emit_move_insn (x_reg, x);
+         riscv_emit_unary (rcode, xmode_reg, x_reg);
+       }
     }
+  else if (mode == Xmode)
+    return x;
+  else
+    riscv_emit_unary (rcode, xmode_reg, x);
 
   return xmode_reg;
 }
@@ -12717,8 +12736,8 @@ riscv_expand_usadd (rtx dest, rtx x, rtx y)
   machine_mode mode = GET_MODE (dest);
   rtx xmode_sum = gen_reg_rtx (Xmode);
   rtx xmode_lt = gen_reg_rtx (Xmode);
-  rtx xmode_x = riscv_gen_zero_extend_rtx (x, mode);
-  rtx xmode_y = riscv_gen_zero_extend_rtx (y, mode);
+  rtx xmode_x = riscv_extend_to_xmode_reg (x, mode, ZERO_EXTEND);
+  rtx xmode_y = riscv_extend_to_xmode_reg (y, mode, ZERO_EXTEND);
   rtx xmode_dest = gen_reg_rtx (Xmode);
 
   /* Step-1: sum = x + y  */
@@ -12852,8 +12871,8 @@ void
 riscv_expand_ussub (rtx dest, rtx x, rtx y)
 {
   machine_mode mode = GET_MODE (dest);
-  rtx xmode_x = riscv_gen_zero_extend_rtx (x, mode);
-  rtx xmode_y = riscv_gen_zero_extend_rtx (y, mode);
+  rtx xmode_x = riscv_extend_to_xmode_reg (x, mode, ZERO_EXTEND);
+  rtx xmode_y = riscv_extend_to_xmode_reg (y, mode, ZERO_EXTEND);
   rtx xmode_lt = gen_reg_rtx (Xmode);
   rtx xmode_minus = gen_reg_rtx (Xmode);
   rtx xmode_dest = gen_reg_rtx (Xmode);
-- 
2.43.0

Reply via email to