diff mbox

Generalize gimple_val_nonnegative_real_p

Message ID 87y4fdacx5.fsf@e105548-lin.cambridge.arm.com
State New
Headers show

Commit Message

Richard Sandiford Oct. 8, 2015, 10:10 a.m. UTC
Richard Biener <richard.guenther@gmail.com> writes:
> On Mon, Oct 5, 2015 at 5:02 PM, Richard Sandiford
> <richard.sandiford@arm.com> wrote:
>> The upcoming patch to move sqrt and cbrt simplifications to match.pd
>> caused a regression because the (abs @0)->@0 simplification didn't
>> trigger for:
>>
>>     (abs (convert (abs X)))
>>
>> The simplification is based on tree_expr_nonnegative_p, which is
>> pretty weak for gimple (it gives up if it sees an SSA_NAME).
>>
>> We have the stronger gimple_val_nonnegative_real_p, but (a) as its
>> name implies, it's specific to reals and (b) in its current form it
>> doesn't handle converts.  This patch:
>>
>> - generalises the routine all types
>> - reuses tree_{unary,binary,call}_nonnegative_warnv_p for the leaf cases
>> - makes the routine handle CONVERT_EXPR
>> - allows a nesting depth of 1 for CONVERT_EXPR
>> - uses the routine instead of tree_expr_nonnegative_p for gimple.
>>
>> Limiting the depth to 1 is a little arbitrary but adding a param seemed
>> over the top.
>>
>> Bootstrapped & regression-tested on x86_64-linux-gnu.  I didn't write
>> a specific test because this is already covered by the testsuite if
>> the follow-on patch is also applied.  OK to install?
>
> Hmm.  I don't like having essentially two copies of the same machinery.
> Can you instead fold gimple_val_nonnegative_real_p into a
> tree_ssa_name_nonnegative_warnv_p used by tree_expr_nonnegative_warnv_p?
> For integers it's also possible to look at SSA name range info.
> You'd still limit recursion appropriately (by passing down a depth arg
> everywhere,
> defaulted to 0 I guess).

OK.  I wanted to combine the functions originally but, with
gimple_val_nonnegative_real_p being an obvious partial cut-&-paste
of fold-const.c, I assumed things were the way they were because
having a single routine would be breaking some abstraction barrier.

This patch moves the vrp code for querying gimple statements to
gimple-fold.c, adds a function to fold-const.c for querying SSA names,
and adds a depth parameter to both sets of functions.  As discussed
on IRC, it has the downside that gimple-fold.c calls fold-const.c
and fold-const.c calls gimple-fold.c.

Also as discussed on IRC, a knock-on effect is that we can now prove
_i_589 < 0 is false in sequences like:

      i_1917 = ASSERT_EXPR <i_1075, i_1075 == 0>;
      _i_589 = (const int) i_1917;
      _i_1507 = ASSERT_EXPR <_i_589, _i_589 < 0>;

This defeats an assert in tree-vrp.c that ASSERT_EXPR conditions
are never known to be false.  Previously the assert only ever used
local knowledge and so would be limited to cases like x != x for
integer x.  Now that we use global knowledge it's possible to prove
the assertion condition is false in blocks that are in practice
unreachable.  I've removed the assert in the patch below.

(FWIW the first hit was during stage2 of a bootstrap, in cfgcleanup.c)

> Note that the comment in gimple_val_nonnegative_real_p is correct in
> that we really shouldn't recurse (but maybe handle fixed patterns -
> like you do here) as the appropriate way is to have a "nonnegative"
> lattice.  SSA name range info may already provide enough info here
> (well, not for reals - time to add basic real range support to VRP!).

I retained a form of this comment in tree_ssa_name_nonnegative_warnv_p.

Bootstrapped & regression-tested on x86_64-linux-gnu.  I didn't write
a specific test because this is already covered by the testsuite if
the follow-on patch is also applied.  OK to install?

Thanks,
Richard


gcc/
	* params.def (PARAM_MAX_SSA_NAME_QUERY_DEPTH): New param.
	* doc/invoke.texi (--param max-ssa-name-query-depth): Document.
	* fold-const.h (tree_unary_nonnegative_warnv_p)
	(tree_single_nonnegative_warnv_p, tree_call_nonnegative_warnv_p)
	(tree_expr_nonnegative_warnv_p): Add depth parameters.
	* fold-const.c: Include gimple-fold.h and params.h.
	(tree_ssa_name_nonnegative_warnv_p): New function.
	(tree_unary_nonnegative_warnv_p, tree_binary_nonnegative_warnv_p)
	(tree_single_nonnegative_warnv_p, tree_call_nonnegative_warnv_p)
	(tree_invalid_nonnegative_warnv_p, tree_expr_nonnegative_warnv_p):
	Add a depth parameter and increment it for recursive calls to
	tree_expr_nonnegative_warnv_p.  Use tree_ssa_name_nonnegative_warnv_p
	to handle SSA names.
	* gimple-fold.h (gimple_val_nonnegative_real_p): Delete.
	(gimple_stmt_nonnegative_warnv_p): Declare.
	* tree-vrp.c (remove_range_assertions): Remove assert that condition
	cannot be proven false.
	(gimple_assign_nonnegative_warnv_p, gimple_call_nonnegative_warnv_p)
	(gimple_stmt_nonnegative_warnv_p): Move to...
	* gimple-fold.c: ...here.  Add depth parameters and pass them
	down to the tree routines.  Accept statements that aren't
	assignments or calls but just return false for them.
	(gimple_val_nonnegative_real_p): Delete.
	* tree-ssa-math-opts.c (gimple_expand_builtin_pow): Use
	tree_expr_nonnegative_p instead of gimple_val_nonnegative_real_p.
	Check HONOR_NANs first.

Comments

Richard Biener Oct. 8, 2015, 1:42 p.m. UTC | #1
On Thu, Oct 8, 2015 at 12:10 PM, Richard Sandiford
<richard.sandiford@arm.com> wrote:
> Richard Biener <richard.guenther@gmail.com> writes:
>> On Mon, Oct 5, 2015 at 5:02 PM, Richard Sandiford
>> <richard.sandiford@arm.com> wrote:
>>> The upcoming patch to move sqrt and cbrt simplifications to match.pd
>>> caused a regression because the (abs @0)->@0 simplification didn't
>>> trigger for:
>>>
>>>     (abs (convert (abs X)))
>>>
>>> The simplification is based on tree_expr_nonnegative_p, which is
>>> pretty weak for gimple (it gives up if it sees an SSA_NAME).
>>>
>>> We have the stronger gimple_val_nonnegative_real_p, but (a) as its
>>> name implies, it's specific to reals and (b) in its current form it
>>> doesn't handle converts.  This patch:
>>>
>>> - generalises the routine all types
>>> - reuses tree_{unary,binary,call}_nonnegative_warnv_p for the leaf cases
>>> - makes the routine handle CONVERT_EXPR
>>> - allows a nesting depth of 1 for CONVERT_EXPR
>>> - uses the routine instead of tree_expr_nonnegative_p for gimple.
>>>
>>> Limiting the depth to 1 is a little arbitrary but adding a param seemed
>>> over the top.
>>>
>>> Bootstrapped & regression-tested on x86_64-linux-gnu.  I didn't write
>>> a specific test because this is already covered by the testsuite if
>>> the follow-on patch is also applied.  OK to install?
>>
>> Hmm.  I don't like having essentially two copies of the same machinery.
>> Can you instead fold gimple_val_nonnegative_real_p into a
>> tree_ssa_name_nonnegative_warnv_p used by tree_expr_nonnegative_warnv_p?
>> For integers it's also possible to look at SSA name range info.
>> You'd still limit recursion appropriately (by passing down a depth arg
>> everywhere,
>> defaulted to 0 I guess).
>
> OK.  I wanted to combine the functions originally but, with
> gimple_val_nonnegative_real_p being an obvious partial cut-&-paste
> of fold-const.c, I assumed things were the way they were because
> having a single routine would be breaking some abstraction barrier.
>
> This patch moves the vrp code for querying gimple statements to
> gimple-fold.c, adds a function to fold-const.c for querying SSA names,
> and adds a depth parameter to both sets of functions.  As discussed
> on IRC, it has the downside that gimple-fold.c calls fold-const.c
> and fold-const.c calls gimple-fold.c.
>
> Also as discussed on IRC, a knock-on effect is that we can now prove
> _i_589 < 0 is false in sequences like:
>
>       i_1917 = ASSERT_EXPR <i_1075, i_1075 == 0>;
>       _i_589 = (const int) i_1917;
>       _i_1507 = ASSERT_EXPR <_i_589, _i_589 < 0>;
>
> This defeats an assert in tree-vrp.c that ASSERT_EXPR conditions
> are never known to be false.  Previously the assert only ever used
> local knowledge and so would be limited to cases like x != x for
> integer x.  Now that we use global knowledge it's possible to prove
> the assertion condition is false in blocks that are in practice
> unreachable.  I've removed the assert in the patch below.
>
> (FWIW the first hit was during stage2 of a bootstrap, in cfgcleanup.c)
>
>> Note that the comment in gimple_val_nonnegative_real_p is correct in
>> that we really shouldn't recurse (but maybe handle fixed patterns -
>> like you do here) as the appropriate way is to have a "nonnegative"
>> lattice.  SSA name range info may already provide enough info here
>> (well, not for reals - time to add basic real range support to VRP!).
>
> I retained a form of this comment in tree_ssa_name_nonnegative_warnv_p.
>
> Bootstrapped & regression-tested on x86_64-linux-gnu.  I didn't write
> a specific test because this is already covered by the testsuite if
> the follow-on patch is also applied.  OK to install?

Ok.

Thanks,
Richard.

