RISC-V: Optimize switch with sign-extended index.
authorJim Wilson <jimw@sifive.com>
Thu, 17 May 2018 22:37:38 +0000 (22:37 +0000)
committerJim Wilson <wilson@gcc.gnu.org>
Thu, 17 May 2018 22:37:38 +0000 (15:37 -0700)
gcc/
* expr.c (do_tablejump): When converting index to Pmode, if we have a
sign extended promoted subreg, and the range does not have the sign bit
set, then do a sign extend.

* 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.

From-SVN: r260340

gcc/ChangeLog
gcc/config/riscv/riscv.c
gcc/expr.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/riscv/switch-qi.c [new file with mode: 0644]
gcc/testsuite/gcc.target/riscv/switch-si.c [new file with mode: 0644]

index e027c17551b0bd6a4044ad7f8cb8471233ac007c..cc71c8b12e9fe7a193b406b5c36185acd823b5f0 100644 (file)
@@ -1,3 +1,13 @@
+2018-05-17  Jim Wilson  <jimw@sifive.com>
+
+       * expr.c (do_tablejump): When converting index to Pmode, if we have a
+       sign extended promoted subreg, and the range does not have the sign bit
+       set, then do a sign extend.
+
+       * 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.
+
 2018-05-17  Steve Ellcey  <sellcey@cavium.com>
 
        * config/aarch64/thunderx2t99.md (thunderx2t99_ls_both): Delete.
index 2a8f87d1e9447402d5da1c709d52b84ebf306295..b4975888bbbe0a33ac7b6ade5808fa3c039d990a 100644 (file)
@@ -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))
index 9dd0e60d24d3e4829c44b2df65f2013920eced48..00a802c2ad09d44e4d49112f5e7626cb5e7d03ee 100644 (file)
@@ -11782,11 +11782,26 @@ do_tablejump (rtx index, machine_mode mode, rtx range, rtx table_label,
     emit_cmp_and_jump_insns (index, range, GTU, NULL_RTX, mode, 1,
                             default_label, default_probability);
 
-
   /* If index is in range, it must fit in Pmode.
      Convert to Pmode so we can index with it.  */
   if (mode != Pmode)
-    index = convert_to_mode (Pmode, index, 1);
+    {
+      unsigned int width;
+
+      /* We know the value of INDEX is between 0 and RANGE.  If we have a
+        sign-extended subreg, and RANGE does not have the sign bit set, then
+        we have a value that is valid for both sign and zero extension.  In
+        this case, we get better code if we sign extend.  */
+      if (GET_CODE (index) == SUBREG
+         && SUBREG_PROMOTED_VAR_P (index)
+         && SUBREG_PROMOTED_SIGNED_P (index)
+         && ((width = GET_MODE_PRECISION (as_a <scalar_int_mode> (mode)))
+             <= HOST_BITS_PER_WIDE_INT)
+         && ! (UINTVAL (range) & (HOST_WIDE_INT_1U << (width - 1))))
+       index = convert_to_mode (Pmode, index, 0);
+      else
+       index = convert_to_mode (Pmode, index, 1);
+    }
 
   /* Don't let a MEM slip through, because then INDEX that comes
      out of PIC_CASE_VECTOR_ADDRESS won't be a valid address,
index 2dd034016c05d3f1d6aaf458b9094740a7820818..7442eb4c9e201c9d39f4ef344f2a77fc95228ead 100644 (file)
@@ -1,3 +1,8 @@
+2018-05-17  Jim Wilson  <jimw@sifive.com>
+
+       * gcc.target/riscv/switch-qi.c: New.
+       * gcc.target/riscv/switch-si.c: New.
+
 2018-05-17  Pat Haugen  <pthaugen@us.ibm.com>
 
        PR target/85698
diff --git a/gcc/testsuite/gcc.target/riscv/switch-qi.c b/gcc/testsuite/gcc.target/riscv/switch-qi.c
new file mode 100644 (file)
index 0000000..973d09a
--- /dev/null
@@ -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 (file)
index 0000000..de4d68f
--- /dev/null
@@ -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" } } */