diff mbox

[RFA,PR,tree-optimization/79095,3/4] Improve ASSERT_EXPRs and simplification of overflow tests V2

Message ID 8446b785-aa35-ebd9-9351-2be5cc9c39e3@redhat.com
State New
Headers show

Commit Message

Jeff Law Feb. 7, 2017, 6:32 p.m. UTC
This patch addresses issues Richi raised from V1.  Specifically the 
users of overflow_comparison_1 don't need to worry about trying both the 
original comparison and the reversed comparison.  This slightly 
simplifies the callers.

Bootstrapped and regression tested as part of the full patch series.

OK for the trunk?

Jeff
* tree-vrp.c (register_edge_assert_for_2): Register additional asserts
	if NAME is used in an overflow test.
	(vrp_evaluate_conditional_warnv_with_ops): If the ops represent an
	overflow check that can be expressed as an equality test, then adjust
	ops to be that equality test.

Comments

Richard Biener Feb. 14, 2017, 1:36 p.m. UTC | #1
On Tue, Feb 7, 2017 at 7:32 PM, Jeff Law <law@redhat.com> wrote:
> This patch addresses issues Richi raised from V1.  Specifically the users of
> overflow_comparison_1 don't need to worry about trying both the original
> comparison and the reversed comparison.  This slightly simplifies the
> callers.
>
> Bootstrapped and regression tested as part of the full patch series.
>
> OK for the trunk?

Ok.

Richard.

