This adds some new patterns to eliminate some unecessary zero/sign extends. This also adds one testcase for each pattern, and one testcase that works only with the rtx_costs change. There is a lot more work to be done here, but this does help. With a toolchain/linux kernel/busybox build, I see these patterns trigger a little over 2300 times.
This was tested with a gcc make check, with no regressions. It was also tested by building the toolchain/linux kernel/busybox and booting the kernel on a simulator. Committed. gcc/ * config/riscv/riscv.c (SINGLE_SHIFT_COST): New. (riscv_rtx_costs): Case ZERO_EXTRACT, match new pattern, and return SINGLE_SHIFT_COST. Case LT and ZERO_EXTEND, likewise. Case ASHIFT, use SINGLE_SHIFT_COST. * config/riscv/riscv.md (lshrsi3_zero_extend_1): New. (lshrsi3_zero_extend_2, lshrsi3_zero_extend_3): New. gcc/testsuite/ * gcc.target/riscv/riscv.exp: New. * gcc.target/riscv/zero-extend-1.c: New. * gcc.target/riscv/zero-extend-2.c: New. * gcc.target/riscv/zero-extend-3.c: New. * gcc.target/riscv/zero-extend-4.c: New. --- gcc/config/riscv/riscv.c | 32 +++++++++++++++++-- gcc/config/riscv/riscv.md | 43 ++++++++++++++++++++++++++ gcc/testsuite/gcc.target/riscv/riscv.exp | 41 ++++++++++++++++++++++++ gcc/testsuite/gcc.target/riscv/zero-extend-1.c | 8 +++++ gcc/testsuite/gcc.target/riscv/zero-extend-2.c | 13 ++++++++ gcc/testsuite/gcc.target/riscv/zero-extend-3.c | 12 +++++++ gcc/testsuite/gcc.target/riscv/zero-extend-4.c | 20 ++++++++++++ 7 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/riscv.exp create mode 100644 gcc/testsuite/gcc.target/riscv/zero-extend-1.c create mode 100644 gcc/testsuite/gcc.target/riscv/zero-extend-2.c create mode 100644 gcc/testsuite/gcc.target/riscv/zero-extend-3.c create mode 100644 gcc/testsuite/gcc.target/riscv/zero-extend-4.c diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c index 279af909a69..5547d68193c 100644 --- a/gcc/config/riscv/riscv.c +++ b/gcc/config/riscv/riscv.c @@ -1429,6 +1429,8 @@ riscv_extend_cost (rtx op, bool unsigned_p) /* Implement TARGET_RTX_COSTS. */ +#define SINGLE_SHIFT_COST 1 + static bool riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UNUSED, int *total, bool speed) @@ -1489,10 +1491,21 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN *total = riscv_binary_cost (x, 1, 2); return false; + case ZERO_EXTRACT: + /* This is an SImode shift. */ + if (outer_code == SET && (INTVAL (XEXP (x, 2)) > 0) + && (INTVAL (XEXP (x, 1)) + INTVAL (XEXP (x, 2)) == 32)) + { + *total = COSTS_N_INSNS (SINGLE_SHIFT_COST); + return true; + } + return false; + case ASHIFT: case ASHIFTRT: case LSHIFTRT: - *total = riscv_binary_cost (x, 1, CONSTANT_P (XEXP (x, 1)) ? 4 : 9); + *total = riscv_binary_cost (x, SINGLE_SHIFT_COST, + CONSTANT_P (XEXP (x, 1)) ? 4 : 9); return false; case ABS: @@ -1504,6 +1517,14 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN return true; case LT: + /* This is an SImode shift. */ + if (outer_code == SET && GET_MODE (x) == DImode + && GET_MODE (XEXP (x, 0)) == SImode) + { + *total = COSTS_N_INSNS (SINGLE_SHIFT_COST); + return true; + } + /* Fall through. */ case LTU: case LE: case LEU: @@ -1601,8 +1622,15 @@ riscv_rtx_costs (rtx x, machine_mode mode, int outer_code, int opno ATTRIBUTE_UN *total = COSTS_N_INSNS (1); return false; - case SIGN_EXTEND: case ZERO_EXTEND: + /* This is an SImode shift. */ + if (GET_CODE (XEXP (x, 0)) == LSHIFTRT) + { + *total = COSTS_N_INSNS (SINGLE_SHIFT_COST); + return true; + } + /* Fall through. */ + case SIGN_EXTEND: *total = riscv_extend_cost (XEXP (x, 0), GET_CODE (x) == ZERO_EXTEND); return false; diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 814ff6ec6ad..db4fed48e53 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -1524,6 +1524,49 @@ [(set_attr "type" "shift") (set_attr "mode" "SI")]) +;; Non-canonical, but can be formed by ree when combine is not successful at +;; producing one of the two canonical patterns below. +(define_insn "*lshrsi3_zero_extend_1" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extend:DI + (lshiftrt:SI (match_operand:SI 1 "register_operand" " r") + (match_operand:SI 2 "const_int_operand"))))] + "TARGET_64BIT && (INTVAL (operands[2]) & 0x1f) > 0" +{ + operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); + + return "srliw\t%0,%1,%2"; +} + [(set_attr "type" "shift") + (set_attr "mode" "SI")]) + +;; Canonical form for a zero-extend of a logical right shift. +(define_insn "*lshrsi3_zero_extend_2" + [(set (match_operand:DI 0 "register_operand" "=r") + (zero_extract:DI (match_operand:DI 1 "register_operand" " r") + (match_operand 2 "const_int_operand") + (match_operand 3 "const_int_operand")))] + "(TARGET_64BIT && (INTVAL (operands[3]) > 0) + && (INTVAL (operands[2]) + INTVAL (operands[3]) == 32))" +{ + return "srliw\t%0,%1,%3"; +} + [(set_attr "type" "shift") + (set_attr "mode" "SI")]) + +;; Canonical form for a zero-extend of a logical right shift when the +;; shift count is 31. +(define_insn "*lshrsi3_zero_extend_3" + [(set (match_operand:DI 0 "register_operand" "=r") + (lt:DI (match_operand:SI 1 "register_operand" " r") + (const_int 0)))] + "TARGET_64BIT" +{ + return "srliw\t%0,%1,31"; +} + [(set_attr "type" "shift") + (set_attr "mode" "SI")]) + ;; ;; .................... ;; diff --git a/gcc/testsuite/gcc.target/riscv/riscv.exp b/gcc/testsuite/gcc.target/riscv/riscv.exp new file mode 100644 index 00000000000..7b1f7e097fb --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/riscv.exp @@ -0,0 +1,41 @@ +# Copyright (C) 2017 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# <http://www.gnu.org/licenses/>. + +# GCC testsuite that uses the `dg.exp' driver. + +# Exit immediately if this isn't a RISC-V target. +if ![istarget riscv*-*-*] then { + return +} + +# Load support procs. +load_lib gcc-dg.exp + +# If a testcase doesn't have special options, use these. +global DEFAULT_CFLAGS +if ![info exists DEFAULT_CFLAGS] then { + set DEFAULT_CFLAGS " -ansi -pedantic-errors" +} + +# Initialize `dg'. +dg-init + +# Main loop. +dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cS\]]] \ + "" $DEFAULT_CFLAGS + +# All done. +dg-finish diff --git a/gcc/testsuite/gcc.target/riscv/zero-extend-1.c b/gcc/testsuite/gcc.target/riscv/zero-extend-1.c new file mode 100644 index 00000000000..8a7d84ddbca --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zero-extend-1.c @@ -0,0 +1,8 @@ +/* { dg-do compile { target { riscv64*-*-* } } } */ +/* { dg-options "-march=rv64gc -mabi=lp64 -O2" } */ +unsigned long +sub1 (unsigned int i) +{ + return i >> 1; +} +/* { dg-final { scan-assembler-times "srliw" 1 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zero-extend-2.c b/gcc/testsuite/gcc.target/riscv/zero-extend-2.c new file mode 100644 index 00000000000..9d30ae29367 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zero-extend-2.c @@ -0,0 +1,13 @@ +/* { dg-do compile { target { riscv64*-*-* } } } */ +/* { dg-options "-march=rv64gc -mabi=lp64 -O2" } */ +void +sub (unsigned int wc, unsigned long step, unsigned char *start) +{ + do + { + start[--step] = wc; + wc >>= 6; + } + while (step > 1); +} +/* { dg-final { scan-assembler-times "sext.w" 0 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zero-extend-3.c b/gcc/testsuite/gcc.target/riscv/zero-extend-3.c new file mode 100644 index 00000000000..eb3b8d43959 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zero-extend-3.c @@ -0,0 +1,12 @@ +/* { dg-do compile { target { riscv64*-*-* } } } */ +/* { dg-options "-march=rv64gc -mabi=lp64 -O2" } */ +extern int e (void); +enum { a, b } +c (void) +{ + int d = a; + if (e() < 0) + d = b; + return d; +} +/* { dg-final { scan-assembler-times "sext.w" 0 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zero-extend-4.c b/gcc/testsuite/gcc.target/riscv/zero-extend-4.c new file mode 100644 index 00000000000..d7703a6dfb7 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zero-extend-4.c @@ -0,0 +1,20 @@ +/* { dg-do compile { target { riscv64*-*-* } } } */ +/* { dg-options "-march=rv64gc -mabi=lp64 -O2" } */ +int a, b, e; +struct c *d; +struct c +{ + int bins; + int binmap[10]; +} +f(void) +{ + for (;;) + { + e = (unsigned) a >> 3; + b = (long) &d[e]; + if (b) + d->binmap[0] = e; + } +} +/* { dg-final { scan-assembler-times "sext.w" 0 } } */ -- 2.14.1