We produce inefficient code for some synthesized SImode conditional set 
operations (i.e. ones that are not directly implemented in hardware) on 
RV64.  For example a piece of C code like this:

int
sleu (unsigned int x, unsigned int y)
{
  return x <= y;
}

gets compiled (at `-O2') to this:

sleu:
        sgtu    a0,a0,a1        # 9     [c=4 l=4]  *sgtu_disi
        xori    a0,a0,1         # 10    [c=4 l=4]  *xorsi3_internal/1
        sext.w  a0,a0           # 16    [c=4 l=4]  extendsidi2/0
        ret                     # 25    [c=0 l=4]  simple_return

This is because the middle end expands a SLEU operation missing from 
RISC-V hardware into a sequence of a SImode SGTU operation followed by 
an explicit SImode XORI operation with immediate 1.  And while the SGTU 
machine instruction (alias SLTU with the input operands swapped) gives a 
properly sign-extended 32-bit result which is valid both as a SImode or 
a DImode operand the middle end does not see that through a SImode XORI 
operation, because we tell the middle end that the RISC-V target (unlike 
MIPS) may hold values in DImode integer registers that are valid for 
SImode operations even if not properly sign-extended.

However the RISC-V psABI requires that 32-bit function arguments and 
results passed in 64-bit integer registers be properly sign-extended, so 
this is explicitly done at the conclusion of the function.

Fix this by making the backend use a sequence of a DImode SGTU operation 
followed by a SImode SEQZ operation instead.  The latter operation is 
known by the middle end to produce a properly sign-extended 32-bit 
result and therefore combine gets rid of the sign-extension operation 
that follows and actually folds it into the very same XORI machine 
operation resulting in:

sleu:
        sgtu    a0,a0,a1        # 9     [c=4 l=4]  *sgtu_didi
        xori    a0,a0,1         # 16    [c=4 l=4]  xordi3/1
        ret                     # 25    [c=0 l=4]  simple_return

instead (although the SEQZ alias SLTIU against immediate 1 machine 
instruction would equally do and is actually retained at `-O0').  This 
is handled analogously for the remaining synthesized operations of this 
kind, i.e. `SLE', `SGEU', and `SGE'.

        gcc/
        * config/riscv/riscv.cc (riscv_emit_int_order_test): Use EQ 0 
        rather that XOR 1 for LE and LEU operations.

        gcc/testsuite/
        * gcc.target/riscv/sge.c: New test.
        * gcc.target/riscv/sgeu.c: New test.
        * gcc.target/riscv/sle.c: New test.
        * gcc.target/riscv/sleu.c: New test.
---
Hi,

 Regression-tested with the `riscv64-linux-gnu' target.  OK to apply?

  Maciej
---
 gcc/config/riscv/riscv.cc             |    4 ++--
 gcc/testsuite/gcc.target/riscv/sge.c  |   11 +++++++++++
 gcc/testsuite/gcc.target/riscv/sgeu.c |   11 +++++++++++
 gcc/testsuite/gcc.target/riscv/sle.c  |   11 +++++++++++
 gcc/testsuite/gcc.target/riscv/sleu.c |   11 +++++++++++
 5 files changed, 46 insertions(+), 2 deletions(-)

gcc-riscv-int-order-inv-seqz.diff
Index: gcc/gcc/config/riscv/riscv.cc
===================================================================
--- gcc.orig/gcc/config/riscv/riscv.cc
+++ gcc/gcc/config/riscv/riscv.cc
@@ -2500,9 +2500,9 @@ riscv_emit_int_order_test (enum rtx_code
        }
       else if (invert_ptr == 0)
        {
-         rtx inv_target = riscv_force_binary (GET_MODE (target),
+         rtx inv_target = riscv_force_binary (word_mode,
                                               inv_code, cmp0, cmp1);
-         riscv_emit_binary (XOR, target, inv_target, const1_rtx);
+         riscv_emit_binary (EQ, target, inv_target, const0_rtx);
        }
       else
        {
Index: gcc/gcc/testsuite/gcc.target/riscv/sge.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.target/riscv/sge.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target rv64 } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+int
+sge (int x, int y)
+{
+  return x >= y;
+}
+
+/* { dg-final { scan-assembler-not "sext\\.w" } } */
Index: gcc/gcc/testsuite/gcc.target/riscv/sgeu.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.target/riscv/sgeu.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target rv64 } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+int
+sgeu (unsigned int x, unsigned int y)
+{
+  return x >= y;
+}
+
+/* { dg-final { scan-assembler-not "sext\\.w" } } */
Index: gcc/gcc/testsuite/gcc.target/riscv/sle.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.target/riscv/sle.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target rv64 } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+int
+sle (int x, int y)
+{
+  return x <= y;
+}
+
+/* { dg-final { scan-assembler-not "sext\\.w" } } */
Index: gcc/gcc/testsuite/gcc.target/riscv/sleu.c
===================================================================
--- /dev/null
+++ gcc/gcc/testsuite/gcc.target/riscv/sleu.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target rv64 } */
+/* { dg-skip-if "" { *-*-* } { "-O0" } } */
+
+int
+sleu (unsigned int x, unsigned int y)
+{
+  return x <= y;
+}
+
+/* { dg-final { scan-assembler-not "sext\\.w" } } */

Reply via email to