From: Philipp Tomsich <p...@gnu.org> In case a negative shift operand makes it through into the backend, it will be treated as unsigned and truncated (using a mask) to fit into the range 0..31 (for SImode) and 0..63 (for DImode).
Consider the following output illustrating the issue and shows how the shift amount is truncated): #(insn 16 15 53 (set (reg:DI 10 a0 [orig:72 <retval> ] [72]) # (sign_extend:DI (ashift:SI (reg:SI 15 a5 [orig:73 a ] [73]) # (const_int -1 [0xffffffffffffffff])))) "isolated.c":3:13 168 {*ashlsi3_extend} # (expr_list:REG_DEAD (reg:SI 15 a5 [orig:73 a ] [73]) # (nil))) slliw a0,a5,31 #, <retval>, a # 16 [c=8 l=4] *ashlsi3_extend This change adjusts the predicates to allow immediate shifts for the supported ranges 0..31 and 0..63, respectively, only. As immediates outside of these ranges can no longer pass the constraint-check, the implementation of the patterns emitting the respective shift can also be simplified. Larger shift amounts will now be forced along a path resulting in a non-immediate shift. A new testcase is added to check that non-immediate shift instructions are emitted. gcc/ChangeLog: * config/riscv/predicates.md (riscv_shift_imm_si, riscv_shift_si, riscv_shift_imm_di, riscv_shift_di): New. * config/riscv/riscv.md: Use 'riscv_shift_si' and 'riscv_shift_di' in definition of shift instructions; remove (now unnecessary) truncation of immediates. gcc/testsuite/ChangeLog: * gcc.target/riscv/shift-negative-amount.c: New. --- gcc/ChangeLog | 5 +++++ gcc/config/riscv/predicates.md | 16 ++++++++++++++++ gcc/config/riscv/riscv.md | 21 ++++----------------- gcc/testsuite/ChangeLog | 4 ++++ .../gcc.target/riscv/shift-negative-amount.c | 14 ++++++++++++++ 5 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/shift-negative-amount.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b8b9beb..6ca8ee0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,10 @@ 2020-11-16 Philipp Tomsich <p...@gnu.org> + * config/riscv/predicates.md (riscv_shift_imm_si, riscv_shift_si, + riscv_shift_imm_di, riscv_shift_di): New. + * config/riscv/riscv.md: Use 'riscv_shift_si' and 'riscv_shift_di' + in definition of shift instructions; remove (now unnecessary) + truncation of immediates. * vr-values.h (simplify_using_ranges): Declare. * vr-values.c (simplify_lshift_using_ranges): New function. (simplify): Use simplify_lshift_using_ranges for LSHIFT_EXPR. diff --git a/gcc/config/riscv/predicates.md b/gcc/config/riscv/predicates.md index f764fe7..fb35871 100644 --- a/gcc/config/riscv/predicates.md +++ b/gcc/config/riscv/predicates.md @@ -27,6 +27,22 @@ (ior (match_operand 0 "const_arith_operand") (match_operand 0 "register_operand"))) +(define_predicate "riscv_shift_imm_si" + (and (match_code "const_int") + (match_test "(unsigned HOST_WIDE_INT) INTVAL (op) < 32"))) + +(define_predicate "riscv_shift_si" + (ior (match_operand 0 "riscv_shift_imm_si") + (match_operand 0 "register_operand"))) + +(define_predicate "riscv_shift_imm_di" + (and (match_code "const_int") + (match_test "(unsigned HOST_WIDE_INT) INTVAL (op) < 64"))) + +(define_predicate "riscv_shift_di" + (ior (match_operand 0 "riscv_shift_imm_di") + (match_operand 0 "register_operand"))) + (define_predicate "lui_operand" (and (match_code "const_int") (match_test "LUI_OPERAND (INTVAL (op))"))) diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index f15bad3..7b34839 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -1574,13 +1574,9 @@ [(set (match_operand:SI 0 "register_operand" "= r") (any_shift:SI (match_operand:SI 1 "register_operand" " r") - (match_operand:QI 2 "arith_operand" " rI")))] + (match_operand:QI 2 "riscv_shift_si" " rI")))] "" { - if (GET_CODE (operands[2]) == CONST_INT) - operands[2] = GEN_INT (INTVAL (operands[2]) - & (GET_MODE_BITSIZE (SImode) - 1)); - return TARGET_64BIT ? "<insn>%i2w\t%0,%1,%2" : "<insn>%i2\t%0,%1,%2"; } [(set_attr "type" "shift") @@ -1629,13 +1625,9 @@ [(set (match_operand:DI 0 "register_operand" "= r") (any_shift:DI (match_operand:DI 1 "register_operand" " r") - (match_operand:QI 2 "arith_operand" " rI")))] + (match_operand:QI 2 "riscv_shift_di" " rI")))] "TARGET_64BIT" { - if (GET_CODE (operands[2]) == CONST_INT) - operands[2] = GEN_INT (INTVAL (operands[2]) - & (GET_MODE_BITSIZE (DImode) - 1)); - return "<insn>%i2\t%0,%1,%2"; } [(set_attr "type" "shift") @@ -1685,14 +1677,9 @@ [(set (match_operand:DI 0 "register_operand" "= r") (sign_extend:DI (any_shift:SI (match_operand:SI 1 "register_operand" " r") - (match_operand:QI 2 "arith_operand" " rI"))))] + (match_operand:QI 2 "riscv_shift_si" " rI"))))] "TARGET_64BIT" -{ - if (GET_CODE (operands[2]) == CONST_INT) - operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); - - return "<insn>%i2w\t%0,%1,%2"; -} + "<insn>%i2w\t%0,%1,%2" [(set_attr "type" "shift") (set_attr "mode" "SI")]) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a748ff6..1efe87d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2020-11-16 Philipp Tomsich <p...@gnu.org> + + * gcc.target/riscv/shift-negative-amount.c: New. + 2020-11-13 Joseph Myers <jos...@codesourcery.com> * gcc.dg/binary-constants-2.c, gcc.dg/binary-constants-3.c, diff --git a/gcc/testsuite/gcc.target/riscv/shift-negative-amount.c b/gcc/testsuite/gcc.target/riscv/shift-negative-amount.c new file mode 100644 index 0000000..0db5e4d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/shift-negative-amount.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc -mabi=lp64 -O2 -fno-tree-vrp" } */ + +int shift1 (int a, int b, int c) +{ + return (a << ((b && c) - 1)); +} + +long int shift2 (long int a, long int b, long int c) +{ + return (a << ((b && c) - 1)); +} +/* { dg-final { scan-assembler "sllw" } } */ +/* { dg-final { scan-assembler "sll" } } */ -- 1.8.3.1