> Thanks,
> Richard
>
>
> gcc/
>         * params.def (PARAM_MAX_SSA_NAME_QUERY_DEPTH): New param.
>         * doc/invoke.texi (--param max-ssa-name-query-depth): Document.
>         * fold-const.h (tree_unary_nonnegative_warnv_p)
>         (tree_single_nonnegative_warnv_p, tree_call_nonnegative_warnv_p)
>         (tree_expr_nonnegative_warnv_p): Add depth parameters.
>         * fold-const.c: Include gimple-fold.h and params.h.
>         (tree_ssa_name_nonnegative_warnv_p): New function.
>         (tree_unary_nonnegative_warnv_p, tree_binary_nonnegative_warnv_p)
>         (tree_single_nonnegative_warnv_p, tree_call_nonnegative_warnv_p)
>         (tree_invalid_nonnegative_warnv_p, tree_expr_nonnegative_warnv_p):
>         Add a depth parameter and increment it for recursive calls to
>         tree_expr_nonnegative_warnv_p.  Use tree_ssa_name_nonnegative_warnv_p
>         to handle SSA names.
>         * gimple-fold.h (gimple_val_nonnegative_real_p): Delete.
>         (gimple_stmt_nonnegative_warnv_p): Declare.
>         * tree-vrp.c (remove_range_assertions): Remove assert that condition
>         cannot be proven false.
>         (gimple_assign_nonnegative_warnv_p, gimple_call_nonnegative_warnv_p)
>         (gimple_stmt_nonnegative_warnv_p): Move to...
>         * gimple-fold.c: ...here.  Add depth parameters and pass them
>         down to the tree routines.  Accept statements that aren't
>         assignments or calls but just return false for them.
>         (gimple_val_nonnegative_real_p): Delete.
>         * tree-ssa-math-opts.c (gimple_expand_builtin_pow): Use
>         tree_expr_nonnegative_p instead of gimple_val_nonnegative_real_p.
>         Check HONOR_NANs first.
>
> Index: gcc/params.def
> ===================================================================
> --- gcc/params.def      2015-10-05 20:45:49.164957708 +0100
> +++ gcc/params.def      2015-10-08 10:59:12.904576852 +0100
> @@ -1152,6 +1152,12 @@ DEFPARAM (PARAM_PARLOOPS_CHUNK_SIZE,
>           "parloops-chunk-size",
>           "Chunk size of omp schedule for loops parallelized by parloops",
>           0, 0, 0)
> +
> +DEFPARAM (PARAM_MAX_SSA_NAME_QUERY_DEPTH,
> +         "max-ssa-name-query-depth",
> +         "Maximum recursion depth allowed when querying a property of an"
> +         " SSA name",
> +         2, 1, 0)
>  /*
>
>  Local variables:
> Index: gcc/doc/invoke.texi
> ===================================================================
> --- gcc/doc/invoke.texi 2015-10-07 09:07:20.758346426 +0100
> +++ gcc/doc/invoke.texi 2015-10-08 10:59:12.904576852 +0100
> @@ -11132,6 +11132,10 @@ automaton.  The default is 50.
>  Chunk size of omp schedule for loops parallelized by parloops.  The default
>  is 0.
>
> +@item max-ssa-name-query-depth
> +Maximum depth of recursion when querying properties of SSA names in things
> +like fold routines.  One level of recursion corresponds to following a
> +use-def chain.
>  @end table
>  @end table
>
> Index: gcc/fold-const.h
> ===================================================================
> --- gcc/fold-const.h    2015-09-25 12:49:13.080824131 +0100
> +++ gcc/fold-const.h    2015-10-08 10:59:12.904576852 +0100
> @@ -132,11 +132,13 @@ extern bool tree_unary_nonzero_warnv_p (
>  extern bool tree_binary_nonzero_warnv_p (enum tree_code, tree, tree, tree op1,
>                                           bool *);
>  extern bool tree_single_nonzero_warnv_p (tree, bool *);
> -extern bool tree_unary_nonnegative_warnv_p (enum tree_code, tree, tree, bool *);
> +extern bool tree_unary_nonnegative_warnv_p (enum tree_code, tree, tree,
> +                                           bool *, int);
>  extern bool tree_binary_nonnegative_warnv_p (enum tree_code, tree, tree, tree,
> -                                             bool *);
> -extern bool tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p);
> -extern bool tree_call_nonnegative_warnv_p (tree, tree, tree, tree, bool *);
> +                                            bool *, int);
> +extern bool tree_single_nonnegative_warnv_p (tree, bool *, int);
> +extern bool tree_call_nonnegative_warnv_p (tree, tree, tree, tree, bool *,
> +                                          int);
>
>  extern bool fold_real_zero_addition_p (const_tree, const_tree, int);
>  extern tree combine_comparisons (location_t, enum tree_code, enum tree_code,
> @@ -160,7 +162,7 @@ #define non_lvalue(T) non_lvalue_loc (UN
>  extern tree non_lvalue_loc (location_t, tree);
>
>  extern bool tree_expr_nonnegative_p (tree);
> -extern bool tree_expr_nonnegative_warnv_p (tree, bool *);
> +extern bool tree_expr_nonnegative_warnv_p (tree, bool *, int = 0);
>  extern tree make_range (tree, int *, tree *, tree *, bool *);
>  extern tree make_range_step (location_t, enum tree_code, tree, tree, tree,
>                              tree *, tree *, int *, bool *);
> Index: gcc/fold-const.c
> ===================================================================
> --- gcc/fold-const.c    2015-10-05 12:31:58.565944573 +0100
> +++ gcc/fold-const.c    2015-10-08 10:59:12.904576852 +0100
> @@ -77,6 +77,8 @@ Software Foundation; either version 3, o
>  #include "cgraph.h"
>  #include "generic-match.h"
>  #include "optabs-query.h"
> +#include "gimple-fold.h"
> +#include "params.h"
>
>  #ifndef LOAD_EXTEND_OP
>  #define LOAD_EXTEND_OP(M) UNKNOWN
> @@ -12749,6 +12751,12 @@ multiple_of_p (tree type, const_tree top
>      }
>  }
>
> +#define tree_expr_nonnegative_warnv_p(X, Y) \
> +  _Pragma ("GCC error \"Use RECURSE for recursive calls\"") 0
> +
> +#define RECURSE(X) \
> +  ((tree_expr_nonnegative_warnv_p) (X, strict_overflow_p, depth + 1))
> +
>  /* Return true if CODE or TYPE is known to be non-negative. */
>
>  static bool
> @@ -12765,11 +12773,11 @@ tree_simple_nonnegative_warnv_p (enum tr
>  /* Return true if (CODE OP0) is known to be non-negative.  If the return
>     value is based on the assumption that signed overflow is undefined,
>     set *STRICT_OVERFLOW_P to true; otherwise, don't change
> -   *STRICT_OVERFLOW_P.  */
> +   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
>
>  bool
>  tree_unary_nonnegative_warnv_p (enum tree_code code, tree type, tree op0,
> -                               bool *strict_overflow_p)
> +                               bool *strict_overflow_p, int depth)
>  {
>    if (TYPE_UNSIGNED (type))
>      return true;
> @@ -12791,8 +12799,7 @@ tree_unary_nonnegative_warnv_p (enum tre
>      case NON_LVALUE_EXPR:
>      case FLOAT_EXPR:
>      case FIX_TRUNC_EXPR:
> -      return tree_expr_nonnegative_warnv_p (op0,
> -                                           strict_overflow_p);
> +      return RECURSE (op0);
>
>      CASE_CONVERT:
>        {
> @@ -12802,21 +12809,18 @@ tree_unary_nonnegative_warnv_p (enum tre
>         if (TREE_CODE (outer_type) == REAL_TYPE)
>           {
>             if (TREE_CODE (inner_type) == REAL_TYPE)
> -             return tree_expr_nonnegative_warnv_p (op0,
> -                                                   strict_overflow_p);
> +             return RECURSE (op0);
>             if (INTEGRAL_TYPE_P (inner_type))
>               {
>                 if (TYPE_UNSIGNED (inner_type))
>                   return true;
> -               return tree_expr_nonnegative_warnv_p (op0,
> -                                                     strict_overflow_p);
> +               return RECURSE (op0);
>               }
>           }
>         else if (INTEGRAL_TYPE_P (outer_type))
>           {
>             if (TREE_CODE (inner_type) == REAL_TYPE)
> -             return tree_expr_nonnegative_warnv_p (op0,
> -                                                   strict_overflow_p);
> +             return RECURSE (op0);
>             if (INTEGRAL_TYPE_P (inner_type))
>               return TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type)
>                       && TYPE_UNSIGNED (inner_type);
> @@ -12835,11 +12839,12 @@ tree_unary_nonnegative_warnv_p (enum tre
>  /* Return true if (CODE OP0 OP1) is known to be non-negative.  If the return
>     value is based on the assumption that signed overflow is undefined,
>     set *STRICT_OVERFLOW_P to true; otherwise, don't change
> -   *STRICT_OVERFLOW_P.  */
> +   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
>
>  bool
>  tree_binary_nonnegative_warnv_p (enum tree_code code, tree type, tree op0,
> -                                     tree op1, bool *strict_overflow_p)
> +                                tree op1, bool *strict_overflow_p,
> +                                int depth)
>  {
>    if (TYPE_UNSIGNED (type))
>      return true;
> @@ -12849,10 +12854,7 @@ tree_binary_nonnegative_warnv_p (enum tr
>      case POINTER_PLUS_EXPR:
>      case PLUS_EXPR:
>        if (FLOAT_TYPE_P (type))
> -       return (tree_expr_nonnegative_warnv_p (op0,
> -                                              strict_overflow_p)
> -               && tree_expr_nonnegative_warnv_p (op1,
> -                                                 strict_overflow_p));
> +       return RECURSE (op0) && RECURSE (op1);
>
>        /* zero_extend(x) + zero_extend(y) is non-negative if x and y are
>          both unsigned and at least 2 bits shorter than the result.  */
> @@ -12878,8 +12880,7 @@ tree_binary_nonnegative_warnv_p (enum tr
>           /* x * x is always non-negative for floating point x
>              or without overflow.  */
>           if (operand_equal_p (op0, op1, 0)
> -             || (tree_expr_nonnegative_warnv_p (op0, strict_overflow_p)
> -                 && tree_expr_nonnegative_warnv_p (op1, strict_overflow_p)))
> +             || (RECURSE (op0) && RECURSE (op1)))
>             {
>               if (ANY_INTEGRAL_TYPE_P (type)
>                   && TYPE_OVERFLOW_UNDEFINED (type))
> @@ -12928,10 +12929,7 @@ tree_binary_nonnegative_warnv_p (enum tr
>
>      case BIT_AND_EXPR:
>      case MAX_EXPR:
> -      return (tree_expr_nonnegative_warnv_p (op0,
> -                                            strict_overflow_p)
> -             || tree_expr_nonnegative_warnv_p (op1,
> -                                               strict_overflow_p));
> +      return RECURSE (op0) || RECURSE (op1);
>
>      case BIT_IOR_EXPR:
>      case BIT_XOR_EXPR:
> @@ -12941,17 +12939,14 @@ tree_binary_nonnegative_warnv_p (enum tr
>      case CEIL_DIV_EXPR:
>      case FLOOR_DIV_EXPR:
>      case ROUND_DIV_EXPR:
> -      return (tree_expr_nonnegative_warnv_p (op0,
> -                                            strict_overflow_p)
> -             && tree_expr_nonnegative_warnv_p (op1,
> -                                               strict_overflow_p));
> +      return RECURSE (op0) && RECURSE (op1);
>
>      case TRUNC_MOD_EXPR:
>      case CEIL_MOD_EXPR:
>      case FLOOR_MOD_EXPR:
>      case ROUND_MOD_EXPR:
> -      return tree_expr_nonnegative_warnv_p (op0,
> -                                           strict_overflow_p);
> +      return RECURSE (op0);
> +
>      default:
>        return tree_simple_nonnegative_warnv_p (code, type);
>      }
> @@ -12960,13 +12955,32 @@ tree_binary_nonnegative_warnv_p (enum tr
>    return false;
>  }
>
> +/* Return true if SSA name T is known to be non-negative.  If the return
> +   value is based on the assumption that signed overflow is undefined,
> +   set *STRICT_OVERFLOW_P to true; otherwise, don't change
> +   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
> +
> +static bool
> +tree_ssa_name_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth)
> +{
> +  /* Limit the depth of recursion to avoid quadratic behavior.
> +     This is expected to catch almost all occurrences in practice.
> +     If this code misses important cases that unbounded recursion
> +     would not, passes that need this information could be revised
> +     to provide it through dataflow propagation.  */
> +  if (depth < PARAM_VALUE (PARAM_MAX_SSA_NAME_QUERY_DEPTH))
> +    return gimple_stmt_nonnegative_warnv_p (SSA_NAME_DEF_STMT (t),
> +                                           strict_overflow_p, depth);
> +  return tree_simple_nonnegative_warnv_p (TREE_CODE (t), TREE_TYPE (t));
> +}
> +
>  /* Return true if T is known to be non-negative.  If the return
>     value is based on the assumption that signed overflow is undefined,
>     set *STRICT_OVERFLOW_P to true; otherwise, don't change
> -   *STRICT_OVERFLOW_P.  */
> +   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
>
>  bool
> -tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
> +tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth)
>  {
>    if (TYPE_UNSIGNED (TREE_TYPE (t)))
>      return true;
> @@ -12983,26 +12997,24 @@ tree_single_nonnegative_warnv_p (tree t,
>        return ! FIXED_VALUE_NEGATIVE (TREE_FIXED_CST (t));
>
>      case COND_EXPR:
> -      return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
> -                                            strict_overflow_p)
> -             && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 2),
> -                                               strict_overflow_p));
> +      return RECURSE (TREE_OPERAND (t, 1)) && RECURSE (TREE_OPERAND (t, 2));
> +
> +    case SSA_NAME:
> +      return tree_ssa_name_nonnegative_warnv_p (t, strict_overflow_p, depth);
> +
>      default:
> -      return tree_simple_nonnegative_warnv_p (TREE_CODE (t),
> -                                                  TREE_TYPE (t));
> +      return tree_simple_nonnegative_warnv_p (TREE_CODE (t), TREE_TYPE (t));
>      }
> -  /* We don't know sign of `t', so be conservative and return false.  */
> -  return false;
>  }
>
>  /* Return true if T is known to be non-negative.  If the return
>     value is based on the assumption that signed overflow is undefined,
>     set *STRICT_OVERFLOW_P to true; otherwise, don't change
> -   *STRICT_OVERFLOW_P.  */
> +   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
>
>  bool
> -tree_call_nonnegative_warnv_p (tree type, tree fndecl,
> -                              tree arg0, tree arg1, bool *strict_overflow_p)
> +tree_call_nonnegative_warnv_p (tree type, tree fndecl, tree arg0, tree arg1,
> +                              bool *strict_overflow_p, int depth)
>  {
>    if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
>      switch (DECL_FUNCTION_CODE (fndecl))
> @@ -13033,8 +13045,7 @@ tree_call_nonnegative_warnv_p (tree type
>         /* sqrt(-0.0) is -0.0.  */
>         if (!HONOR_SIGNED_ZEROS (element_mode (type)))
>           return true;
> -       return tree_expr_nonnegative_warnv_p (arg0,
> -                                             strict_overflow_p);
> +       return RECURSE (arg0);
>
>         CASE_FLT_FN (BUILT_IN_ASINH):
>         CASE_FLT_FN (BUILT_IN_ATAN):
> @@ -13072,27 +13083,19 @@ tree_call_nonnegative_warnv_p (tree type
>         CASE_FLT_FN (BUILT_IN_TANH):
>         CASE_FLT_FN (BUILT_IN_TRUNC):
>         /* True if the 1st argument is nonnegative.  */
> -       return tree_expr_nonnegative_warnv_p (arg0,
> -                                             strict_overflow_p);
> +       return RECURSE (arg0);
>
>         CASE_FLT_FN (BUILT_IN_FMAX):
>         /* True if the 1st OR 2nd arguments are nonnegative.  */
> -       return (tree_expr_nonnegative_warnv_p (arg0,
> -                                              strict_overflow_p)
> -               || (tree_expr_nonnegative_warnv_p (arg1,
> -                                                  strict_overflow_p)));
> +       return RECURSE (arg0) || RECURSE (arg1);
>
>         CASE_FLT_FN (BUILT_IN_FMIN):
>         /* True if the 1st AND 2nd arguments are nonnegative.  */
> -       return (tree_expr_nonnegative_warnv_p (arg0,
> -                                              strict_overflow_p)
> -               && (tree_expr_nonnegative_warnv_p (arg1,
> -                                                  strict_overflow_p)));
> +       return RECURSE (arg0) && RECURSE (arg1);
>
>         CASE_FLT_FN (BUILT_IN_COPYSIGN):
>         /* True if the 2nd argument is nonnegative.  */
> -       return tree_expr_nonnegative_warnv_p (arg1,
> -                                             strict_overflow_p);
> +       return RECURSE (arg1);
>
>         CASE_FLT_FN (BUILT_IN_POWI):
>         /* True if the 1st argument is nonnegative or the second
> @@ -13100,8 +13103,7 @@ tree_call_nonnegative_warnv_p (tree type
>         if (TREE_CODE (arg1) == INTEGER_CST
>             && (TREE_INT_CST_LOW (arg1) & 1) == 0)
>           return true;
> -       return tree_expr_nonnegative_warnv_p (arg0,
> -                                             strict_overflow_p);
> +       return RECURSE (arg0);
>
>         CASE_FLT_FN (BUILT_IN_POW):
>         /* True if the 1st argument is nonnegative or the second
> @@ -13121,23 +13123,21 @@ tree_call_nonnegative_warnv_p (tree type
>                   return true;
>               }
>           }
> -       return tree_expr_nonnegative_warnv_p (arg0,
> -                                             strict_overflow_p);
> +       return RECURSE (arg0);
>
>        default:
>         break;
>        }
> -  return tree_simple_nonnegative_warnv_p (CALL_EXPR,
> -                                         type);
> +  return tree_simple_nonnegative_warnv_p (CALL_EXPR, type);
>  }
>
>  /* Return true if T is known to be non-negative.  If the return
>     value is based on the assumption that signed overflow is undefined,
>     set *STRICT_OVERFLOW_P to true; otherwise, don't change
> -   *STRICT_OVERFLOW_P.  */
> +   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
>
>  static bool
> -tree_invalid_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
> +tree_invalid_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth)
>  {
>    enum tree_code code = TREE_CODE (t);
>    if (TYPE_UNSIGNED (TREE_TYPE (t)))
> @@ -13153,7 +13153,7 @@ tree_invalid_nonnegative_warnv_p (tree t
>         /* If the initializer is non-void, then it's a normal expression
>            that will be assigned to the slot.  */
>         if (!VOID_TYPE_P (t))
> -         return tree_expr_nonnegative_warnv_p (t, strict_overflow_p);
> +         return RECURSE (t);
>
>         /* Otherwise, the initializer sets the slot in some way.  One common
>            way is an assignment statement at the end of the initializer.  */
> @@ -13171,8 +13171,7 @@ tree_invalid_nonnegative_warnv_p (tree t
>           }
>         if (TREE_CODE (t) == MODIFY_EXPR
>             && TREE_OPERAND (t, 0) == temp)
> -         return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
> -                                               strict_overflow_p);
> +         return RECURSE (TREE_OPERAND (t, 1));
>
>         return false;
>        }
> @@ -13186,35 +13185,33 @@ tree_invalid_nonnegative_warnv_p (tree t
>                                               get_callee_fndecl (t),
>                                               arg0,
>                                               arg1,
> -                                             strict_overflow_p);
> +                                             strict_overflow_p, depth);
>        }
>      case COMPOUND_EXPR:
>      case MODIFY_EXPR:
> -      return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
> -                                           strict_overflow_p);
> +      return RECURSE (TREE_OPERAND (t, 1));
> +
>      case BIND_EXPR:
> -      return tree_expr_nonnegative_warnv_p (expr_last (TREE_OPERAND (t, 1)),
> -                                           strict_overflow_p);
> +      return RECURSE (expr_last (TREE_OPERAND (t, 1)));
> +
>      case SAVE_EXPR:
> -      return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
> -                                           strict_overflow_p);
> +      return RECURSE (TREE_OPERAND (t, 0));
>
>      default:
> -      return tree_simple_nonnegative_warnv_p (TREE_CODE (t),
> -                                                  TREE_TYPE (t));
> +      return tree_simple_nonnegative_warnv_p (TREE_CODE (t), TREE_TYPE (t));
>      }
> -
> -  /* We don't know sign of `t', so be conservative and return false.  */
> -  return false;
>  }
>
> +#undef RECURSE
> +#undef tree_expr_nonnegative_warnv_p
> +
>  /* Return true if T is known to be non-negative.  If the return
>     value is based on the assumption that signed overflow is undefined,
>     set *STRICT_OVERFLOW_P to true; otherwise, don't change
> -   *STRICT_OVERFLOW_P.  */
> +   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
>
>  bool
> -tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
> +tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth)
>  {
>    enum tree_code code;
>    if (t == error_mark_node)
> @@ -13229,18 +13226,18 @@ tree_expr_nonnegative_warnv_p (tree t, b
>                                               TREE_TYPE (t),
>                                               TREE_OPERAND (t, 0),
>                                               TREE_OPERAND (t, 1),
> -                                             strict_overflow_p);
> +                                             strict_overflow_p, depth);
>
>      case tcc_unary:
>        return tree_unary_nonnegative_warnv_p (TREE_CODE (t),
>                                              TREE_TYPE (t),
>                                              TREE_OPERAND (t, 0),
> -                                            strict_overflow_p);
> +                                            strict_overflow_p, depth);
>
>      case tcc_constant:
>      case tcc_declaration:
>      case tcc_reference:
> -      return tree_single_nonnegative_warnv_p (t, strict_overflow_p);
> +      return tree_single_nonnegative_warnv_p (t, strict_overflow_p, depth);
>
>      default:
>        break;
> @@ -13255,12 +13252,12 @@ tree_expr_nonnegative_warnv_p (tree t, b
>                                               TREE_TYPE (t),
>                                               TREE_OPERAND (t, 0),
>                                               TREE_OPERAND (t, 1),
> -                                             strict_overflow_p);
> +                                             strict_overflow_p, depth);
>      case TRUTH_NOT_EXPR:
>        return tree_unary_nonnegative_warnv_p (TREE_CODE (t),
>                                              TREE_TYPE (t),
>                                              TREE_OPERAND (t, 0),
> -                                            strict_overflow_p);
> +                                            strict_overflow_p, depth);
>
>      case COND_EXPR:
>      case CONSTRUCTOR:
> @@ -13269,10 +13266,10 @@ tree_expr_nonnegative_warnv_p (tree t, b
>      case ADDR_EXPR:
>      case WITH_SIZE_EXPR:
>      case SSA_NAME:
> -      return tree_single_nonnegative_warnv_p (t, strict_overflow_p);
> +      return tree_single_nonnegative_warnv_p (t, strict_overflow_p, depth);
>
>      default:
> -      return tree_invalid_nonnegative_warnv_p (t, strict_overflow_p);
> +      return tree_invalid_nonnegative_warnv_p (t, strict_overflow_p, depth);
>      }
>  }
>
> Index: gcc/gimple-fold.h
> ===================================================================
> --- gcc/gimple-fold.h   2015-09-25 12:49:13.928814656 +0100
> +++ gcc/gimple-fold.h   2015-10-08 10:59:12.904576852 +0100
> @@ -48,7 +48,6 @@ extern tree gimple_get_virt_method_for_b
>  extern tree gimple_get_virt_method_for_vtable (HOST_WIDE_INT, tree,
>                                                unsigned HOST_WIDE_INT,
>                                                bool *can_refer = NULL);
> -extern bool gimple_val_nonnegative_real_p (tree);
>  extern tree gimple_fold_indirect_ref (tree);
>  extern bool arith_code_with_undefined_signed_overflow (tree_code);
>  extern gimple_seq rewrite_to_defined_overflow (gimple *);
> @@ -113,6 +112,8 @@ gimple_convert (gimple_seq *seq, tree ty
>    return gimple_convert (seq, UNKNOWN_LOCATION, type, op);
>  }
>
> +extern bool gimple_stmt_nonnegative_warnv_p (gimple *, bool *, int = 0);
> +
>  /* In gimple-match.c.  */
>  extern tree gimple_simplify (enum tree_code, tree, tree,
>                              gimple_seq *, tree (*)(tree));
> Index: gcc/tree-vrp.c
> ===================================================================
> --- gcc/tree-vrp.c      2015-10-05 20:45:48.964959975 +0100
> +++ gcc/tree-vrp.c      2015-10-08 10:59:12.908576806 +0100
> @@ -1007,80 +1007,6 @@ usable_range_p (value_range *vr, bool *s
>    return true;
>  }
>
> -
> -/* Return true if the result of assignment STMT is know to be non-negative.
> -   If the return value is based on the assumption that signed overflow is
> -   undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
> -   *STRICT_OVERFLOW_P.*/
> -
> -static bool
> -gimple_assign_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p)
> -{
> -  enum tree_code code = gimple_assign_rhs_code (stmt);
> -  switch (get_gimple_rhs_class (code))
> -    {
> -    case GIMPLE_UNARY_RHS:
> -      return tree_unary_nonnegative_warnv_p (gimple_assign_rhs_code (stmt),
> -                                            gimple_expr_type (stmt),
> -                                            gimple_assign_rhs1 (stmt),
> -                                            strict_overflow_p);
> -    case GIMPLE_BINARY_RHS:
> -      return tree_binary_nonnegative_warnv_p (gimple_assign_rhs_code (stmt),
> -                                             gimple_expr_type (stmt),
> -                                             gimple_assign_rhs1 (stmt),
> -                                             gimple_assign_rhs2 (stmt),
> -                                             strict_overflow_p);
> -    case GIMPLE_TERNARY_RHS:
> -      return false;
> -    case GIMPLE_SINGLE_RHS:
> -      return tree_single_nonnegative_warnv_p (gimple_assign_rhs1 (stmt),
> -                                             strict_overflow_p);
> -    case GIMPLE_INVALID_RHS:
> -      gcc_unreachable ();
> -    default:
> -      gcc_unreachable ();
> -    }
> -}
> -
> -/* Return true if return value of call STMT is know to be non-negative.
> -   If the return value is based on the assumption that signed overflow is
> -   undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
> -   *STRICT_OVERFLOW_P.*/
> -
> -static bool
> -gimple_call_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p)
> -{
> -  tree arg0 = gimple_call_num_args (stmt) > 0 ?
> -    gimple_call_arg (stmt, 0) : NULL_TREE;
> -  tree arg1 = gimple_call_num_args (stmt) > 1 ?
> -    gimple_call_arg (stmt, 1) : NULL_TREE;
> -
> -  return tree_call_nonnegative_warnv_p (gimple_expr_type (stmt),
> -                                       gimple_call_fndecl (stmt),
> -                                       arg0,
> -                                       arg1,
> -                                       strict_overflow_p);
> -}
> -
> -/* Return true if STMT is know to compute a non-negative value.
> -   If the return value is based on the assumption that signed overflow is
> -   undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
> -   *STRICT_OVERFLOW_P.*/
> -
> -static bool
> -gimple_stmt_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p)
> -{
> -  switch (gimple_code (stmt))
> -    {
> -    case GIMPLE_ASSIGN:
> -      return gimple_assign_nonnegative_warnv_p (stmt, strict_overflow_p);
> -    case GIMPLE_CALL:
> -      return gimple_call_nonnegative_warnv_p (stmt, strict_overflow_p);
> -    default:
> -      gcc_unreachable ();
> -    }
> -}
> -
>  /* Return true if the result of assignment STMT is know to be non-zero.
>     If the return value is based on the assumption that signed overflow is
>     undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
> @@ -6858,12 +6784,9 @@ remove_range_assertions (void)
>             tree lhs = gimple_assign_lhs (stmt);
>             tree rhs = gimple_assign_rhs1 (stmt);
>             tree var;
> -           tree cond = fold (ASSERT_EXPR_COND (rhs));
>             use_operand_p use_p;
>             imm_use_iterator iter;
>
> -           gcc_assert (cond != boolean_false_node);
> -
>             var = ASSERT_EXPR_VAR (rhs);
>             gcc_assert (TREE_CODE (var) == SSA_NAME);
>
> Index: gcc/gimple-fold.c
> ===================================================================
> --- gcc/gimple-fold.c   2015-10-07 09:07:21.198341367 +0100
> +++ gcc/gimple-fold.c   2015-10-08 10:59:12.904576852 +0100
> @@ -5773,137 +5773,6 @@ gimple_get_virt_method_for_binfo (HOST_W
>    return gimple_get_virt_method_for_vtable (token, v, offset, can_refer);
>  }
>
> -/* Return true iff VAL is a gimple expression that is known to be
> -   non-negative.  Restricted to floating-point inputs.  */
> -
> -bool
> -gimple_val_nonnegative_real_p (tree val)
> -{
> -  gimple *def_stmt;
> -
> -  gcc_assert (val && SCALAR_FLOAT_TYPE_P (TREE_TYPE (val)));
> -
> -  /* Use existing logic for non-gimple trees.  */
> -  if (tree_expr_nonnegative_p (val))
> -    return true;
> -
> -  if (TREE_CODE (val) != SSA_NAME)
> -    return false;
> -
> -  /* Currently we look only at the immediately defining statement
> -     to make this determination, since recursion on defining
> -     statements of operands can lead to quadratic behavior in the
> -     worst case.  This is expected to catch almost all occurrences
> -     in practice.  It would be possible to implement limited-depth
> -     recursion if important cases are lost.  Alternatively, passes
> -     that need this information (such as the pow/powi lowering code
> -     in the cse_sincos pass) could be revised to provide it through
> -     dataflow propagation.  */
> -
> -  def_stmt = SSA_NAME_DEF_STMT (val);
> -
> -  if (is_gimple_assign (def_stmt))
> -    {
> -      tree op0, op1;
> -
> -      /* See fold-const.c:tree_expr_nonnegative_p for additional
> -        cases that could be handled with recursion.  */
> -
> -      switch (gimple_assign_rhs_code (def_stmt))
> -       {
> -       case ABS_EXPR:
> -         /* Always true for floating-point operands.  */
> -         return true;
> -
> -       case MULT_EXPR:
> -         /* True if the two operands are identical (since we are
> -            restricted to floating-point inputs).  */
> -         op0 = gimple_assign_rhs1 (def_stmt);
> -         op1 = gimple_assign_rhs2 (def_stmt);
> -
> -         if (op0 == op1
> -             || operand_equal_p (op0, op1, 0))
> -           return true;
> -
> -       default:
> -         return false;
> -       }
> -    }
> -  else if (is_gimple_call (def_stmt))
> -    {
> -      tree fndecl = gimple_call_fndecl (def_stmt);
> -      if (fndecl
> -         && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
> -       {
> -         tree arg1;
> -
> -         switch (DECL_FUNCTION_CODE (fndecl))
> -           {
> -           CASE_FLT_FN (BUILT_IN_ACOS):
> -           CASE_FLT_FN (BUILT_IN_ACOSH):
> -           CASE_FLT_FN (BUILT_IN_CABS):
> -           CASE_FLT_FN (BUILT_IN_COSH):
> -           CASE_FLT_FN (BUILT_IN_ERFC):
> -           CASE_FLT_FN (BUILT_IN_EXP):
> -           CASE_FLT_FN (BUILT_IN_EXP10):
> -           CASE_FLT_FN (BUILT_IN_EXP2):
> -           CASE_FLT_FN (BUILT_IN_FABS):
> -           CASE_FLT_FN (BUILT_IN_FDIM):
> -           CASE_FLT_FN (BUILT_IN_HYPOT):
> -           CASE_FLT_FN (BUILT_IN_POW10):
> -             return true;
> -
> -           CASE_FLT_FN (BUILT_IN_SQRT):
> -             /* sqrt(-0.0) is -0.0, and sqrt is not defined over other
> -                nonnegative inputs.  */
> -             if (!HONOR_SIGNED_ZEROS (val))
> -               return true;
> -
> -             break;
> -
> -           CASE_FLT_FN (BUILT_IN_POWI):
> -             /* True if the second argument is an even integer.  */
> -             arg1 = gimple_call_arg (def_stmt, 1);
> -
> -             if (TREE_CODE (arg1) == INTEGER_CST
> -                 && (TREE_INT_CST_LOW (arg1) & 1) == 0)
> -               return true;
> -
> -             break;
> -
> -           CASE_FLT_FN (BUILT_IN_POW):
> -             /* True if the second argument is an even integer-valued
> -                real.  */
> -             arg1 = gimple_call_arg (def_stmt, 1);
> -
> -             if (TREE_CODE (arg1) == REAL_CST)
> -               {
> -                 REAL_VALUE_TYPE c;
> -                 HOST_WIDE_INT n;
> -
> -                 c = TREE_REAL_CST (arg1);
> -                 n = real_to_integer (&c);
> -
> -                 if ((n & 1) == 0)
> -                   {
> -                     REAL_VALUE_TYPE cint;
> -                     real_from_integer (&cint, VOIDmode, n, SIGNED);
> -                     if (real_identical (&c, &cint))
> -                       return true;
> -                   }
> -               }
> -
> -             break;
> -
> -           default:
> -             return false;
> -           }
> -       }
> -    }
> -
> -  return false;
> -}
> -
>  /* Given a pointer value OP0, return a simplified version of an
>     indirection through OP0, or NULL_TREE if no simplification is
>     possible.  Note that the resulting type may be different from
> @@ -6280,3 +6149,80 @@ gimple_convert (gimple_seq *seq, locatio
>      return op;
>    return gimple_build (seq, loc, NOP_EXPR, type, op);
>  }
> +
> +/* Return true if the result of assignment STMT is known to be non-negative.
> +   If the return value is based on the assumption that signed overflow is
> +   undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
> +   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
> +
> +static bool
> +gimple_assign_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p,
> +                                  int depth)
> +{
> +  enum tree_code code = gimple_assign_rhs_code (stmt);
> +  switch (get_gimple_rhs_class (code))
> +    {
> +    case GIMPLE_UNARY_RHS:
> +      return tree_unary_nonnegative_warnv_p (gimple_assign_rhs_code (stmt),
> +                                            gimple_expr_type (stmt),
> +                                            gimple_assign_rhs1 (stmt),
> +                                            strict_overflow_p, depth);
> +    case GIMPLE_BINARY_RHS:
> +      return tree_binary_nonnegative_warnv_p (gimple_assign_rhs_code (stmt),
> +                                             gimple_expr_type (stmt),
> +                                             gimple_assign_rhs1 (stmt),
> +                                             gimple_assign_rhs2 (stmt),
> +                                             strict_overflow_p, depth);
> +    case GIMPLE_TERNARY_RHS:
> +      return false;
> +    case GIMPLE_SINGLE_RHS:
> +      return tree_single_nonnegative_warnv_p (gimple_assign_rhs1 (stmt),
> +                                             strict_overflow_p, depth);
> +    case GIMPLE_INVALID_RHS:
> +      break;
> +    }
> +  gcc_unreachable ();
> +}
> +
> +/* Return true if return value of call STMT is known to be non-negative.
> +   If the return value is based on the assumption that signed overflow is
> +   undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
> +   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
> +
> +static bool
> +gimple_call_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p,
> +                                int depth)
> +{
> +  tree arg0 = gimple_call_num_args (stmt) > 0 ?
> +    gimple_call_arg (stmt, 0) : NULL_TREE;
> +  tree arg1 = gimple_call_num_args (stmt) > 1 ?
> +    gimple_call_arg (stmt, 1) : NULL_TREE;
> +
> +  return tree_call_nonnegative_warnv_p (gimple_expr_type (stmt),
> +                                       gimple_call_fndecl (stmt),
> +                                       arg0,
> +                                       arg1,
> +                                       strict_overflow_p, depth);
> +}
> +
> +/* Return true if STMT is known to compute a non-negative value.
> +   If the return value is based on the assumption that signed overflow is
> +   undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
> +   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
> +
> +bool
> +gimple_stmt_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p,
> +                                int depth)
> +{
> +  switch (gimple_code (stmt))
> +    {
> +    case GIMPLE_ASSIGN:
> +      return gimple_assign_nonnegative_warnv_p (stmt, strict_overflow_p,
> +                                               depth);
> +    case GIMPLE_CALL:
> +      return gimple_call_nonnegative_warnv_p (stmt, strict_overflow_p,
> +                                             depth);
> +    default:
> +      return false;
> +    }
> +}
> Index: gcc/tree-ssa-math-opts.c
> ===================================================================
> --- gcc/tree-ssa-math-opts.c    2015-10-05 12:34:55.923949581 +0100
> +++ gcc/tree-ssa-math-opts.c    2015-10-08 10:59:12.908576806 +0100
> @@ -1526,7 +1526,7 @@ gimple_expand_builtin_pow (gimple_stmt_i
>
>    if (flag_unsafe_math_optimizations
>        && cbrtfn
> -      && (gimple_val_nonnegative_real_p (arg0) || !HONOR_NANS (mode))
> +      && (!HONOR_NANS (mode) || tree_expr_nonnegative_p (arg0))
>        && real_equal (&c, &dconst1_3))
>      return build_and_insert_call (gsi, loc, cbrtfn, arg0);
>
> @@ -1538,7 +1538,7 @@ gimple_expand_builtin_pow (gimple_stmt_i
>    if (flag_unsafe_math_optimizations
>        && sqrtfn
>        && cbrtfn
> -      && (gimple_val_nonnegative_real_p (arg0) || !HONOR_NANS (mode))
> +      && (!HONOR_NANS (mode) || tree_expr_nonnegative_p (arg0))
>        && speed_p
>        && hw_sqrt_exists
>        && real_equal (&c, &dconst1_6))
> @@ -1594,7 +1594,7 @@ gimple_expand_builtin_pow (gimple_stmt_i
>
>    if (flag_unsafe_math_optimizations
>        && cbrtfn
> -      && (gimple_val_nonnegative_real_p (arg0) || !HONOR_NANS (mode))
> +      && (!HONOR_NANS (mode) || tree_expr_nonnegative_p (arg0))
>        && real_identical (&c2, &c)
>        && !c2_is_int
>        && optimize_function_for_speed_p (cfun)
>
diff mbox

Patch

Index: gcc/params.def
===================================================================
--- gcc/params.def	2015-10-05 20:45:49.164957708 +0100
+++ gcc/params.def	2015-10-08 10:59:12.904576852 +0100
@@ -1152,6 +1152,12 @@  DEFPARAM (PARAM_PARLOOPS_CHUNK_SIZE,
 	  "parloops-chunk-size",
 	  "Chunk size of omp schedule for loops parallelized by parloops",
 	  0, 0, 0)
+
+DEFPARAM (PARAM_MAX_SSA_NAME_QUERY_DEPTH,
+	  "max-ssa-name-query-depth",
+	  "Maximum recursion depth allowed when querying a property of an"
+	  " SSA name",
+	  2, 1, 0)
 /*
 
 Local variables:
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	2015-10-07 09:07:20.758346426 +0100
+++ gcc/doc/invoke.texi	2015-10-08 10:59:12.904576852 +0100
@@ -11132,6 +11132,10 @@  automaton.  The default is 50.
 Chunk size of omp schedule for loops parallelized by parloops.  The default
 is 0.
 
+@item max-ssa-name-query-depth
+Maximum depth of recursion when querying properties of SSA names in things
+like fold routines.  One level of recursion corresponds to following a
+use-def chain.
 @end table
 @end table
 
Index: gcc/fold-const.h
===================================================================
--- gcc/fold-const.h	2015-09-25 12:49:13.080824131 +0100
+++ gcc/fold-const.h	2015-10-08 10:59:12.904576852 +0100
@@ -132,11 +132,13 @@  extern bool tree_unary_nonzero_warnv_p (
 extern bool tree_binary_nonzero_warnv_p (enum tree_code, tree, tree, tree op1,
                                          bool *);
 extern bool tree_single_nonzero_warnv_p (tree, bool *);
-extern bool tree_unary_nonnegative_warnv_p (enum tree_code, tree, tree, bool *);
+extern bool tree_unary_nonnegative_warnv_p (enum tree_code, tree, tree,
+					    bool *, int);
 extern bool tree_binary_nonnegative_warnv_p (enum tree_code, tree, tree, tree,
-                                             bool *);
-extern bool tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p);
-extern bool tree_call_nonnegative_warnv_p (tree, tree, tree, tree, bool *);
+					     bool *, int);
+extern bool tree_single_nonnegative_warnv_p (tree, bool *, int);
+extern bool tree_call_nonnegative_warnv_p (tree, tree, tree, tree, bool *,
+					   int);
 
 extern bool fold_real_zero_addition_p (const_tree, const_tree, int);
 extern tree combine_comparisons (location_t, enum tree_code, enum tree_code,
@@ -160,7 +162,7 @@  #define non_lvalue(T) non_lvalue_loc (UN
 extern tree non_lvalue_loc (location_t, tree);
 
 extern bool tree_expr_nonnegative_p (tree);
-extern bool tree_expr_nonnegative_warnv_p (tree, bool *);
+extern bool tree_expr_nonnegative_warnv_p (tree, bool *, int = 0);
 extern tree make_range (tree, int *, tree *, tree *, bool *);
 extern tree make_range_step (location_t, enum tree_code, tree, tree, tree,
 			     tree *, tree *, int *, bool *);
Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c	2015-10-05 12:31:58.565944573 +0100
+++ gcc/fold-const.c	2015-10-08 10:59:12.904576852 +0100
@@ -77,6 +77,8 @@  Software Foundation; either version 3, o
 #include "cgraph.h"
 #include "generic-match.h"
 #include "optabs-query.h"
+#include "gimple-fold.h"
+#include "params.h"
 
 #ifndef LOAD_EXTEND_OP
 #define LOAD_EXTEND_OP(M) UNKNOWN
@@ -12749,6 +12751,12 @@  multiple_of_p (tree type, const_tree top
     }
 }
 
+#define tree_expr_nonnegative_warnv_p(X, Y) \
+  _Pragma ("GCC error \"Use RECURSE for recursive calls\"") 0
+
+#define RECURSE(X) \
+  ((tree_expr_nonnegative_warnv_p) (X, strict_overflow_p, depth + 1))
+
 /* Return true if CODE or TYPE is known to be non-negative. */
 
 static bool
@@ -12765,11 +12773,11 @@  tree_simple_nonnegative_warnv_p (enum tr
 /* Return true if (CODE OP0) is known to be non-negative.  If the return
    value is based on the assumption that signed overflow is undefined,
    set *STRICT_OVERFLOW_P to true; otherwise, don't change
-   *STRICT_OVERFLOW_P.  */
+   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
 
 bool
 tree_unary_nonnegative_warnv_p (enum tree_code code, tree type, tree op0,
-				bool *strict_overflow_p)
+				bool *strict_overflow_p, int depth)
 {
   if (TYPE_UNSIGNED (type))
     return true;
@@ -12791,8 +12799,7 @@  tree_unary_nonnegative_warnv_p (enum tre
     case NON_LVALUE_EXPR:
     case FLOAT_EXPR:
     case FIX_TRUNC_EXPR:
-      return tree_expr_nonnegative_warnv_p (op0,
-					    strict_overflow_p);
+      return RECURSE (op0);
 
     CASE_CONVERT:
       {
@@ -12802,21 +12809,18 @@  tree_unary_nonnegative_warnv_p (enum tre
 	if (TREE_CODE (outer_type) == REAL_TYPE)
 	  {
 	    if (TREE_CODE (inner_type) == REAL_TYPE)
-	      return tree_expr_nonnegative_warnv_p (op0,
-						    strict_overflow_p);
+	      return RECURSE (op0);
 	    if (INTEGRAL_TYPE_P (inner_type))
 	      {
 		if (TYPE_UNSIGNED (inner_type))
 		  return true;
-		return tree_expr_nonnegative_warnv_p (op0,
-						      strict_overflow_p);
+		return RECURSE (op0);
 	      }
 	  }
 	else if (INTEGRAL_TYPE_P (outer_type))
 	  {
 	    if (TREE_CODE (inner_type) == REAL_TYPE)
-	      return tree_expr_nonnegative_warnv_p (op0,
-						    strict_overflow_p);
+	      return RECURSE (op0);
 	    if (INTEGRAL_TYPE_P (inner_type))
 	      return TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type)
 		      && TYPE_UNSIGNED (inner_type);
@@ -12835,11 +12839,12 @@  tree_unary_nonnegative_warnv_p (enum tre
 /* Return true if (CODE OP0 OP1) is known to be non-negative.  If the return
    value is based on the assumption that signed overflow is undefined,
    set *STRICT_OVERFLOW_P to true; otherwise, don't change
-   *STRICT_OVERFLOW_P.  */
+   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
 
 bool
 tree_binary_nonnegative_warnv_p (enum tree_code code, tree type, tree op0,
-				      tree op1, bool *strict_overflow_p)
+				 tree op1, bool *strict_overflow_p,
+				 int depth)
 {
   if (TYPE_UNSIGNED (type))
     return true;
@@ -12849,10 +12854,7 @@  tree_binary_nonnegative_warnv_p (enum tr
     case POINTER_PLUS_EXPR:
     case PLUS_EXPR:
       if (FLOAT_TYPE_P (type))
-	return (tree_expr_nonnegative_warnv_p (op0,
-					       strict_overflow_p)
-		&& tree_expr_nonnegative_warnv_p (op1,
-						  strict_overflow_p));
+	return RECURSE (op0) && RECURSE (op1);
 
       /* zero_extend(x) + zero_extend(y) is non-negative if x and y are
 	 both unsigned and at least 2 bits shorter than the result.  */
@@ -12878,8 +12880,7 @@  tree_binary_nonnegative_warnv_p (enum tr
 	  /* x * x is always non-negative for floating point x
 	     or without overflow.  */
 	  if (operand_equal_p (op0, op1, 0)
-	      || (tree_expr_nonnegative_warnv_p (op0, strict_overflow_p)
-		  && tree_expr_nonnegative_warnv_p (op1, strict_overflow_p)))
+	      || (RECURSE (op0) && RECURSE (op1)))
 	    {
 	      if (ANY_INTEGRAL_TYPE_P (type)
 		  && TYPE_OVERFLOW_UNDEFINED (type))
@@ -12928,10 +12929,7 @@  tree_binary_nonnegative_warnv_p (enum tr
 
     case BIT_AND_EXPR:
     case MAX_EXPR:
-      return (tree_expr_nonnegative_warnv_p (op0,
-					     strict_overflow_p)
-	      || tree_expr_nonnegative_warnv_p (op1,
-						strict_overflow_p));
+      return RECURSE (op0) || RECURSE (op1);
 
     case BIT_IOR_EXPR:
     case BIT_XOR_EXPR:
@@ -12941,17 +12939,14 @@  tree_binary_nonnegative_warnv_p (enum tr
     case CEIL_DIV_EXPR:
     case FLOOR_DIV_EXPR:
     case ROUND_DIV_EXPR:
-      return (tree_expr_nonnegative_warnv_p (op0,
-					     strict_overflow_p)
-	      && tree_expr_nonnegative_warnv_p (op1,
-						strict_overflow_p));
+      return RECURSE (op0) && RECURSE (op1);
 
     case TRUNC_MOD_EXPR:
     case CEIL_MOD_EXPR:
     case FLOOR_MOD_EXPR:
     case ROUND_MOD_EXPR:
-      return tree_expr_nonnegative_warnv_p (op0,
-					    strict_overflow_p);
+      return RECURSE (op0);
+
     default:
       return tree_simple_nonnegative_warnv_p (code, type);
     }
@@ -12960,13 +12955,32 @@  tree_binary_nonnegative_warnv_p (enum tr
   return false;
 }
 
+/* Return true if SSA name T is known to be non-negative.  If the return
+   value is based on the assumption that signed overflow is undefined,
+   set *STRICT_OVERFLOW_P to true; otherwise, don't change
+   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
+
+static bool
+tree_ssa_name_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth)
+{
+  /* Limit the depth of recursion to avoid quadratic behavior.
+     This is expected to catch almost all occurrences in practice.
+     If this code misses important cases that unbounded recursion
+     would not, passes that need this information could be revised
+     to provide it through dataflow propagation.  */
+  if (depth < PARAM_VALUE (PARAM_MAX_SSA_NAME_QUERY_DEPTH))
+    return gimple_stmt_nonnegative_warnv_p (SSA_NAME_DEF_STMT (t),
+					    strict_overflow_p, depth);
+  return tree_simple_nonnegative_warnv_p (TREE_CODE (t), TREE_TYPE (t));
+}
+
 /* Return true if T is known to be non-negative.  If the return
    value is based on the assumption that signed overflow is undefined,
    set *STRICT_OVERFLOW_P to true; otherwise, don't change
-   *STRICT_OVERFLOW_P.  */
+   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
 
 bool
-tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
+tree_single_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth)
 {
   if (TYPE_UNSIGNED (TREE_TYPE (t)))
     return true;
@@ -12983,26 +12997,24 @@  tree_single_nonnegative_warnv_p (tree t,
       return ! FIXED_VALUE_NEGATIVE (TREE_FIXED_CST (t));
 
     case COND_EXPR:
-      return (tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
-					     strict_overflow_p)
-	      && tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 2),
-						strict_overflow_p));
+      return RECURSE (TREE_OPERAND (t, 1)) && RECURSE (TREE_OPERAND (t, 2));
+
+    case SSA_NAME:
+      return tree_ssa_name_nonnegative_warnv_p (t, strict_overflow_p, depth);
+
     default:
-      return tree_simple_nonnegative_warnv_p (TREE_CODE (t),
-						   TREE_TYPE (t));
+      return tree_simple_nonnegative_warnv_p (TREE_CODE (t), TREE_TYPE (t));
     }
-  /* We don't know sign of `t', so be conservative and return false.  */
-  return false;
 }
 
 /* Return true if T is known to be non-negative.  If the return
    value is based on the assumption that signed overflow is undefined,
    set *STRICT_OVERFLOW_P to true; otherwise, don't change
-   *STRICT_OVERFLOW_P.  */
+   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
 
 bool
-tree_call_nonnegative_warnv_p (tree type, tree fndecl,
-			       tree arg0, tree arg1, bool *strict_overflow_p)
+tree_call_nonnegative_warnv_p (tree type, tree fndecl, tree arg0, tree arg1,
+			       bool *strict_overflow_p, int depth)
 {
   if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
     switch (DECL_FUNCTION_CODE (fndecl))
@@ -13033,8 +13045,7 @@  tree_call_nonnegative_warnv_p (tree type
 	/* sqrt(-0.0) is -0.0.  */
 	if (!HONOR_SIGNED_ZEROS (element_mode (type)))
 	  return true;
-	return tree_expr_nonnegative_warnv_p (arg0,
-					      strict_overflow_p);
+	return RECURSE (arg0);
 
 	CASE_FLT_FN (BUILT_IN_ASINH):
 	CASE_FLT_FN (BUILT_IN_ATAN):
@@ -13072,27 +13083,19 @@  tree_call_nonnegative_warnv_p (tree type
 	CASE_FLT_FN (BUILT_IN_TANH):
 	CASE_FLT_FN (BUILT_IN_TRUNC):
 	/* True if the 1st argument is nonnegative.  */
-	return tree_expr_nonnegative_warnv_p (arg0,
-					      strict_overflow_p);
+	return RECURSE (arg0);
 
 	CASE_FLT_FN (BUILT_IN_FMAX):
 	/* True if the 1st OR 2nd arguments are nonnegative.  */
-	return (tree_expr_nonnegative_warnv_p (arg0,
-					       strict_overflow_p)
-		|| (tree_expr_nonnegative_warnv_p (arg1,
-						   strict_overflow_p)));
+	return RECURSE (arg0) || RECURSE (arg1);
 
 	CASE_FLT_FN (BUILT_IN_FMIN):
 	/* True if the 1st AND 2nd arguments are nonnegative.  */
-	return (tree_expr_nonnegative_warnv_p (arg0,
-					       strict_overflow_p)
-		&& (tree_expr_nonnegative_warnv_p (arg1,
-						   strict_overflow_p)));
+	return RECURSE (arg0) && RECURSE (arg1);
 
 	CASE_FLT_FN (BUILT_IN_COPYSIGN):
 	/* True if the 2nd argument is nonnegative.  */
-	return tree_expr_nonnegative_warnv_p (arg1,
-					      strict_overflow_p);
+	return RECURSE (arg1);
 
 	CASE_FLT_FN (BUILT_IN_POWI):
 	/* True if the 1st argument is nonnegative or the second
@@ -13100,8 +13103,7 @@  tree_call_nonnegative_warnv_p (tree type
 	if (TREE_CODE (arg1) == INTEGER_CST
 	    && (TREE_INT_CST_LOW (arg1) & 1) == 0)
 	  return true;
-	return tree_expr_nonnegative_warnv_p (arg0,
-					      strict_overflow_p);
+	return RECURSE (arg0);
 
 	CASE_FLT_FN (BUILT_IN_POW):
 	/* True if the 1st argument is nonnegative or the second
@@ -13121,23 +13123,21 @@  tree_call_nonnegative_warnv_p (tree type
 		  return true;
 	      }
 	  }
-	return tree_expr_nonnegative_warnv_p (arg0,
-					      strict_overflow_p);
+	return RECURSE (arg0);
 
       default:
 	break;
       }
-  return tree_simple_nonnegative_warnv_p (CALL_EXPR,
-					  type);
+  return tree_simple_nonnegative_warnv_p (CALL_EXPR, type);
 }
 
 /* Return true if T is known to be non-negative.  If the return
    value is based on the assumption that signed overflow is undefined,
    set *STRICT_OVERFLOW_P to true; otherwise, don't change
-   *STRICT_OVERFLOW_P.  */
+   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
 
 static bool
-tree_invalid_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
+tree_invalid_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth)
 {
   enum tree_code code = TREE_CODE (t);
   if (TYPE_UNSIGNED (TREE_TYPE (t)))
@@ -13153,7 +13153,7 @@  tree_invalid_nonnegative_warnv_p (tree t
 	/* If the initializer is non-void, then it's a normal expression
 	   that will be assigned to the slot.  */
 	if (!VOID_TYPE_P (t))
-	  return tree_expr_nonnegative_warnv_p (t, strict_overflow_p);
+	  return RECURSE (t);
 
 	/* Otherwise, the initializer sets the slot in some way.  One common
 	   way is an assignment statement at the end of the initializer.  */
@@ -13171,8 +13171,7 @@  tree_invalid_nonnegative_warnv_p (tree t
 	  }
 	if (TREE_CODE (t) == MODIFY_EXPR
 	    && TREE_OPERAND (t, 0) == temp)
-	  return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
-						strict_overflow_p);
+	  return RECURSE (TREE_OPERAND (t, 1));
 
 	return false;
       }
@@ -13186,35 +13185,33 @@  tree_invalid_nonnegative_warnv_p (tree t
 					      get_callee_fndecl (t),
 					      arg0,
 					      arg1,
-					      strict_overflow_p);
+					      strict_overflow_p, depth);
       }
     case COMPOUND_EXPR:
     case MODIFY_EXPR:
-      return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 1),
-					    strict_overflow_p);
+      return RECURSE (TREE_OPERAND (t, 1));
+
     case BIND_EXPR:
-      return tree_expr_nonnegative_warnv_p (expr_last (TREE_OPERAND (t, 1)),
-					    strict_overflow_p);
+      return RECURSE (expr_last (TREE_OPERAND (t, 1)));
+
     case SAVE_EXPR:
-      return tree_expr_nonnegative_warnv_p (TREE_OPERAND (t, 0),
-					    strict_overflow_p);
+      return RECURSE (TREE_OPERAND (t, 0));
 
     default:
-      return tree_simple_nonnegative_warnv_p (TREE_CODE (t),
-						   TREE_TYPE (t));
+      return tree_simple_nonnegative_warnv_p (TREE_CODE (t), TREE_TYPE (t));
     }
-
-  /* We don't know sign of `t', so be conservative and return false.  */
-  return false;
 }
 
