As the PR observes, if the first operand of a right shift is 0 or -1,
operand 2 doesn't matter and the result will be the same as op1, so it
can be turned into a copy.
This patch checks for that condition and performs the operation in EVRP.
Bootstrapped on x86_64-pc-linux-gnu with no regressions. Pushed.
Andrew
commit f0b7d4cc49ddb1c2c7474cc3f61e260aa93a96c0
Author: Andrew MacLeod <amacl...@redhat.com>
Date: Thu Oct 14 10:43:58 2021 -0400
Simplification for right shift.
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.
diff --git a/gcc/testsuite/gcc.dg/pr102738.c b/gcc/testsuite/gcc.dg/pr102738.c
new file mode 100644
index 00000000000..776fcecb27a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr102738.c
@@ -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" } } */
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index 9bf58f416f2..d0f7cb41bc8 100644
--- a/gcc/vr-values.c
+++ b/gcc/vr-values.c
@@ -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;
}