diff mbox

[RFA,PR,tree-optimization/79095,2/4] Add infrastructure to detect overflow checks V2

Message ID 607e9df8-6814-683b-02b5-b69eb5c521ed@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 it 
relieves the callers from having to try op0 COND op1 and op1 COND' op0 
separately and adds some additional comments about motivation.  There 
may have been minor nits Richi pointed out, if so, they were addressed 
as well.

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

OK for the trunk?

Jeff
* tree-vrp.c (overflow_comparison_p_1): New function.
	(overflow_comparison_p): New function.

Comments

Richard Biener Feb. 14, 2017, 1:35 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 it relieves
> the callers from having to try op0 COND op1 and op1 COND' op0 separately and
> adds some additional comments about motivation.  There may have been minor
> nits Richi pointed out, if so, they were addressed as well.
>
> Bootstrapped and regression tested as part of the full patch series.
>
> OK for the trunk?

Ok.

Richard.

> Jeff
>
>
>         * tree-vrp.c (overflow_comparison_p_1): New function.
>         (overflow_comparison_p): New function.
>
> diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
> index ad8173c..2c03a74 100644
> --- a/gcc/tree-vrp.c
> +++ b/gcc/tree-vrp.c
> @@ -5186,6 +5186,118 @@ masked_increment (const wide_int &val_in, const
> wide_int &mask,
>    return val ^ sgnbit;
>  }
>
> +/* Helper for overflow_comparison_p
> +
> +   OP0 CODE OP1 is a comparison.  Examine the comparison and potentially
> +   OP1's defining statement to see if it ultimately has the form
> +   OP0 CODE (OP0 PLUS INTEGER_CST)
> +
> +   If so, return TRUE indicating this is an overflow test and store into
> +   *NEW_CST an updated constant that can be used in a narrowed range test.
> +
> +   REVERSED indicates if the comparison was originally:
> +
> +   OP1 CODE' OP0.
> +
> +   This affects how we build the updated constant.  */
> +
> +static bool
> +overflow_comparison_p_1 (enum tree_code code, tree op0, tree op1,
> +                        bool follow_assert_exprs, bool reversed, tree
> *new_cst)
> +{
> +  /* See if this is a relational operation between two SSA_NAMES with
> +     unsigned, overflow wrapping values.  If so, check it more deeply.  */
> +  if ((code == LT_EXPR || code == LE_EXPR
> +       || code == GE_EXPR || code == GT_EXPR)
> +      && TREE_CODE (op0) == SSA_NAME
> +      && TREE_CODE (op1) == SSA_NAME
> +      && INTEGRAL_TYPE_P (TREE_TYPE (op0))
> +      && TYPE_UNSIGNED (TREE_TYPE (op0))
> +      && TYPE_OVERFLOW_WRAPS (TREE_TYPE (op0)))
> +    {
> +      gimple *op1_def = SSA_NAME_DEF_STMT (op1);
> +
> +      /* If requested, follow any ASSERT_EXPRs backwards for OP1.  */
> +      if (follow_assert_exprs)
> +       {
> +         while (gimple_assign_single_p (op1_def)
> +                && TREE_CODE (gimple_assign_rhs1 (op1_def)) == ASSERT_EXPR)
> +           {
> +             op1 = TREE_OPERAND (gimple_assign_rhs1 (op1_def), 0);
> +             if (TREE_CODE (op1) != SSA_NAME)
> +               break;
> +             op1_def = SSA_NAME_DEF_STMT (op1);
> +           }
> +       }
> +
> +      /* Now look at the defining statement of OP1 to see if it adds
> +        or subtracts a nonzero constant from another operand.  */
> +      if (op1_def
> +         && is_gimple_assign (op1_def)
> +         && gimple_assign_rhs_code (op1_def) == PLUS_EXPR
> +         && TREE_CODE (gimple_assign_rhs2 (op1_def)) == INTEGER_CST
> +         && !integer_zerop (gimple_assign_rhs2 (op1_def)))
> +       {
> +         tree target = gimple_assign_rhs1 (op1_def);
> +
> +         /* If requested, follow ASSERT_EXPRs backwards for op0 looking
> +            for one where TARGET appears on the RHS.  */
> +         if (follow_assert_exprs)
> +           {
> +             /* Now see if that "other operand" is op0, following the chain
> +                of ASSERT_EXPRs if necessary.  */
> +             gimple *op0_def = SSA_NAME_DEF_STMT (op0);
> +             while (op0 != target
> +                    && gimple_assign_single_p (op0_def)
> +                    && TREE_CODE (gimple_assign_rhs1 (op0_def)) ==
> ASSERT_EXPR)
> +               {
> +                 op0 = TREE_OPERAND (gimple_assign_rhs1 (op0_def), 0);
> +                 if (TREE_CODE (op0) != SSA_NAME)
> +                   break;
> +                 op0_def = SSA_NAME_DEF_STMT (op0);
> +               }
> +           }
> +
> +         /* If we did not find our target SSA_NAME, then this is not
> +            an overflow test.  */
> +         if (op0 != target)
> +           return false;
> +
> +         tree type = TREE_TYPE (op0);
> +         wide_int max = wi::max_value (TYPE_PRECISION (type), UNSIGNED);
> +         tree inc = gimple_assign_rhs2 (op1_def);
> +         if (reversed)
> +           *new_cst = wide_int_to_tree (type, max + inc);
> +         else
> +           *new_cst = wide_int_to_tree (type, max - inc);
> +         return true;
> +       }
> +    }
> +  return false;
> +}
> +
> +/* OP0 CODE OP1 is a comparison.  Examine the comparison and potentially
> +   OP1's defining statement to see if it ultimately has the form
> +   OP0 CODE (OP0 PLUS INTEGER_CST)
> +
> +   If so, return TRUE indicating this is an overflow test and store into
> +   *NEW_CST an updated constant that can be used in a narrowed range test.
> +
> +   These statements are left as-is in the IL to facilitate discovery of
> +   {ADD,SUB}_OVERFLOW sequences later in the optimizer pipeline.  But
> +   the alternate range representation is often useful within VRP.  */
> +
> +static bool
> +overflow_comparison_p (tree_code code, tree name, tree val,
> +                      bool use_equiv_p, tree *new_cst)
> +{
> +  if (overflow_comparison_p_1 (code, name, val, use_equiv_p, false,
> new_cst))
> +    return true;
> +  return overflow_comparison_p_1 (swap_tree_comparison (code), val, name,
> +                                 use_equiv_p, true, new_cst);
> +}
> +
> +
>  /* 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
> BSI.
>     Invert the condition COND if INVERT is true.  */
>
diff mbox

