[2/2,RISC-V] Optimize switch with sign-extended index.

Message ID 20180502220536.6589-1-jimw@sifive.com
State New
Headers show
Series
  • [1/2,expr.c] Optimize switch with sign-extended index.
Related show

Commit Message

Jim Wilson May 2, 2018, 10:05 p.m.
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

-- 
2.14.1

Comments

Jim Wilson May 17, 2018, 10:43 p.m. | #1
On Wed, May 2, 2018 at 3:05 PM, Jim Wilson <jimw@sifive.com> wrote:>
>         * 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.


Committed.

Jim

Patch

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" } } */