]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Simplification for right shift.
authorAndrew MacLeod <amacleod@redhat.com>
Thu, 14 Oct 2021 14:43:58 +0000 (10:43 -0400)
committerAndrew MacLeod <amacleod@redhat.com>
Thu, 14 Oct 2021 17:56:37 +0000 (13:56 -0400)
When the first operand of a signed right shift is zero or negative one, the
RHS doesn't matter and the shift can be converted to a copy.

PR tree-optimization/102738
gcc/
* vr-values.c (simplify_using_ranges::simplify): Handle RSHIFT_EXPR.

gcc/testsuite
* gcc.dg/pr102738.c: New.

gcc/testsuite/gcc.dg/pr102738.c [new file with mode: 0644]
gcc/vr-values.c

diff --git a/gcc/testsuite/gcc.dg/pr102738.c b/gcc/testsuite/gcc.dg/pr102738.c
new file mode 100644 (file)
index 0000000..776fcec
--- /dev/null
@@ -0,0 +1,48 @@
+/* PR tree-optimization/102738 */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+/* Remove arithmetic shift right when the LHS is known to be 0 or -1.  */
+
+int a1(__int128 f, int g)
+{
+     /* Leaves f >> 127.  */
+    return (f >> 127) >> g;
+}
+
+int a2(int f, int g)
+{
+     /* Leaves f >> 31.  */
+    return (f >> 31) >> g;
+}
+
+int a3(int f, int g)
+{
+    if (f == 0 || f == -1)
+      return f >> g;
+    __builtin_unreachable();
+}
+
+int a4(int f, int g)
+{
+    if (f == 0 || f == 1)
+      return (-f) >> g;
+    __builtin_unreachable();
+}
+
+int a5(int f, int g)
+{
+    if (f == 0 || f == 1)
+      return (f-1) >> g;
+    return 0;
+}
+
+int a6(int f, int g)
+{
+    if (f == 6 || f == 7)
+      return (f-7) >> g;
+    __builtin_unreachable();
+}
+
+/* { dg-final { scan-tree-dump-times " >> 127" 1 "evrp" } } */
+/* { dg-final { scan-tree-dump-times " >> 31" 1 "evrp" } } */
+/* { dg-final { scan-tree-dump-times " >> " 2 "evrp" } } */
index 9bf58f416f2d86f2fcb2a494861fa6807fa52fb7..d0f7cb41bc851058236980f98b4021a3eb20d4d9 100644 (file)
@@ -4281,6 +4281,28 @@ simplify_using_ranges::simplify (gimple_stmt_iterator *gsi)
        case MAX_EXPR:
          return simplify_min_or_max_using_ranges (gsi, stmt);
 
+       case RSHIFT_EXPR:
+         {
+           tree op0 = gimple_assign_rhs1 (stmt);
+           tree type = TREE_TYPE (op0);
+           int_range_max range;
+           if (TYPE_SIGN (type) == SIGNED
+               && query->range_of_expr (range, op0, stmt))
+             {
+               unsigned prec = TYPE_PRECISION (TREE_TYPE (op0));
+               int_range<2> nzm1 (type, wi::minus_one (prec), wi::zero (prec),
+                                  VR_ANTI_RANGE);
+               range.intersect (nzm1);
+               // If there are no ranges other than [-1, 0] remove the shift.
+               if (range.undefined_p ())
+                 {
+                   gimple_assign_set_rhs_from_tree (gsi, op0);
+                   return true;
+                 }
+               return false;
+             }
+           break;
+         }
        default:
          break;
        }