tree-vrp.c (is_masked_range_test): New function.
authorYury Gribov <tetra2005@gmail.com>
Tue, 13 Jun 2017 11:16:15 +0000 (11:16 +0000)
committerMaxim Ostapenko <chefmax@gcc.gnu.org>
Tue, 13 Jun 2017 11:16:15 +0000 (14:16 +0300)
2017-06-13  Yury Gribov  <tetra2005@gmail.com>

gcc/
* tree-vrp.c (is_masked_range_test): New function.
(register_edge_assert_for): Determine ranges for
some bit tests.

From-SVN: r249150

gcc/ChangeLog
gcc/tree-vrp.c

index 83f0480..4567036 100644 (file)
@@ -1,5 +1,11 @@
 2017-06-13  Yury Gribov  <tetra2005@gmail.com>
 
+       * tree-vrp.c (is_masked_range_test): New function.
+       (register_edge_assert_for): Determine ranges for
+       some bit tests.
+
+2017-06-13  Yury Gribov  <tetra2005@gmail.com>
+
        PR tree-optimization/67328
        * fold-const.c (maskable_range_p): New function.
        (build_range_check): Generate bittests if possible.
index 716a7c2..a7424a3 100644 (file)
@@ -5628,6 +5628,82 @@ register_edge_assert_for_1 (tree op, enum tree_code code,
     }
 }
 
+/* Check if comparison
+     NAME COND_OP INTEGER_CST
+   has a form of
+     (X & 11...100..0) COND_OP XX...X00...0
+   Such comparison can yield assertions like
+     X >= XX...X00...0
+     X <= XX...X11...1
+   in case of COND_OP being NE_EXPR or
+     X < XX...X00...0
+     X > XX...X11...1
+   in case of EQ_EXPR.  */
+
+static bool
+is_masked_range_test (tree name, tree valt, enum tree_code cond_code,
+                     tree *new_name, tree *low, enum tree_code *low_code,
+                     tree *high, enum tree_code *high_code)
+{
+  gimple *def_stmt = SSA_NAME_DEF_STMT (name);
+
+  if (!is_gimple_assign (def_stmt)
+      || gimple_assign_rhs_code (def_stmt) != BIT_AND_EXPR)
+    return false;
+
+  tree maskt = gimple_assign_rhs2 (def_stmt);
+  if (TREE_CODE (maskt) != INTEGER_CST)
+    return false;
+
+  wide_int mask = maskt;
+  wide_int inv_mask = ~mask;
+  wide_int val = valt;  // Assume VALT is INTEGER_CST
+
+  if ((inv_mask & (inv_mask + 1)) != 0
+      || (val & mask) != val)
+    return false;
+
+  tree t = gimple_assign_rhs1 (def_stmt);
+  tree type = TREE_TYPE (t);
+
+  bool is_range = cond_code == EQ_EXPR;
+
+  wide_int min = wi::min_value (type),
+    max = wi::max_value (type);
+
+  if (is_range)
+    {
+      *low_code = val == min ? ERROR_MARK : GE_EXPR;
+      *high_code = val == max ? ERROR_MARK : LE_EXPR;
+    }
+  else
+    {
+      /* We can still generate assertion if one of alternatives
+        is known to always be false.  */
+      if (val == min)
+       {
+         *low_code = (enum tree_code) 0;
+         *high_code = GT_EXPR;
+       }
+      else if ((val | inv_mask) == max)
+       {
+         *low_code = LT_EXPR;
+         *high_code = (enum tree_code) 0;
+       }
+      else
+       return false;
+    }
+
+  *new_name = t;
+  *low = wide_int_to_tree (type, val);
+  *high = wide_int_to_tree (type, val | inv_mask);
+
+  if (wi::neg_p (val, TYPE_SIGN (type)))
+    std::swap (*low, *high);
+
+  return true;
+}
+
 /* Try to register an edge assertion for SSA name NAME on edge E for
    the condition COND contributing to the conditional jump pointed to by
    SI.  */
@@ -5700,6 +5776,24 @@ register_edge_assert_for (tree name, edge e,
          register_edge_assert_for_1 (op1, EQ_EXPR, e, asserts);
        }
     }
+
+  /* Sometimes we can infer ranges from (NAME & MASK) == VALUE.  */
+  if ((comp_code == EQ_EXPR || comp_code == NE_EXPR)
+      && TREE_CODE (val) == INTEGER_CST)
+    {
+      enum tree_code low_code, high_code;
+      tree low, high;
+      if (is_masked_range_test (name, val, comp_code, &name, &low,
+                               &low_code, &high, &high_code))
+       {
+         if (low_code != ERROR_MARK)
+           register_edge_assert_for_2 (name, e, low_code, name,
+                                       low, /*invert*/false, asserts);
+         if (high_code != ERROR_MARK)
+           register_edge_assert_for_2 (name, e, high_code, name,
+                                       high, /*invert*/false, asserts);
+       }
+    }
 }
 
 /* Finish found ASSERTS for E and register them at GSI.  */