> Jeff
>
>         * tree-vrp.c (register_edge_assert_for_2): Register additional
> asserts
>         if NAME is used in an overflow test.
>         (vrp_evaluate_conditional_warnv_with_ops): If the ops represent an
>         overflow check that can be expressed as an equality test, then
> adjust
>         ops to be that equality test.
>
> diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
> index 2c03a74..21c459c 100644
> --- a/gcc/tree-vrp.c
> +++ b/gcc/tree-vrp.c
> @@ -5319,7 +5319,17 @@ register_edge_assert_for_2 (tree name, edge e,
> gimple_stmt_iterator bsi,
>    /* Only register an ASSERT_EXPR if NAME was found in the sub-graph
>       reachable from E.  */
>    if (live_on_edge (e, name))
> -    register_new_assert_for (name, name, comp_code, val, NULL, e, bsi);
> +    {
> +      tree x;
> +      if (overflow_comparison_p (comp_code, name, val, false, &x))
> +       {
> +         enum tree_code new_code
> +           = ((comp_code == GT_EXPR || comp_code == GE_EXPR)
> +              ? GT_EXPR : LE_EXPR);
> +         register_new_assert_for (name, name, new_code, x, NULL, e, bsi);
> +       }
> +      register_new_assert_for (name, name, comp_code, val, NULL, e, bsi);
> +    }
>
>    /* In the case of NAME <= CST and NAME being defined as
>       NAME = (unsigned) NAME2 + CST2 we can assert NAME2 >= -CST2
> @@ -7678,6 +7688,39 @@ vrp_evaluate_conditional_warnv_with_ops (enum
> tree_code code, tree op0,
>        && !POINTER_TYPE_P (TREE_TYPE (op0)))
>      return NULL_TREE;
>
> +  /* If OP0 CODE OP1 is an overflow comparison, if it can be expressed
> +     as a simple equality test, then prefer that over its current form
> +     for evaluation.
> +
> +     An overflow test which collapses to an equality test can always be
> +     expressed as a comparison of one argument against zero.  Overflow
> +     occurs when the chosen argument is zero and does not occur if the
> +     chosen argument is not zero.  */
> +  tree x;
> +  if (overflow_comparison_p (code, op0, op1, use_equiv_p, &x))
> +    {
> +      wide_int max = wi::max_value (TYPE_PRECISION (TREE_TYPE (op0)),
> UNSIGNED);
> +      /* B = A - 1; if (A < B) -> B = A - 1; if (A == 0)
> +         B = A - 1; if (A > B) -> B = A - 1; if (A != 0)
> +         B = A + 1; if (B < A) -> B = A + 1; if (B == 0)
> +         B = A + 1; if (B > A) -> B = A + 1; if (B != 0) */
> +      if (integer_zerop (x))
> +       {
> +         op1 = x;
> +         code = (code == LT_EXPR || code == LE_EXPR) ? EQ_EXPR : NE_EXPR;
> +       }
> +      /* B = A + 1; if (A > B) -> B = A + 1; if (B == 0)
> +         B = A + 1; if (A < B) -> B = A + 1; if (B != 0)
> +         B = A - 1; if (B > A) -> B = A - 1; if (A == 0)
> +         B = A - 1; if (B < A) -> B = A - 1; if (A != 0) */
> +      else if (wi::eq_p (x, max - 1))
> +       {
> +         op0 = op1;
> +         op1 = wide_int_to_tree (TREE_TYPE (op0), 0);
> +         code = (code == GT_EXPR || code == GE_EXPR) ? EQ_EXPR : NE_EXPR;
> +       }
> +    }
> +
>    if ((ret = vrp_evaluate_conditional_warnv_with_ops_using_ranges
>                (code, op0, op1, strict_overflow_p)))
>      return ret;
>
diff mbox

Patch

diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 2c03a74..21c459c 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -5319,7 +5319,17 @@  register_edge_assert_for_2 (tree name, edge e, gimple_stmt_iterator bsi,
   /* Only register an ASSERT_EXPR if NAME was found in the sub-graph
      reachable from E.  */
   if (live_on_edge (e, name))
-    register_new_assert_for (name, name, comp_code, val, NULL, e, bsi);
+    {
+      tree x;
+      if (overflow_comparison_p (comp_code, name, val, false, &x))
+	{
+	  enum tree_code new_code
+	    = ((comp_code == GT_EXPR || comp_code == GE_EXPR)
+	       ? GT_EXPR : LE_EXPR);
+	  register_new_assert_for (name, name, new_code, x, NULL, e, bsi);
+	}
+      register_new_assert_for (name, name, comp_code, val, NULL, e, bsi);
+    }
 
   /* In the case of NAME <= CST and NAME being defined as
      NAME = (unsigned) NAME2 + CST2 we can assert NAME2 >= -CST2
@@ -7678,6 +7688,39 @@  vrp_evaluate_conditional_warnv_with_ops (enum tree_code code, tree op0,
       && !POINTER_TYPE_P (TREE_TYPE (op0)))
     return NULL_TREE;
 
+  /* If OP0 CODE OP1 is an overflow comparison, if it can be expressed
+     as a simple equality test, then prefer that over its current form
+     for evaluation.
+
+     An overflow test which collapses to an equality test can always be
+     expressed as a comparison of one argument against zero.  Overflow
+     occurs when the chosen argument is zero and does not occur if the
+     chosen argument is not zero.  */
+  tree x;
+  if (overflow_comparison_p (code, op0, op1, use_equiv_p, &x))
+    {
+      wide_int max = wi::max_value (TYPE_PRECISION (TREE_TYPE (op0)), UNSIGNED);
+      /* B = A - 1; if (A < B) -> B = A - 1; if (A == 0)
+         B = A - 1; if (A > B) -> B = A - 1; if (A != 0)
+         B = A + 1; if (B < A) -> B = A + 1; if (B == 0)
+         B = A + 1; if (B > A) -> B = A + 1; if (B != 0) */
+      if (integer_zerop (x))
+	{
+	  op1 = x;
+	  code = (code == LT_EXPR || code == LE_EXPR) ? EQ_EXPR : NE_EXPR;
+	}
+      /* B = A + 1; if (A > B) -> B = A + 1; if (B == 0)
+         B = A + 1; if (A < B) -> B = A + 1; if (B != 0)
+         B = A - 1; if (B > A) -> B = A - 1; if (A == 0)
+         B = A - 1; if (B < A) -> B = A - 1; if (A != 0) */
+      else if (wi::eq_p (x, max - 1))
+	{
+	  op0 = op1;
+	  op1 = wide_int_to_tree (TREE_TYPE (op0), 0);
+	  code = (code == GT_EXPR || code == GE_EXPR) ? EQ_EXPR : NE_EXPR;
+	}
+    }
+
   if ((ret = vrp_evaluate_conditional_warnv_with_ops_using_ranges
 	       (code, op0, op1, strict_overflow_p)))
     return ret;