+#undef RECURSE
+#undef tree_expr_nonnegative_warnv_p
+
 /* Return true if T is known to be non-negative.  If the return
    value is based on the assumption that signed overflow is undefined,
    set *STRICT_OVERFLOW_P to true; otherwise, don't change
-   *STRICT_OVERFLOW_P.  */
+   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
 
 bool
-tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p)
+tree_expr_nonnegative_warnv_p (tree t, bool *strict_overflow_p, int depth)
 {
   enum tree_code code;
   if (t == error_mark_node)
@@ -13229,18 +13226,18 @@  tree_expr_nonnegative_warnv_p (tree t, b
 					      TREE_TYPE (t),
 					      TREE_OPERAND (t, 0),
 					      TREE_OPERAND (t, 1),
-					      strict_overflow_p);
+					      strict_overflow_p, depth);
 
     case tcc_unary:
       return tree_unary_nonnegative_warnv_p (TREE_CODE (t),
 					     TREE_TYPE (t),
 					     TREE_OPERAND (t, 0),
-					     strict_overflow_p);
+					     strict_overflow_p, depth);
 
     case tcc_constant:
     case tcc_declaration:
     case tcc_reference:
-      return tree_single_nonnegative_warnv_p (t, strict_overflow_p);
+      return tree_single_nonnegative_warnv_p (t, strict_overflow_p, depth);
 
     default:
       break;
