From: Philipp Tomsich <p...@gnu.org>

While most shifts wider than the bitwidth of a type will be caught by
other passes, it is possible that these show up for VRP.
Consider the following example:
  int func (int a, int b, int c)
  {
    return (a << ((b && c) - 1));
  }

This adds simplify_using_ranges::simplify_lshift_using_ranges to
detect and rewrite such cases.  If the intersection of meaningful
shift amounts for the underlying type and the value-range computed
for the shift-amount (whether an integer constant or a variable) is
empty, the statement is replaced with the zero-constant of the same
precision as the result.

gcc/ChangeLog:

       * 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.

---

 gcc/ChangeLog   |  6 ++++++
 gcc/vr-values.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gcc/vr-values.h |  1 +
 3 files changed, 66 insertions(+)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 89317d4..b8b9beb 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2020-11-16  Philipp Tomsich  <p...@gnu.org>
+
+       * 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.
+
 2020-11-13  Jan Hubicka  <j...@suse.cz>
 
        * tree-ssa-alias.c (ao_ref_base_alias_ptr_type): Remove accidental
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index 9f5943a..da7208e 100644
--- a/gcc/vr-values.c
+++ b/gcc/vr-values.c
@@ -3318,6 +3318,58 @@ simplify_using_ranges::simplify_div_or_mod_using_ranges
   return false;
 }
 
+/* Simplify a lshift, if the shift-amount is larger than the
+   bit-width of the type.  Return true if we do simplify.  */
+bool
+simplify_using_ranges::simplify_lshift_using_ranges
+                               (gimple_stmt_iterator *gsi,
+                                gimple *stmt)
+{
+  tree op0 = gimple_assign_rhs1 (stmt);
+  tree op1 = gimple_assign_rhs2 (stmt);
+  value_range vr1;
+
+  /* We only support integral types.  */
+  if (INTEGRAL_TYPE_P (op0))
+    return false;
+
+  if (TREE_CODE (op1) == INTEGER_CST)
+    vr1.set (op1);
+  else if (TREE_CODE (op1) == SSA_NAME)
+    vr1 = *(query->get_value_range (op1, stmt));
+  else
+    return false;
+
+  if (vr1.varying_p () || vr1.undefined_p ())
+    return false;
+
+  /* Shift amounts are valid up to the type precision.  Any shift that
+     is outside of the range [0, type precision - 1] can be rewritten
+     to a constant result.  */
+  const unsigned prec = TYPE_PRECISION (TREE_TYPE (op0));
+  value_range valid (build_zero_cst (TREE_TYPE (op1)),
+                    build_int_cst (TREE_TYPE (op1), prec - 1),
+                    VR_RANGE);
+
+  valid.intersect (vr1);
+  if (valid.undefined_p ())
+    {
+      /* If the intersection is empty (i.e. undefined), then we can replace the
+        shift with the zero-constant.  */
+
+      if (dump_file && (dump_flags & TDF_DETAILS))
+       {
+         fprintf (dump_file, "\nReplacing shift beyond precision in stmt: ");
+         print_gimple_stmt (dump_file, stmt, 0);
+       }
+      gimple_assign_set_rhs_from_tree (gsi, build_zero_cst (TREE_TYPE (op0)));
+      update_stmt (gsi_stmt (*gsi));
+      return true;
+    }
+
+  return false;
+}
+
 /* Simplify a min or max if the ranges of the two operands are
    disjoint.   Return true if we do simplify.  */
 
@@ -4422,6 +4474,13 @@ simplify_using_ranges::simplify (gimple_stmt_iterator 
*gsi)
        case MAX_EXPR:
          return simplify_min_or_max_using_ranges (gsi, stmt);
 
+       case LSHIFT_EXPR:
+         if ((TREE_CODE (rhs1) == SSA_NAME
+              || TREE_CODE (rhs1) == INTEGER_CST)
+             && INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
+           return simplify_lshift_using_ranges (gsi, stmt);
+         break;
+
        default:
          break;
        }
diff --git a/gcc/vr-values.h b/gcc/vr-values.h
index 59fac0c..18fd5c1 100644
--- a/gcc/vr-values.h
+++ b/gcc/vr-values.h
@@ -48,6 +48,7 @@ private:
   bool simplify_div_or_mod_using_ranges (gimple_stmt_iterator *, gimple *);
   bool simplify_abs_using_ranges (gimple_stmt_iterator *, gimple *);
   bool simplify_bit_ops_using_ranges (gimple_stmt_iterator *, gimple *);
+  bool simplify_lshift_using_ranges (gimple_stmt_iterator *, gimple *);
   bool simplify_min_or_max_using_ranges (gimple_stmt_iterator *, gimple *);
   bool simplify_cond_using_ranges_1 (gcond *);
   bool fold_cond (gcond *);
-- 
1.8.3.1

Reply via email to