Patch

diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index ad8173c..2c03a74 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -5186,6 +5186,118 @@  masked_increment (const wide_int &val_in, const wide_int &mask,
   return val ^ sgnbit;
 }
 
+/* Helper for overflow_comparison_p
+
+   OP0 CODE OP1 is a comparison.  Examine the comparison and potentially
+   OP1's defining statement to see if it ultimately has the form
+   OP0 CODE (OP0 PLUS INTEGER_CST)
+
+   If so, return TRUE indicating this is an overflow test and store into
+   *NEW_CST an updated constant that can be used in a narrowed range test.
+
+   REVERSED indicates if the comparison was originally:
+
+   OP1 CODE' OP0.
+
+   This affects how we build the updated constant.  */
+
+static bool
+overflow_comparison_p_1 (enum tree_code code, tree op0, tree op1,
+		         bool follow_assert_exprs, bool reversed, tree *new_cst)
+{
+  /* See if this is a relational operation between two SSA_NAMES with
+     unsigned, overflow wrapping values.  If so, check it more deeply.  */
+  if ((code == LT_EXPR || code == LE_EXPR
+       || code == GE_EXPR || code == GT_EXPR)
+      && TREE_CODE (op0) == SSA_NAME
+      && TREE_CODE (op1) == SSA_NAME
+      && INTEGRAL_TYPE_P (TREE_TYPE (op0))
+      && TYPE_UNSIGNED (TREE_TYPE (op0))
+      && TYPE_OVERFLOW_WRAPS (TREE_TYPE (op0)))
+    {
+      gimple *op1_def = SSA_NAME_DEF_STMT (op1);
+
+      /* If requested, follow any ASSERT_EXPRs backwards for OP1.  */
+      if (follow_assert_exprs)
+	{
+	  while (gimple_assign_single_p (op1_def)
+		 && TREE_CODE (gimple_assign_rhs1 (op1_def)) == ASSERT_EXPR)
+	    {
+	      op1 = TREE_OPERAND (gimple_assign_rhs1 (op1_def), 0);
+	      if (TREE_CODE (op1) != SSA_NAME)
+		break;
+	      op1_def = SSA_NAME_DEF_STMT (op1);
+	    }
+	}
+
+      /* Now look at the defining statement of OP1 to see if it adds
+	 or subtracts a nonzero constant from another operand.  */
+      if (op1_def
+	  && is_gimple_assign (op1_def)
+	  && gimple_assign_rhs_code (op1_def) == PLUS_EXPR
+	  && TREE_CODE (gimple_assign_rhs2 (op1_def)) == INTEGER_CST
+	  && !integer_zerop (gimple_assign_rhs2 (op1_def)))
+	{
+	  tree target = gimple_assign_rhs1 (op1_def);
+
+	  /* If requested, follow ASSERT_EXPRs backwards for op0 looking
+	     for one where TARGET appears on the RHS.  */
+	  if (follow_assert_exprs)
+	    {
+	      /* Now see if that "other operand" is op0, following the chain
+		 of ASSERT_EXPRs if necessary.  */
+	      gimple *op0_def = SSA_NAME_DEF_STMT (op0);
+	      while (op0 != target
+		     && gimple_assign_single_p (op0_def)
+		     && TREE_CODE (gimple_assign_rhs1 (op0_def)) == ASSERT_EXPR)
+		{
+		  op0 = TREE_OPERAND (gimple_assign_rhs1 (op0_def), 0);
+		  if (TREE_CODE (op0) != SSA_NAME)
+		    break;
+		  op0_def = SSA_NAME_DEF_STMT (op0);
+		}
+	    }
+
+	  /* If we did not find our target SSA_NAME, then this is not
+	     an overflow test.  */
+	  if (op0 != target)
+	    return false;
+
+	  tree type = TREE_TYPE (op0);
+	  wide_int max = wi::max_value (TYPE_PRECISION (type), UNSIGNED);
+	  tree inc = gimple_assign_rhs2 (op1_def);
+	  if (reversed)
+	    *new_cst = wide_int_to_tree (type, max + inc);
+	  else
+	    *new_cst = wide_int_to_tree (type, max - inc);
+	  return true;
+	}
+    }
+  return false;
+}
+
+/* OP0 CODE OP1 is a comparison.  Examine the comparison and potentially
+   OP1's defining statement to see if it ultimately has the form
+   OP0 CODE (OP0 PLUS INTEGER_CST)
+
+   If so, return TRUE indicating this is an overflow test and store into
+   *NEW_CST an updated constant that can be used in a narrowed range test.
+
+   These statements are left as-is in the IL to facilitate discovery of
+   {ADD,SUB}_OVERFLOW sequences later in the optimizer pipeline.  But
+   the alternate range representation is often useful within VRP.  */
+
+static bool
+overflow_comparison_p (tree_code code, tree name, tree val,
+		       bool use_equiv_p, tree *new_cst)
+{
+  if (overflow_comparison_p_1 (code, name, val, use_equiv_p, false, new_cst))
+    return true;
+  return overflow_comparison_p_1 (swap_tree_comparison (code), val, name,
+				  use_equiv_p, true, new_cst);
+}
+
+
 /* 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 BSI.
    Invert the condition COND if INVERT is true.  */