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

Reply via email to