@@ -13255,12 +13252,12 @@  tree_expr_nonnegative_warnv_p (tree t, b
 					      TREE_TYPE (t),
 					      TREE_OPERAND (t, 0),
 					      TREE_OPERAND (t, 1),
-					      strict_overflow_p);
+					      strict_overflow_p, depth);
     case TRUTH_NOT_EXPR:
       return tree_unary_nonnegative_warnv_p (TREE_CODE (t),
 					     TREE_TYPE (t),
 					     TREE_OPERAND (t, 0),
-					     strict_overflow_p);
+					     strict_overflow_p, depth);
 
     case COND_EXPR:
     case CONSTRUCTOR:
@@ -13269,10 +13266,10 @@  tree_expr_nonnegative_warnv_p (tree t, b
     case ADDR_EXPR:
     case WITH_SIZE_EXPR:
     case SSA_NAME:
-      return tree_single_nonnegative_warnv_p (t, strict_overflow_p);
+      return tree_single_nonnegative_warnv_p (t, strict_overflow_p, depth);
 
     default:
-      return tree_invalid_nonnegative_warnv_p (t, strict_overflow_p);
+      return tree_invalid_nonnegative_warnv_p (t, strict_overflow_p, depth);
     }
 }
 
Index: gcc/gimple-fold.h
===================================================================
--- gcc/gimple-fold.h	2015-09-25 12:49:13.928814656 +0100
+++ gcc/gimple-fold.h	2015-10-08 10:59:12.904576852 +0100
@@ -48,7 +48,6 @@  extern tree gimple_get_virt_method_for_b
 extern tree gimple_get_virt_method_for_vtable (HOST_WIDE_INT, tree,
 					       unsigned HOST_WIDE_INT,
 					       bool *can_refer = NULL);
