In the RISC-V backend, there is code that does a zero-extend by default for
QImode compare arguments.  This is because zero-extend is a single and insn,
whereas sign-extend is two shifts.  However, if we have two values that are
already sign extended, or a sign extended value and a CONST_INT, then we get
better code if we do the sign-extend, as this requires 0 instructions.

Without the patch, for a switch using signed char, I get
        andi    a0,a0,0xff
        li      a5,4
        bgtu    a0,a5,.L1
and with the patch the andi is optimized aways.

This patch contains two testcases.  The switch-si.c testcase requires the
previous patch to pass.  The switch-qi.c testcase requires both this patch
and the previous patch to pass.

This was tested with riscv{32,64}-{elf,linux} cross builds and testsuite runs.
There were no regressions.

Since this is a RISC-V specific patch, I can self approve it.

Jim

        gcc/
        * config/riscv/riscv.c (riscv_extend_comparands): In unsigned QImode
        test, check for sign extended subreg and/or constant operands, and
        do a sign extend in that case.

        gcc/testsuite/
        * gcc.target/riscv/switch-qi.c: New.
        * gcc.target/riscv/switch-si.c: New.
---
 gcc/config/riscv/riscv.c                   | 14 ++++++++++++--
 gcc/testsuite/gcc.target/riscv/switch-qi.c | 15 +++++++++++++++
 gcc/testsuite/gcc.target/riscv/switch-si.c | 15 +++++++++++++++
 3 files changed, 42 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/switch-qi.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/switch-si.c

diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
index 2a8f87d1e94..b4975888bbb 100644
--- a/gcc/config/riscv/riscv.c
+++ b/gcc/config/riscv/riscv.c
@@ -2002,8 +2002,18 @@ riscv_extend_comparands (rtx_code code, rtx *op0, rtx 
*op1)
   /* Comparisons consider all XLEN bits, so extend sub-XLEN values.  */
   if (GET_MODE_SIZE (word_mode) > GET_MODE_SIZE (GET_MODE (*op0)))
     {
-      /* It is more profitable to zero-extend QImode values.  */
-      if (unsigned_condition (code) == code && GET_MODE (*op0) == QImode)
+      /* It is more profitable to zero-extend QImode values.  But not if the
+        first operand has already been sign-extended, and the second one is
+        is a constant or has already been sign-extended also.  */
+      if (unsigned_condition (code) == code
+         && (GET_MODE (*op0) == QImode
+             && ! (GET_CODE (*op0) == SUBREG
+                   && SUBREG_PROMOTED_VAR_P (*op0)
+                   && SUBREG_PROMOTED_SIGNED_P (*op0)
+                   && (CONST_INT_P (*op1)
+                       || (GET_CODE (*op1) == SUBREG
+                           && SUBREG_PROMOTED_VAR_P (*op1)
+                           && SUBREG_PROMOTED_SIGNED_P (*op1))))))
        {
          *op0 = gen_rtx_ZERO_EXTEND (word_mode, *op0);
          if (CONST_INT_P (*op1))
diff --git a/gcc/testsuite/gcc.target/riscv/switch-qi.c 
b/gcc/testsuite/gcc.target/riscv/switch-qi.c
new file mode 100644
index 00000000000..973d09aaaf1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/switch-qi.c
@@ -0,0 +1,15 @@
+/* { dg-do compile { target { riscv64*-*-* } } } */
+/* { dg-options "-march=rv64gc -mabi=lp64 -O2" } */
+
+/* Test for riscv_extend_comparands patch.  */
+extern void asdf(int);
+void foo(signed char x) {
+  switch (x) {
+  case 0: asdf(10); break;
+  case 1: asdf(11); break;
+  case 2: asdf(12); break;
+  case 3: asdf(13); break;
+  case 4: asdf(14); break;
+  }
+}
+/* { dg-final { scan-assembler-not "andi" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/switch-si.c 
b/gcc/testsuite/gcc.target/riscv/switch-si.c
new file mode 100644
index 00000000000..de4d68f4d0e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/switch-si.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+/* Test for do_tablejump patch.  */
+extern void asdf(int);
+void foo(int x) {
+  switch (x) {
+  case 0: asdf(10); break;
+  case 1: asdf(11); break;
+  case 2: asdf(12); break;
+  case 3: asdf(13); break;
+  case 4: asdf(14); break;
+  }
+}
+/* { dg-final { scan-assembler-not "srli" } } */
-- 
2.14.1

Reply via email to