This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: Generalize gimple_val_nonnegative_real_p
- From: Richard Biener <richard dot guenther at gmail dot com>
- To: Richard Biener <richard dot guenther at gmail dot com>, GCC Patches <gcc-patches at gcc dot gnu dot org>, richard dot sandiford at arm dot com
- Date: Thu, 8 Oct 2015 15:42:12 +0200
- Subject: Re: Generalize gimple_val_nonnegative_real_p
- Authentication-results: sourceware.org; auth=none
- References: <87oagdbbot dot fsf at e105548-lin dot cambridge dot arm dot com> <CAFiYyc2t96rsJbi4A7Q4=h4-GQ3T17ELecnHUnZWk6yRXyrBUg at mail dot gmail dot com> <87y4fdacx5 dot fsf at e105548-lin dot cambridge dot arm dot com>
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)
>