-extern bool gimple_val_nonnegative_real_p (tree);
 extern tree gimple_fold_indirect_ref (tree);
 extern bool arith_code_with_undefined_signed_overflow (tree_code);
 extern gimple_seq rewrite_to_defined_overflow (gimple *);
@@ -113,6 +112,8 @@  gimple_convert (gimple_seq *seq, tree ty
   return gimple_convert (seq, UNKNOWN_LOCATION, type, op);
 }
 
+extern bool gimple_stmt_nonnegative_warnv_p (gimple *, bool *, int = 0);
+
 /* In gimple-match.c.  */
 extern tree gimple_simplify (enum tree_code, tree, tree,
 			     gimple_seq *, tree (*)(tree));
Index: gcc/tree-vrp.c
===================================================================
--- gcc/tree-vrp.c	2015-10-05 20:45:48.964959975 +0100
+++ gcc/tree-vrp.c	2015-10-08 10:59:12.908576806 +0100
@@ -1007,80 +1007,6 @@  usable_range_p (value_range *vr, bool *s
   return true;
 }
 
-
-/* Return true if the result of assignment STMT is know to be non-negative.
-   If the return value is based on the assumption that signed overflow is
-   undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
-   *STRICT_OVERFLOW_P.*/
-
-static bool
-gimple_assign_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p)
-{
-  enum tree_code code = gimple_assign_rhs_code (stmt);
-  switch (get_gimple_rhs_class (code))
-    {
-    case GIMPLE_UNARY_RHS:
-      return tree_unary_nonnegative_warnv_p (gimple_assign_rhs_code (stmt),
-					     gimple_expr_type (stmt),
-					     gimple_assign_rhs1 (stmt),
-					     strict_overflow_p);
-    case GIMPLE_BINARY_RHS:
-      return tree_binary_nonnegative_warnv_p (gimple_assign_rhs_code (stmt),
-					      gimple_expr_type (stmt),
-					      gimple_assign_rhs1 (stmt),
-					      gimple_assign_rhs2 (stmt),
-					      strict_overflow_p);
-    case GIMPLE_TERNARY_RHS:
-      return false;
-    case GIMPLE_SINGLE_RHS:
-      return tree_single_nonnegative_warnv_p (gimple_assign_rhs1 (stmt),
-					      strict_overflow_p);
-    case GIMPLE_INVALID_RHS:
-      gcc_unreachable ();
-    default:
-      gcc_unreachable ();
-    }
-}
-
-/* Return true if return value of call STMT is know to be non-negative.
-   If the return value is based on the assumption that signed overflow is
-   undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
-   *STRICT_OVERFLOW_P.*/
-
-static bool
-gimple_call_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p)
-{
-  tree arg0 = gimple_call_num_args (stmt) > 0 ?
-    gimple_call_arg (stmt, 0) : NULL_TREE;
-  tree arg1 = gimple_call_num_args (stmt) > 1 ?
-    gimple_call_arg (stmt, 1) : NULL_TREE;
-
-  return tree_call_nonnegative_warnv_p (gimple_expr_type (stmt),
-					gimple_call_fndecl (stmt),
-					arg0,
-					arg1,
-					strict_overflow_p);
-}
-
-/* Return true if STMT is know to compute a non-negative value.
-   If the return value is based on the assumption that signed overflow is
-   undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
-   *STRICT_OVERFLOW_P.*/
-
-static bool
-gimple_stmt_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p)
-{
-  switch (gimple_code (stmt))
-    {
-    case GIMPLE_ASSIGN:
-      return gimple_assign_nonnegative_warnv_p (stmt, strict_overflow_p);
-    case GIMPLE_CALL:
-      return gimple_call_nonnegative_warnv_p (stmt, strict_overflow_p);
-    default:
-      gcc_unreachable ();
-    }
-}
-
 /* Return true if the result of assignment STMT is know to be non-zero.
    If the return value is based on the assumption that signed overflow is
    undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
@@ -6858,12 +6784,9 @@  remove_range_assertions (void)
 	    tree lhs = gimple_assign_lhs (stmt);
 	    tree rhs = gimple_assign_rhs1 (stmt);
 	    tree var;
-	    tree cond = fold (ASSERT_EXPR_COND (rhs));
 	    use_operand_p use_p;
 	    imm_use_iterator iter;
 
-	    gcc_assert (cond != boolean_false_node);
-
 	    var = ASSERT_EXPR_VAR (rhs);
 	    gcc_assert (TREE_CODE (var) == SSA_NAME);
 
Index: gcc/gimple-fold.c
===================================================================
--- gcc/gimple-fold.c	2015-10-07 09:07:21.198341367 +0100
+++ gcc/gimple-fold.c	2015-10-08 10:59:12.904576852 +0100
@@ -5773,137 +5773,6 @@  gimple_get_virt_method_for_binfo (HOST_W
   return gimple_get_virt_method_for_vtable (token, v, offset, can_refer);
 }
 
-/* Return true iff VAL is a gimple expression that is known to be
-   non-negative.  Restricted to floating-point inputs.  */
-
-bool
-gimple_val_nonnegative_real_p (tree val)
-{
-  gimple *def_stmt;
-
-  gcc_assert (val && SCALAR_FLOAT_TYPE_P (TREE_TYPE (val)));
-
-  /* Use existing logic for non-gimple trees.  */
-  if (tree_expr_nonnegative_p (val))
-    return true;
-
-  if (TREE_CODE (val) != SSA_NAME)
-    return false;
-
-  /* Currently we look only at the immediately defining statement
-     to make this determination, since recursion on defining 
-     statements of operands can lead to quadratic behavior in the
-     worst case.  This is expected to catch almost all occurrences
-     in practice.  It would be possible to implement limited-depth
-     recursion if important cases are lost.  Alternatively, passes
-     that need this information (such as the pow/powi lowering code
-     in the cse_sincos pass) could be revised to provide it through
-     dataflow propagation.  */
-
-  def_stmt = SSA_NAME_DEF_STMT (val);
-
-  if (is_gimple_assign (def_stmt))
-    {
-      tree op0, op1;
-
-      /* See fold-const.c:tree_expr_nonnegative_p for additional
-	 cases that could be handled with recursion.  */
-
-      switch (gimple_assign_rhs_code (def_stmt))
-	{
-	case ABS_EXPR:
-	  /* Always true for floating-point operands.  */
-	  return true;
-
-	case MULT_EXPR:
-	  /* True if the two operands are identical (since we are
-	     restricted to floating-point inputs).  */
-	  op0 = gimple_assign_rhs1 (def_stmt);
-	  op1 = gimple_assign_rhs2 (def_stmt);
-
-	  if (op0 == op1
-	      || operand_equal_p (op0, op1, 0))
-	    return true;
-
-	default:
-	  return false;
-	}
-    }
-  else if (is_gimple_call (def_stmt))
-    {
-      tree fndecl = gimple_call_fndecl (def_stmt);
-      if (fndecl
-	  && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
-	{
-	  tree arg1;
-
-	  switch (DECL_FUNCTION_CODE (fndecl))
-	    {
-	    CASE_FLT_FN (BUILT_IN_ACOS):
-	    CASE_FLT_FN (BUILT_IN_ACOSH):
-	    CASE_FLT_FN (BUILT_IN_CABS):
-	    CASE_FLT_FN (BUILT_IN_COSH):
-	    CASE_FLT_FN (BUILT_IN_ERFC):
-	    CASE_FLT_FN (BUILT_IN_EXP):
-	    CASE_FLT_FN (BUILT_IN_EXP10):
-	    CASE_FLT_FN (BUILT_IN_EXP2):
-	    CASE_FLT_FN (BUILT_IN_FABS):
-	    CASE_FLT_FN (BUILT_IN_FDIM):
-	    CASE_FLT_FN (BUILT_IN_HYPOT):
-	    CASE_FLT_FN (BUILT_IN_POW10):
-	      return true;
-
-	    CASE_FLT_FN (BUILT_IN_SQRT):
-	      /* sqrt(-0.0) is -0.0, and sqrt is not defined over other
-		 nonnegative inputs.  */
-	      if (!HONOR_SIGNED_ZEROS (val))
-		return true;
-
-	      break;
-
-	    CASE_FLT_FN (BUILT_IN_POWI):
-	      /* True if the second argument is an even integer.  */
-	      arg1 = gimple_call_arg (def_stmt, 1);
-
-	      if (TREE_CODE (arg1) == INTEGER_CST
-		  && (TREE_INT_CST_LOW (arg1) & 1) == 0)
-		return true;
-
-	      break;
-	      
-	    CASE_FLT_FN (BUILT_IN_POW):
-	      /* True if the second argument is an even integer-valued
-		 real.  */
-	      arg1 = gimple_call_arg (def_stmt, 1);
-
-	      if (TREE_CODE (arg1) == REAL_CST)
-		{
-		  REAL_VALUE_TYPE c;
-		  HOST_WIDE_INT n;
-
-		  c = TREE_REAL_CST (arg1);
-		  n = real_to_integer (&c);
-
-		  if ((n & 1) == 0)
-		    {
-		      REAL_VALUE_TYPE cint;
-		      real_from_integer (&cint, VOIDmode, n, SIGNED);
-		      if (real_identical (&c, &cint))
-			return true;
-		    }
-		}
-
-	      break;
-
-	    default:
-	      return false;
-	    }
-	}
-    }
-
-  return false;
-}
-
 /* Given a pointer value OP0, return a simplified version of an
    indirection through OP0, or NULL_TREE if no simplification is
    possible.  Note that the resulting type may be different from
@@ -6280,3 +6149,80 @@  gimple_convert (gimple_seq *seq, locatio
     return op;
   return gimple_build (seq, loc, NOP_EXPR, type, op);
 }
+
+/* Return true if the result of assignment STMT is known to be non-negative.
+   If the return value is based on the assumption that signed overflow is
+   undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
+   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
+
+static bool
+gimple_assign_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p,
+				   int depth)
+{
+  enum tree_code code = gimple_assign_rhs_code (stmt);
+  switch (get_gimple_rhs_class (code))
+    {
+    case GIMPLE_UNARY_RHS:
+      return tree_unary_nonnegative_warnv_p (gimple_assign_rhs_code (stmt),
+					     gimple_expr_type (stmt),
+					     gimple_assign_rhs1 (stmt),
+					     strict_overflow_p, depth);
+    case GIMPLE_BINARY_RHS:
+      return tree_binary_nonnegative_warnv_p (gimple_assign_rhs_code (stmt),
+					      gimple_expr_type (stmt),
+					      gimple_assign_rhs1 (stmt),
+					      gimple_assign_rhs2 (stmt),
+					      strict_overflow_p, depth);
+    case GIMPLE_TERNARY_RHS:
+      return false;
+    case GIMPLE_SINGLE_RHS:
+      return tree_single_nonnegative_warnv_p (gimple_assign_rhs1 (stmt),
+					      strict_overflow_p, depth);
+    case GIMPLE_INVALID_RHS:
+      break;
+    }
+  gcc_unreachable ();
+}
+
+/* Return true if return value of call STMT is known to be non-negative.
+   If the return value is based on the assumption that signed overflow is
+   undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
+   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
+
+static bool
+gimple_call_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p,
+				 int depth)
+{
+  tree arg0 = gimple_call_num_args (stmt) > 0 ?
+    gimple_call_arg (stmt, 0) : NULL_TREE;
+  tree arg1 = gimple_call_num_args (stmt) > 1 ?
+    gimple_call_arg (stmt, 1) : NULL_TREE;
+
+  return tree_call_nonnegative_warnv_p (gimple_expr_type (stmt),
+					gimple_call_fndecl (stmt),
+					arg0,
+					arg1,
+					strict_overflow_p, depth);
+}
+
+/* Return true if STMT is known to compute a non-negative value.
+   If the return value is based on the assumption that signed overflow is
+   undefined, set *STRICT_OVERFLOW_P to true; otherwise, don't change
+   *STRICT_OVERFLOW_P.  DEPTH is the current nesting depth of the query.  */
+
+bool
+gimple_stmt_nonnegative_warnv_p (gimple *stmt, bool *strict_overflow_p,
+				 int depth)
+{
+  switch (gimple_code (stmt))
+    {
+    case GIMPLE_ASSIGN:
+      return gimple_assign_nonnegative_warnv_p (stmt, strict_overflow_p,
+						depth);
+    case GIMPLE_CALL:
+      return gimple_call_nonnegative_warnv_p (stmt, strict_overflow_p,
+					      depth);
+    default:
+      return false;
+    }
+}
Index: gcc/tree-ssa-math-opts.c
===================================================================
--- gcc/tree-ssa-math-opts.c	2015-10-05 12:34:55.923949581 +0100
+++ gcc/tree-ssa-math-opts.c	2015-10-08 10:59:12.908576806 +0100
@@ -1526,7 +1526,7 @@  gimple_expand_builtin_pow (gimple_stmt_i
 
   if (flag_unsafe_math_optimizations
       && cbrtfn
-      && (gimple_val_nonnegative_real_p (arg0) || !HONOR_NANS (mode))
+      && (!HONOR_NANS (mode) || tree_expr_nonnegative_p (arg0))
       && real_equal (&c, &dconst1_3))
     return build_and_insert_call (gsi, loc, cbrtfn, arg0);
   
@@ -1538,7 +1538,7 @@  gimple_expand_builtin_pow (gimple_stmt_i
   if (flag_unsafe_math_optimizations
       && sqrtfn
       && cbrtfn
-      && (gimple_val_nonnegative_real_p (arg0) || !HONOR_NANS (mode))
+      && (!HONOR_NANS (mode) || tree_expr_nonnegative_p (arg0))
       && speed_p
       && hw_sqrt_exists
       && real_equal (&c, &dconst1_6))
@@ -1594,7 +1594,7 @@  gimple_expand_builtin_pow (gimple_stmt_i
 
   if (flag_unsafe_math_optimizations
       && cbrtfn
-      && (gimple_val_nonnegative_real_p (arg0) || !HONOR_NANS (mode))
+      && (!HONOR_NANS (mode) || tree_expr_nonnegative_p (arg0))
       && real_identical (&c2, &c)
       && !c2_is_int
       && optimize_function_for_speed_p (cfun)