+2015-10-08 Richard Sandiford <richard.sandiford@arm.com>
+
+ * 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.
+
2015-10-08 Martin Jambor <mjambor@suse.cz>
* ipa-cp.c (meet_with_1): Make the argument of abs signed. Remove
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
#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
}
}
+#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
/* 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;
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:
{
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);
/* 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;
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. */
/* 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))
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:
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);
}
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;
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))
/* 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):
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
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
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)))
/* 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. */
}
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;
}
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)
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;
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:
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);
}
}
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,
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 *);
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
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;
+ }
+}
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 *);
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));
"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:
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);
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))
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)
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
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);