/* Support routines for Value Range Propagation (VRP).
- Copyright (C) 2005-2015 Free Software Foundation, Inc.
+ Copyright (C) 2005-2016 Free Software Foundation, Inc.
Contributed by Diego Novillo <dnovillo@redhat.com>.
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "backend.h"
-#include "cfghooks.h"
+#include "insn-codes.h"
+#include "rtl.h"
#include "tree.h"
#include "gimple.h"
-#include "rtl.h"
+#include "cfghooks.h"
+#include "tree-pass.h"
#include "ssa.h"
+#include "optabs-tree.h"
+#include "gimple-pretty-print.h"
+#include "diagnostic-core.h"
#include "flags.h"
-#include "alias.h"
#include "fold-const.h"
#include "stor-layout.h"
#include "calls.h"
#include "cfganal.h"
-#include "internal-fn.h"
#include "gimple-fold.h"
#include "tree-eh.h"
#include "gimple-iterator.h"
#include "tree-ssa-loop.h"
#include "tree-into-ssa.h"
#include "tree-ssa.h"
-#include "tree-pass.h"
-#include "tree-dump.h"
-#include "gimple-pretty-print.h"
-#include "diagnostic-core.h"
#include "intl.h"
#include "cfgloop.h"
#include "tree-scalar-evolution.h"
#include "tree-ssa-propagate.h"
#include "tree-chrec.h"
#include "tree-ssa-threadupdate.h"
-#include "insn-codes.h"
-#include "optabs-tree.h"
#include "tree-ssa-scopedtables.h"
#include "tree-ssa-threadedge.h"
-
-
+#include "omp-low.h"
+#include "target.h"
+#include "case-cfn-macros.h"
/* Range of values that can be associated with an SSA_NAME after VRP
has executed. */
-struct value_range_d
+struct value_range
{
/* Lattice value represented by this range. */
enum value_range_type type;
bitmap equiv;
};
-typedef struct value_range_d value_range_t;
-
#define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
/* Set of SSA names found live during the RPO traversal of the function
/* Local functions. */
static int compare_values (tree val1, tree val2);
static int compare_values_warnv (tree val1, tree val2, bool *);
-static void vrp_meet (value_range_t *, value_range_t *);
-static void vrp_intersect_ranges (value_range_t *, value_range_t *);
+static void vrp_meet (value_range *, value_range *);
+static void vrp_intersect_ranges (value_range *, value_range *);
static tree vrp_evaluate_conditional_warnv_with_ops (enum tree_code,
tree, tree, bool, bool *,
bool *);
/* Value range array. After propagation, VR_VALUE[I] holds the range
of values that SSA name N_I may take. */
static unsigned num_vr_values;
-static value_range_t **vr_value;
+static value_range **vr_value;
static bool values_propagated;
/* For a PHI node which sets SSA name N_I, VR_COUNTS[I] holds the
supports_overflow_infinity (const_tree type)
{
tree min = vrp_val_min (type), max = vrp_val_max (type);
-#ifdef ENABLE_CHECKING
- gcc_assert (needs_overflow_infinity (type));
-#endif
+ gcc_checking_assert (needs_overflow_infinity (type));
return (min != NULL_TREE
&& CONSTANT_CLASS_P (min)
&& max != NULL_TREE
/* Return whether STMT has a constant rhs that is_overflow_infinity. */
static inline bool
-stmt_overflow_infinity (gimple stmt)
+stmt_overflow_infinity (gimple *stmt)
{
if (is_gimple_assign (stmt)
&& get_gimple_rhs_class (gimple_assign_rhs_code (stmt)) ==
/* Set value range VR to VR_UNDEFINED. */
static inline void
-set_value_range_to_undefined (value_range_t *vr)
+set_value_range_to_undefined (value_range *vr)
{
vr->type = VR_UNDEFINED;
vr->min = vr->max = NULL_TREE;
/* Set value range VR to VR_VARYING. */
static inline void
-set_value_range_to_varying (value_range_t *vr)
+set_value_range_to_varying (value_range *vr)
{
vr->type = VR_VARYING;
vr->min = vr->max = NULL_TREE;
/* Set value range VR to {T, MIN, MAX, EQUIV}. */
static void
-set_value_range (value_range_t *vr, enum value_range_type t, tree min,
+set_value_range (value_range *vr, enum value_range_type t, tree min,
tree max, bitmap equiv)
{
-#if defined ENABLE_CHECKING
/* Check the validity of the range. */
- if (t == VR_RANGE || t == VR_ANTI_RANGE)
+ if (flag_checking
+ && (t == VR_RANGE || t == VR_ANTI_RANGE))
{
int cmp;
|| !is_overflow_infinity (max));
}
- if (t == VR_UNDEFINED || t == VR_VARYING)
- gcc_assert (min == NULL_TREE && max == NULL_TREE);
-
- if (t == VR_UNDEFINED || t == VR_VARYING)
- gcc_assert (equiv == NULL || bitmap_empty_p (equiv));
-#endif
+ if (flag_checking
+ && (t == VR_UNDEFINED || t == VR_VARYING))
+ {
+ gcc_assert (min == NULL_TREE && max == NULL_TREE);
+ gcc_assert (equiv == NULL || bitmap_empty_p (equiv));
+ }
vr->type = t;
vr->min = min;
extract ranges from var + CST op limit. */
static void
-set_and_canonicalize_value_range (value_range_t *vr, enum value_range_type t,
+set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
tree min, tree max, bitmap equiv)
{
/* Use the canonical setters for VR_UNDEFINED and VR_VARYING. */
/* Copy value range FROM into value range TO. */
static inline void
-copy_value_range (value_range_t *to, value_range_t *from)
+copy_value_range (value_range *to, value_range *from)
{
set_value_range (to, from->type, from->min, from->max, from->equiv);
}
infinity when we shouldn't. */
static inline void
-set_value_range_to_value (value_range_t *vr, tree val, bitmap equiv)
+set_value_range_to_value (value_range *vr, tree val, bitmap equiv)
{
gcc_assert (is_gimple_min_invariant (val));
if (TREE_OVERFLOW_P (val))
overflow does not occur. */
static inline void
-set_value_range_to_nonnegative (value_range_t *vr, tree type,
+set_value_range_to_nonnegative (value_range *vr, tree type,
bool overflow_infinity)
{
tree zero;
/* Set value range VR to a non-NULL range of type TYPE. */
static inline void
-set_value_range_to_nonnull (value_range_t *vr, tree type)
+set_value_range_to_nonnull (value_range *vr, tree type)
{
tree zero = build_int_cst (type, 0);
set_value_range (vr, VR_ANTI_RANGE, zero, zero, vr->equiv);
/* Set value range VR to a NULL range of type TYPE. */
static inline void
-set_value_range_to_null (value_range_t *vr, tree type)
+set_value_range_to_null (value_range *vr, tree type)
{
set_value_range_to_value (vr, build_int_cst (type, 0), vr->equiv);
}
/* Set value range VR to a range of a truthvalue of type TYPE. */
static inline void
-set_value_range_to_truthvalue (value_range_t *vr, tree type)
+set_value_range_to_truthvalue (value_range *vr, tree type)
{
if (TYPE_PRECISION (type) == 1)
set_value_range_to_varying (vr);
abs (min) >= abs (max), set VR to [-min, min]. */
static void
-abs_extent_range (value_range_t *vr, tree min, tree max)
+abs_extent_range (value_range *vr, tree min, tree max)
{
int cmp;
If we have no values ranges recorded (ie, VRP is not running), then
return NULL. Otherwise create an empty range if none existed for VAR. */
-static value_range_t *
+static value_range *
get_value_range (const_tree var)
{
- static const struct value_range_d vr_const_varying
+ static const value_range vr_const_varying
= { VR_VARYING, NULL_TREE, NULL_TREE, NULL };
- value_range_t *vr;
+ value_range *vr;
tree sym;
unsigned ver = SSA_NAME_VERSION (var);
We should get here at most from the substitute-and-fold stage which
will never try to change values. */
if (ver >= num_vr_values)
- return CONST_CAST (value_range_t *, &vr_const_varying);
+ return CONST_CAST (value_range *, &vr_const_varying);
vr = vr_value[ver];
if (vr)
/* After propagation finished do not allocate new value-ranges. */
if (values_propagated)
- return CONST_CAST (value_range_t *, &vr_const_varying);
+ return CONST_CAST (value_range *, &vr_const_varying);
/* Create a default value range. */
- vr_value[ver] = vr = XCNEW (value_range_t);
+ vr_value[ver] = vr = XCNEW (value_range);
/* Defer allocating the equivalence set. */
vr->equiv = NULL;
is the range object associated with another SSA name. */
static inline bool
-update_value_range (const_tree var, value_range_t *new_vr)
+update_value_range (const_tree var, value_range *new_vr)
{
- value_range_t *old_vr;
+ value_range *old_vr;
bool is_new;
/* If there is a value-range on the SSA name from earlier analysis
value_range_type rtype = get_range_info (var, &min, &max);
if (rtype == VR_RANGE || rtype == VR_ANTI_RANGE)
{
- value_range_d nr;
+ value_range nr;
nr.type = rtype;
nr.min = wide_int_to_tree (TREE_TYPE (var), min);
nr.max = wide_int_to_tree (TREE_TYPE (var), max);
add_equivalence (bitmap *equiv, const_tree var)
{
unsigned ver = SSA_NAME_VERSION (var);
- value_range_t *vr = vr_value[ver];
+ value_range *vr = vr_value[ver];
if (*equiv == NULL)
*equiv = BITMAP_ALLOC (NULL);
/* Return true if VR is ~[0, 0]. */
static inline bool
-range_is_nonnull (value_range_t *vr)
+range_is_nonnull (value_range *vr)
{
return vr->type == VR_ANTI_RANGE
&& integer_zerop (vr->min)
/* Return true if VR is [0, 0]. */
static inline bool
-range_is_null (value_range_t *vr)
+range_is_null (value_range *vr)
{
return vr->type == VR_RANGE
&& integer_zerop (vr->min)
a singleton. */
static inline bool
-range_int_cst_p (value_range_t *vr)
+range_int_cst_p (value_range *vr)
{
return (vr->type == VR_RANGE
&& TREE_CODE (vr->max) == INTEGER_CST
/* Return true if VR is a INTEGER_CST singleton. */
static inline bool
-range_int_cst_singleton_p (value_range_t *vr)
+range_int_cst_singleton_p (value_range *vr)
{
return (range_int_cst_p (vr)
&& !is_overflow_infinity (vr->min)
/* Return true if value range VR involves at least one symbol. */
static inline bool
-symbolic_range_p (value_range_t *vr)
+symbolic_range_p (value_range *vr)
{
return (!is_gimple_min_invariant (vr->min)
|| !is_gimple_min_invariant (vr->max));
/* Return true if value range VR involves exactly one symbol SYM. */
static bool
-symbolic_range_based_on_p (value_range_t *vr, const_tree sym)
+symbolic_range_based_on_p (value_range *vr, const_tree sym)
{
bool neg, min_has_symbol, max_has_symbol;
tree inv;
/* Return true if value range VR uses an overflow infinity. */
static inline bool
-overflow_infinity_range_p (value_range_t *vr)
+overflow_infinity_range_p (value_range *vr)
{
return (vr->type == VR_RANGE
&& (is_overflow_infinity (vr->min)
uses an overflow infinity. */
static bool
-usable_range_p (value_range_t *vr, bool *strict_overflow_p)
+usable_range_p (value_range *vr, bool *strict_overflow_p)
{
gcc_assert (vr->type == VR_RANGE);
if (is_overflow_infinity (vr->min))
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
*STRICT_OVERFLOW_P.*/
static bool
-gimple_assign_nonzero_warnv_p (gimple stmt, bool *strict_overflow_p)
+gimple_assign_nonzero_warnv_p (gimple *stmt, bool *strict_overflow_p)
{
enum tree_code code = gimple_assign_rhs_code (stmt);
switch (get_gimple_rhs_class (code))
*STRICT_OVERFLOW_P.*/
static bool
-gimple_stmt_nonzero_warnv_p (gimple stmt, bool *strict_overflow_p)
+gimple_stmt_nonzero_warnv_p (gimple *stmt, bool *strict_overflow_p)
{
switch (gimple_code (stmt))
{
obtained so far. */
static bool
-vrp_stmt_computes_nonzero (gimple stmt, bool *strict_overflow_p)
+vrp_stmt_computes_nonzero (gimple *stmt, bool *strict_overflow_p)
{
if (gimple_stmt_nonzero_warnv_p (stmt, strict_overflow_p))
return true;
&& TREE_CODE (base) == MEM_REF
&& TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
{
- value_range_t *vr = get_value_range (TREE_OPERAND (base, 0));
+ value_range *vr = get_value_range (TREE_OPERAND (base, 0));
if (range_is_nonnull (vr))
return true;
}
*/
static inline bool
-value_ranges_intersect_p (value_range_t *vr0, value_range_t *vr1)
+value_ranges_intersect_p (value_range *vr0, value_range *vr1)
{
/* The value ranges do not intersect if the maximum of the first range is
less than the minimum of the second range or vice versa.
/* Return true if *VR is know to only contain nonnegative values. */
static inline bool
-value_range_nonnegative_p (value_range_t *vr)
+value_range_nonnegative_p (value_range *vr)
{
/* Testing for VR_ANTI_RANGE is not useful here as any anti-range
which would return a useful value should be encoded as a
otherwise return NULL_TREE. */
static tree
-value_range_constant_singleton (value_range_t *vr)
+value_range_constant_singleton (value_range *vr)
{
if (vr->type == VR_RANGE
&& operand_equal_p (vr->min, vr->max, 0)
static bool
op_with_boolean_value_range_p (tree op)
{
- value_range_t *vr;
+ value_range *vr;
if (TYPE_PRECISION (TREE_TYPE (op)) == 1)
return true;
it in *VR_P. */
static void
-extract_range_from_assert (value_range_t *vr_p, tree expr)
+extract_range_from_assert (value_range *vr_p, tree expr)
{
tree var, cond, limit, min, max, type;
- value_range_t *limit_vr;
+ value_range *limit_vr;
enum tree_code cond_code;
var = ASSERT_EXPR_VAR (expr);
always false. */
static void
-extract_range_from_ssa_name (value_range_t *vr, tree var)
+extract_range_from_ssa_name (value_range *vr, tree var)
{
- value_range_t *var_vr = get_value_range (var);
+ value_range *var_vr = get_value_range (var);
if (var_vr->type != VR_VARYING)
copy_value_range (vr, var_vr);
static bool
zero_nonzero_bits_from_vr (const tree expr_type,
- value_range_t *vr,
+ value_range *vr,
wide_int *may_be_nonzero,
wide_int *must_be_nonzero)
{
*VR1 will be VR_UNDEFINED. */
static bool
-ranges_from_anti_range (value_range_t *ar,
- value_range_t *vr0, value_range_t *vr1)
+ranges_from_anti_range (value_range *ar,
+ value_range *vr0, value_range *vr1)
{
tree type = TREE_TYPE (ar->min);
*VR0 CODE *VR1. */
static void
-extract_range_from_multiplicative_op_1 (value_range_t *vr,
+extract_range_from_multiplicative_op_1 (value_range *vr,
enum tree_code code,
- value_range_t *vr0, value_range_t *vr1)
+ value_range *vr0, value_range *vr1)
{
enum value_range_type type;
tree val[4];
type EXPR_TYPE. The resulting range is stored in *VR. */
static void
-extract_range_from_binary_expr_1 (value_range_t *vr,
+extract_range_from_binary_expr_1 (value_range *vr,
enum tree_code code, tree expr_type,
- value_range_t *vr0_, value_range_t *vr1_)
+ value_range *vr0_, value_range *vr1_)
{
- value_range_t vr0 = *vr0_, vr1 = *vr1_;
- value_range_t vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
+ value_range vr0 = *vr0_, vr1 = *vr1_;
+ value_range vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
enum value_range_type type;
tree min = NULL_TREE, max = NULL_TREE;
int cmp;
extract_range_from_binary_expr_1 (vr, code, expr_type, &vrtem0, vr1_);
if (vrtem1.type != VR_UNDEFINED)
{
- value_range_t vrres = VR_INITIALIZER;
+ value_range vrres = VR_INITIALIZER;
extract_range_from_binary_expr_1 (&vrres, code, expr_type,
&vrtem1, vr1_);
vrp_meet (vr, &vrres);
extract_range_from_binary_expr_1 (vr, code, expr_type, vr0_, &vrtem0);
if (vrtem1.type != VR_UNDEFINED)
{
- value_range_t vrres = VR_INITIALIZER;
+ value_range vrres = VR_INITIALIZER;
extract_range_from_binary_expr_1 (&vrres, code, expr_type,
vr0_, &vrtem1);
vrp_meet (vr, &vrres);
&& range_int_cst_singleton_p (&vr1))
{
bool saved_flag_wrapv;
- value_range_t vr1p = VR_INITIALIZER;
+ value_range vr1p = VR_INITIALIZER;
vr1p.type = VR_RANGE;
vr1p.min = (wide_int_to_tree
(expr_type,
if (vr1.type == VR_RANGE
&& !symbolic_range_p (&vr0)
&& !symbolic_range_p (&vr1)
- && !compare_values (vr1.min, zero))
+ && compare_values (vr1.min, zero) != 0)
max = int_const_binop (code, vr0.max, vr1.min);
else
max = zero;
return;
}
}
- else
+ else if (!symbolic_range_p (&vr0) && !symbolic_range_p (&vr1))
{
extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
return;
The resulting range is stored in *VR. */
static void
-extract_range_from_binary_expr (value_range_t *vr,
+extract_range_from_binary_expr (value_range *vr,
enum tree_code code,
tree expr_type, tree op0, tree op1)
{
- value_range_t vr0 = VR_INITIALIZER;
- value_range_t vr1 = VR_INITIALIZER;
+ value_range vr0 = VR_INITIALIZER;
+ value_range vr1 = VR_INITIALIZER;
/* Get value ranges for each operand. For constant operands, create
a new value range with the operand to simplify processing. */
&& symbolic_range_based_on_p (&vr0, op1))
{
const bool minus_p = (code == MINUS_EXPR);
- value_range_t n_vr1 = VR_INITIALIZER;
+ value_range n_vr1 = VR_INITIALIZER;
/* Try with VR0 and [-INF, OP1]. */
if (is_gimple_min_invariant (minus_p ? vr0.max : vr0.min))
&& symbolic_range_based_on_p (&vr1, op0))
{
const bool minus_p = (code == MINUS_EXPR);
- value_range_t n_vr0 = VR_INITIALIZER;
+ value_range n_vr0 = VR_INITIALIZER;
/* Try with [-INF, OP0] and VR1. */
if (is_gimple_min_invariant (minus_p ? vr1.max : vr1.min))
The resulting range is stored in *VR. */
static void
-extract_range_from_unary_expr_1 (value_range_t *vr,
+extract_range_from_unary_expr_1 (value_range *vr,
enum tree_code code, tree type,
- value_range_t *vr0_, tree op0_type)
+ value_range *vr0_, tree op0_type)
{
- value_range_t vr0 = *vr0_, vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
+ value_range vr0 = *vr0_, vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
/* VRP only operates on integral and pointer types. */
if (!(INTEGRAL_TYPE_P (op0_type)
{
/* -X is simply 0 - X, so re-use existing code that also handles
anti-ranges fine. */
- value_range_t zero = VR_INITIALIZER;
+ value_range zero = VR_INITIALIZER;
set_value_range_to_value (&zero, build_int_cst (type, 0), NULL);
extract_range_from_binary_expr_1 (vr, MINUS_EXPR, type, &zero, &vr0);
return;
{
/* ~X is simply -1 - X, so re-use existing code that also handles
anti-ranges fine. */
- value_range_t minusone = VR_INITIALIZER;
+ value_range minusone = VR_INITIALIZER;
set_value_range_to_value (&minusone, build_int_cst (type, -1), NULL);
extract_range_from_binary_expr_1 (vr, MINUS_EXPR,
type, &minusone, &vr0);
extract_range_from_unary_expr_1 (vr, code, type, &vrtem0, op0_type);
if (vrtem1.type != VR_UNDEFINED)
{
- value_range_t vrres = VR_INITIALIZER;
+ value_range vrres = VR_INITIALIZER;
extract_range_from_unary_expr_1 (&vrres, code, type,
&vrtem1, op0_type);
vrp_meet (vr, &vrres);
The resulting range is stored in *VR. */
static void
-extract_range_from_unary_expr (value_range_t *vr, enum tree_code code,
+extract_range_from_unary_expr (value_range *vr, enum tree_code code,
tree type, tree op0)
{
- value_range_t vr0 = VR_INITIALIZER;
+ value_range vr0 = VR_INITIALIZER;
/* Get value ranges for the operand. For constant operands, create
a new value range with the operand to simplify processing. */
the ranges of each of its operands and the expression code. */
static void
-extract_range_from_cond_expr (value_range_t *vr, gassign *stmt)
+extract_range_from_cond_expr (value_range *vr, gassign *stmt)
{
tree op0, op1;
- value_range_t vr0 = VR_INITIALIZER;
- value_range_t vr1 = VR_INITIALIZER;
+ value_range vr0 = VR_INITIALIZER;
+ value_range vr1 = VR_INITIALIZER;
/* Get value ranges for each operand. For constant operands, create
a new value range with the operand to simplify processing. */
on the range of its operand and the expression code. */
static void
-extract_range_from_comparison (value_range_t *vr, enum tree_code code,
+extract_range_from_comparison (value_range *vr, enum tree_code code,
tree type, tree op0, tree op1)
{
bool sop = false;
check_for_binary_op_overflow (enum tree_code subcode, tree type,
tree op0, tree op1, bool *ovf)
{
- value_range_t vr0 = VR_INITIALIZER;
- value_range_t vr1 = VR_INITIALIZER;
+ value_range vr0 = VR_INITIALIZER;
+ value_range vr1 = VR_INITIALIZER;
if (TREE_CODE (op0) == SSA_NAME)
vr0 = *get_value_range (op0);
else if (TREE_CODE (op0) == INTEGER_CST)
Store the result in *VR */
static void
-extract_range_basic (value_range_t *vr, gimple stmt)
+extract_range_basic (value_range *vr, gimple *stmt)
{
bool sop = false;
tree type = gimple_expr_type (stmt);
- if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
+ if (is_gimple_call (stmt))
{
- tree fndecl = gimple_call_fndecl (stmt), arg;
+ tree arg;
int mini, maxi, zerov = 0, prec;
+ enum tree_code subcode = ERROR_MARK;
+ combined_fn cfn = gimple_call_combined_fn (stmt);
- switch (DECL_FUNCTION_CODE (fndecl))
+ switch (cfn)
{
- case BUILT_IN_CONSTANT_P:
+ case CFN_BUILT_IN_CONSTANT_P:
/* If the call is __builtin_constant_p and the argument is a
function parameter resolve it to false. This avoids bogus
array bound warnings.
break;
/* Both __builtin_ffs* and __builtin_popcount return
[0, prec]. */
- CASE_INT_FN (BUILT_IN_FFS):
- CASE_INT_FN (BUILT_IN_POPCOUNT):
+ CASE_CFN_FFS:
+ CASE_CFN_POPCOUNT:
arg = gimple_call_arg (stmt, 0);
prec = TYPE_PRECISION (TREE_TYPE (arg));
mini = 0;
maxi = prec;
if (TREE_CODE (arg) == SSA_NAME)
{
- value_range_t *vr0 = get_value_range (arg);
+ value_range *vr0 = get_value_range (arg);
/* If arg is non-zero, then ffs or popcount
are non-zero. */
if (((vr0->type == VR_RANGE
}
goto bitop_builtin;
/* __builtin_parity* returns [0, 1]. */
- CASE_INT_FN (BUILT_IN_PARITY):
+ CASE_CFN_PARITY:
mini = 0;
maxi = 1;
goto bitop_builtin;
On many targets where the CLZ RTL or optab value is defined
for 0 the value is prec, so include that in the range
by default. */
- CASE_INT_FN (BUILT_IN_CLZ):
+ CASE_CFN_CLZ:
arg = gimple_call_arg (stmt, 0);
prec = TYPE_PRECISION (TREE_TYPE (arg));
mini = 0;
mini = -2;
if (TREE_CODE (arg) == SSA_NAME)
{
- value_range_t *vr0 = get_value_range (arg);
+ value_range *vr0 = get_value_range (arg);
/* From clz of VR_RANGE minimum we can compute
result maximum. */
if (vr0->type == VR_RANGE
If there is a ctz optab for this mode and
CTZ_DEFINED_VALUE_AT_ZERO, include that in the range,
otherwise just assume 0 won't be seen. */
- CASE_INT_FN (BUILT_IN_CTZ):
+ CASE_CFN_CTZ:
arg = gimple_call_arg (stmt, 0);
prec = TYPE_PRECISION (TREE_TYPE (arg));
mini = 0;
}
if (TREE_CODE (arg) == SSA_NAME)
{
- value_range_t *vr0 = get_value_range (arg);
+ value_range *vr0 = get_value_range (arg);
/* If arg is non-zero, then use [0, prec - 1]. */
if (((vr0->type == VR_RANGE
&& integer_nonzerop (vr0->min))
break;
goto bitop_builtin;
/* __builtin_clrsb* returns [0, prec-1]. */
- CASE_INT_FN (BUILT_IN_CLRSB):
+ CASE_CFN_CLRSB:
arg = gimple_call_arg (stmt, 0);
prec = TYPE_PRECISION (TREE_TYPE (arg));
mini = 0;
set_value_range (vr, VR_RANGE, build_int_cst (type, mini),
build_int_cst (type, maxi), NULL);
return;
- default:
- break;
- }
- }
- else if (is_gimple_call (stmt) && gimple_call_internal_p (stmt))
- {
- enum tree_code subcode = ERROR_MARK;
- switch (gimple_call_internal_fn (stmt))
- {
- case IFN_UBSAN_CHECK_ADD:
+ case CFN_UBSAN_CHECK_ADD:
subcode = PLUS_EXPR;
break;
- case IFN_UBSAN_CHECK_SUB:
+ case CFN_UBSAN_CHECK_SUB:
subcode = MINUS_EXPR;
break;
- case IFN_UBSAN_CHECK_MUL:
+ case CFN_UBSAN_CHECK_MUL:
subcode = MULT_EXPR;
break;
+ case CFN_GOACC_DIM_SIZE:
+ case CFN_GOACC_DIM_POS:
+ /* Optimizing these two internal functions helps the loop
+ optimizer eliminate outer comparisons. Size is [1,N]
+ and pos is [0,N-1]. */
+ {
+ bool is_pos = cfn == CFN_GOACC_DIM_POS;
+ int axis = get_oacc_ifn_dim_arg (stmt);
+ int size = get_oacc_fn_dim_size (current_function_decl, axis);
+
+ if (!size)
+ /* If it's dynamic, the backend might know a hardware
+ limitation. */
+ size = targetm.goacc.dim_limit (axis);
+
+ tree type = TREE_TYPE (gimple_call_lhs (stmt));
+ set_value_range (vr, VR_RANGE,
+ build_int_cst (type, is_pos ? 0 : 1),
+ size ? build_int_cst (type, size - is_pos)
+ : vrp_val_max (type), NULL);
+ }
+ return;
default:
break;
}
tree op = gimple_assign_rhs1 (stmt);
if (TREE_CODE (op) == code && TREE_CODE (TREE_OPERAND (op, 0)) == SSA_NAME)
{
- gimple g = SSA_NAME_DEF_STMT (TREE_OPERAND (op, 0));
+ gimple *g = SSA_NAME_DEF_STMT (TREE_OPERAND (op, 0));
if (is_gimple_call (g) && gimple_call_internal_p (g))
{
enum tree_code subcode = ERROR_MARK;
}
else
{
- value_range_t vr0 = VR_INITIALIZER;
- value_range_t vr1 = VR_INITIALIZER;
+ value_range vr0 = VR_INITIALIZER;
+ value_range vr1 = VR_INITIALIZER;
bool saved_flag_wrapv = flag_wrapv;
/* Pretend the arithmetics is wrapping. If there is
any overflow, IMAGPART_EXPR will be set. */
in *VR. */
static void
-extract_range_from_assignment (value_range_t *vr, gassign *stmt)
+extract_range_from_assignment (value_range *vr, gassign *stmt)
{
enum tree_code code = gimple_assign_rhs_code (stmt);
for VAR. If so, update VR with the new limits. */
static void
-adjust_range_with_scev (value_range_t *vr, struct loop *loop,
- gimple stmt, tree var)
+adjust_range_with_scev (value_range *vr, struct loop *loop,
+ gimple *stmt, tree var)
{
tree init, step, chrec, tmin, tmax, min, max, type, tem;
enum ev_direction dir;
the number of latch executions is the correct thing to use. */
if (max_loop_iterations (loop, &nit))
{
- value_range_t maxvr = VR_INITIALIZER;
+ value_range maxvr = VR_INITIALIZER;
signop sgn = TYPE_SIGN (TREE_TYPE (step));
bool overflow;
&& is_positive_overflow_infinity (max)))
return;
+ /* Even for valid range info, sometimes overflow flag will leak in.
+ As GIMPLE IL should have no constants with TREE_OVERFLOW set, we
+ drop them except for +-overflow_infinity which still need special
+ handling in vrp pass. */
+ if (TREE_OVERFLOW_P (min)
+ && ! is_negative_overflow_infinity (min))
+ min = drop_tree_overflow (min);
+ if (TREE_OVERFLOW_P (max)
+ && ! is_positive_overflow_infinity (max))
+ max = drop_tree_overflow (max);
+
set_value_range (vr, VR_RANGE, min, max, vr->equiv);
}
static tree
-compare_ranges (enum tree_code comp, value_range_t *vr0, value_range_t *vr1,
+compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
bool *strict_overflow_p)
{
/* VARYING or UNDEFINED ranges cannot be compared. */
if (vr0->type == VR_RANGE)
{
/* To simplify processing, make VR0 the anti-range. */
- value_range_t *tmp = vr0;
+ value_range *tmp = vr0;
vr0 = vr1;
vr1 = tmp;
}
infinity was used in the test. */
static tree
-compare_range_with_value (enum tree_code comp, value_range_t *vr, tree val,
+compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
bool *strict_overflow_p)
{
if (vr->type == VR_VARYING || vr->type == VR_UNDEFINED)
/* Debugging dumps. */
-void dump_value_range (FILE *, value_range_t *);
-void debug_value_range (value_range_t *);
+void dump_value_range (FILE *, value_range *);
+void debug_value_range (value_range *);
void dump_all_value_ranges (FILE *);
void debug_all_value_ranges (void);
void dump_vr_equiv (FILE *, bitmap);
/* Dump value range VR to FILE. */
void
-dump_value_range (FILE *file, value_range_t *vr)
+dump_value_range (FILE *file, value_range *vr)
{
if (vr == NULL)
fprintf (file, "[]");
/* Dump value range VR to stderr. */
DEBUG_FUNCTION void
-debug_value_range (value_range_t *vr)
+debug_value_range (value_range *vr)
{
dump_value_range (stderr, vr);
fprintf (stderr, "\n");
create a new SSA name N and return the assertion assignment
'N = ASSERT_EXPR <V, V OP W>'. */
-static gimple
+static gimple *
build_assert_expr_for (tree cond, tree v)
{
tree a;
point values. */
static inline bool
-fp_predicate (gimple stmt)
+fp_predicate (gimple *stmt)
{
GIMPLE_CHECK (stmt, GIMPLE_COND);
inferred. */
static bool
-infer_value_range (gimple stmt, tree op, enum tree_code *comp_code_p, tree *val_p)
+infer_value_range (gimple *stmt, tree op, tree_code *comp_code_p, tree *val_p)
{
*val_p = NULL_TREE;
*comp_code_p = ERROR_MARK;
&& TREE_CODE (val) == INTEGER_CST
&& TYPE_UNSIGNED (TREE_TYPE (val)))
{
- gimple def_stmt = SSA_NAME_DEF_STMT (name);
+ gimple *def_stmt = SSA_NAME_DEF_STMT (name);
tree cst2 = NULL_TREE, name2 = NULL_TREE, name3 = NULL_TREE;
/* Extract CST2 from the (optional) addition. */
&& TREE_CODE (val) == INTEGER_CST)
{
imm_use_iterator ui;
- gimple use_stmt;
+ gimple *use_stmt;
FOR_EACH_IMM_USE_STMT (use_stmt, ui, name)
{
if (!is_gimple_assign (use_stmt))
if (TREE_CODE_CLASS (comp_code) == tcc_comparison
&& TREE_CODE (val) == INTEGER_CST)
{
- gimple def_stmt = SSA_NAME_DEF_STMT (name);
+ gimple *def_stmt = SSA_NAME_DEF_STMT (name);
tree name2 = NULL_TREE, names[2], cst2 = NULL_TREE;
tree val2 = NULL_TREE;
unsigned int prec = TYPE_PRECISION (TREE_TYPE (val));
&& (nprec > 1
|| TYPE_UNSIGNED (TREE_TYPE (val))))
{
- gimple def_stmt2 = SSA_NAME_DEF_STMT (name2);
+ gimple *def_stmt2 = SSA_NAME_DEF_STMT (name2);
if (gimple_assign_cast_p (def_stmt2))
{
names[1] = gimple_assign_rhs1 (def_stmt2);
register_edge_assert_for_1 (tree op, enum tree_code code,
edge e, gimple_stmt_iterator bsi)
{
- gimple op_def;
+ gimple *op_def;
tree val;
enum tree_code rhs_code;
if (((comp_code == EQ_EXPR && integer_onep (val))
|| (comp_code == NE_EXPR && integer_zerop (val))))
{
- gimple def_stmt = SSA_NAME_DEF_STMT (name);
+ gimple *def_stmt = SSA_NAME_DEF_STMT (name);
if (is_gimple_assign (def_stmt)
&& gimple_assign_rhs_code (def_stmt) == BIT_AND_EXPR)
if (((comp_code == EQ_EXPR && integer_zerop (val))
|| (comp_code == NE_EXPR && integer_onep (val))))
{
- gimple def_stmt = SSA_NAME_DEF_STMT (name);
+ gimple *def_stmt = SSA_NAME_DEF_STMT (name);
/* For BIT_IOR_EXPR only if NAME == 0 both operands have
necessarily zero value, or if type-precision is one. */
static void
find_assert_locations_1 (basic_block bb, sbitmap live)
{
- gimple last;
+ gimple *last;
last = last_stmt (bb);
for (gimple_stmt_iterator si = gsi_last_bb (bb); !gsi_end_p (si);
gsi_prev (&si))
{
- gimple stmt;
+ gimple *stmt;
tree op;
ssa_op_iter i;
if (comp_code == NE_EXPR && integer_zerop (value))
{
tree t = op;
- gimple def_stmt = SSA_NAME_DEF_STMT (t);
+ gimple *def_stmt = SSA_NAME_DEF_STMT (t);
while (is_gimple_assign (def_stmt)
&& CONVERT_EXPR_CODE_P
process_assert_insertions_for (tree name, assert_locus *loc)
{
/* Build the comparison expression NAME_i COMP_CODE VAL. */
- gimple stmt;
+ gimple *stmt;
tree cond;
- gimple assert_stmt;
+ gimple *assert_stmt;
edge_iterator ei;
edge e;
static void
check_array_ref (location_t location, tree ref, bool ignore_off_by_one)
{
- value_range_t* vr = NULL;
+ value_range *vr = NULL;
tree low_sub, up_sub;
tree low_bound, up_bound, up_bound_p1;
tree base;
for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
{
- gimple stmt = gsi_stmt (si);
+ gimple *stmt = gsi_stmt (si);
struct walk_stmt_info wi;
if (!gimple_has_location (stmt)
|| is_gimple_debug (stmt))
continue;
memset (&wi, 0, sizeof (wi));
- wi.info = CONST_CAST (void *, (const void *)
- gimple_location_ptr (stmt));
+
+ location_t loc = gimple_location (stmt);
+ wi.info = &loc;
walk_gimple_op (gsi_stmt (si),
check_array_bounds,
in basic block COND_BB. */
static bool
-all_imm_uses_in_stmt_or_feed_cond (tree var, gimple stmt, basic_block cond_bb)
+all_imm_uses_in_stmt_or_feed_cond (tree var, gimple *stmt, basic_block cond_bb)
{
use_operand_p use_p, use2_p;
imm_use_iterator iter;
FOR_EACH_IMM_USE_FAST (use_p, iter, var)
if (USE_STMT (use_p) != stmt)
{
- gimple use_stmt = USE_STMT (use_p), use_stmt2;
+ gimple *use_stmt = USE_STMT (use_p), *use_stmt2;
if (is_gimple_debug (use_stmt))
continue;
while (is_gimple_assign (use_stmt)
{
edge e = single_pred_edge (bb);
basic_block cond_bb = e->src;
- gimple stmt = last_stmt (cond_bb);
+ gimple *stmt = last_stmt (cond_bb);
tree cst;
if (stmt == NULL
return;
if (gimple_assign_rhs1 (stmt) != var)
{
- gimple stmt2;
+ gimple *stmt2;
if (TREE_CODE (gimple_assign_rhs1 (stmt)) != SSA_NAME)
return;
FOR_EACH_BB_FN (bb, cfun)
for (si = gsi_after_labels (bb), is_unreachable = -1; !gsi_end_p (si);)
{
- gimple stmt = gsi_stmt (si);
- gimple use_stmt;
+ gimple *stmt = gsi_stmt (si);
+ gimple *use_stmt;
if (is_gimple_assign (stmt)
&& gimple_assign_rhs_code (stmt) == ASSERT_EXPR)
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);
/* Return true if STMT is interesting for VRP. */
static bool
-stmt_interesting_for_vrp (gimple stmt)
+stmt_interesting_for_vrp (gimple *stmt)
{
if (gimple_code (stmt) == GIMPLE_PHI)
{
values_propagated = false;
num_vr_values = num_ssa_names;
- vr_value = XCNEWVEC (value_range_t *, num_vr_values);
+ vr_value = XCNEWVEC (value_range *, num_vr_values);
vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
FOR_EACH_BB_FN (bb, cfun)
for (gimple_stmt_iterator si = gsi_start_bb (bb); !gsi_end_p (si);
gsi_next (&si))
{
- gimple stmt = gsi_stmt (si);
+ gimple *stmt = gsi_stmt (si);
/* If the statement is a control insn, then we do not
want to avoid simulating the statement once. Failure
{
if (TREE_CODE (name) == SSA_NAME)
{
- value_range_t *vr = get_value_range (name);
+ value_range *vr = get_value_range (name);
if (vr->type == VR_RANGE
&& (vr->min == vr->max
|| operand_equal_p (vr->min, vr->max, 0)))
/* If the definition may be simulated again we cannot follow
this SSA edge as the SSA propagator does not necessarily
re-visit the use. */
- gimple def_stmt = SSA_NAME_DEF_STMT (name);
+ gimple *def_stmt = SSA_NAME_DEF_STMT (name);
if (!gimple_nop_p (def_stmt)
&& prop_simulate_again_p (def_stmt))
return NULL_TREE;
- value_range_t *vr = get_value_range (name);
+ value_range *vr = get_value_range (name);
if (range_int_cst_singleton_p (vr))
return vr->min;
}
the SSA name in *OUTPUT_P. */
static enum ssa_prop_result
-vrp_visit_assignment_or_call (gimple stmt, tree *output_p)
+vrp_visit_assignment_or_call (gimple *stmt, tree *output_p)
{
tree def, lhs;
ssa_op_iter iter;
&& TYPE_MAX_VALUE (TREE_TYPE (lhs)))
|| POINTER_TYPE_P (TREE_TYPE (lhs))))
{
- value_range_t new_vr = VR_INITIALIZER;
+ value_range new_vr = VR_INITIALIZER;
/* Try folding the statement to a constant first. */
tree tem = gimple_fold_stmt_to_constant_1 (stmt, vrp_valueize,
FOR_EACH_IMM_USE_FAST (use_p, iter, lhs)
{
- gimple use_stmt = USE_STMT (use_p);
+ gimple *use_stmt = USE_STMT (use_p);
if (!is_gimple_assign (use_stmt))
continue;
enum tree_code rhs_code = gimple_assign_rhs_code (use_stmt);
SSA_PROP_NOT_INTERESTING. If there are no
{REAL,IMAG}PART_EXPR uses at all,
return SSA_PROP_VARYING. */
- value_range_t new_vr = VR_INITIALIZER;
+ value_range new_vr = VR_INITIALIZER;
extract_range_basic (&new_vr, use_stmt);
- value_range_t *old_vr = get_value_range (use_lhs);
+ value_range *old_vr = get_value_range (use_lhs);
if (old_vr->type != new_vr.type
|| !vrp_operand_equal_p (old_vr->min, new_vr.min)
|| !vrp_operand_equal_p (old_vr->max, new_vr.max)
or a symbolic range containing the SSA_NAME only if the value range
is varying or undefined. */
-static inline value_range_t
+static inline value_range
get_vr_for_comparison (int i)
{
- value_range_t vr = *get_value_range (ssa_name (i));
+ value_range vr = *get_value_range (ssa_name (i));
/* If name N_i does not have a valid range, use N_i as its own
range. This allows us to compare against names that may
tree retval, t;
int used_strict_overflow;
bool sop;
- value_range_t equiv_vr;
+ value_range equiv_vr;
/* Get the set of equivalences for VAR. */
e = get_value_range (var)->equiv;
of the loop just to check N1 and N2 ranges. */
EXECUTE_IF_SET_IN_BITMAP (e1, 0, i1, bi1)
{
- value_range_t vr1 = get_vr_for_comparison (i1);
+ value_range vr1 = get_vr_for_comparison (i1);
t = retval = NULL_TREE;
EXECUTE_IF_SET_IN_BITMAP (e2, 0, i2, bi2)
{
bool sop = false;
- value_range_t vr2 = get_vr_for_comparison (i2);
+ value_range vr2 = get_vr_for_comparison (i2);
t = compare_ranges (comp, &vr1, &vr2, &sop);
if (t)
tree op0, tree op1,
bool * strict_overflow_p)
{
- value_range_t *vr0, *vr1;
+ value_range *vr0, *vr1;
vr0 = (TREE_CODE (op0) == SSA_NAME) ? get_value_range (op0) : NULL;
vr1 = (TREE_CODE (op1) == SSA_NAME) ? get_value_range (op1) : NULL;
appropriate. */
static tree
-vrp_evaluate_conditional (enum tree_code code, tree op0, tree op1, gimple stmt)
+vrp_evaluate_conditional (tree_code code, tree op0, tree op1, gimple *stmt)
{
bool sop;
tree ret;
always fold regardless of the value of OP0. If -Wtype-limits
was specified, emit a warning. */
tree type = TREE_TYPE (op0);
- value_range_t *vr0 = get_value_range (op0);
+ value_range *vr0 = get_value_range (op0);
if (vr0->type == VR_RANGE
&& INTEGRAL_TYPE_P (type)
Returns true if the default label is not needed. */
static bool
-find_case_label_ranges (gswitch *stmt, value_range_t *vr, size_t *min_idx1,
+find_case_label_ranges (gswitch *stmt, value_range *vr, size_t *min_idx1,
size_t *max_idx1, size_t *min_idx2,
size_t *max_idx2)
{
vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
{
tree op, val;
- value_range_t *vr;
+ value_range *vr;
size_t i = 0, j = 0, k, l;
bool take_default;
If STMT produces a varying value, return SSA_PROP_VARYING. */
static enum ssa_prop_result
-vrp_visit_stmt (gimple stmt, edge *taken_edge_p, tree *output_p)
+vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
{
tree def;
ssa_op_iter iter;
in *VR0. This may not be the smallest possible such range. */
static void
-vrp_intersect_ranges_1 (value_range_t *vr0, value_range_t *vr1)
+vrp_intersect_ranges_1 (value_range *vr0, value_range *vr1)
{
- value_range_t saved;
+ value_range saved;
/* If either range is VR_VARYING the other one wins. */
if (vr1->type == VR_VARYING)
}
static void
-vrp_intersect_ranges (value_range_t *vr0, value_range_t *vr1)
+vrp_intersect_ranges (value_range *vr0, value_range *vr1)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
may not be the smallest possible such range. */
static void
-vrp_meet_1 (value_range_t *vr0, value_range_t *vr1)
+vrp_meet_1 (value_range *vr0, value_range *vr1)
{
- value_range_t saved;
+ value_range saved;
if (vr0->type == VR_UNDEFINED)
{
}
static void
-vrp_meet (value_range_t *vr0, value_range_t *vr1)
+vrp_meet (value_range *vr0, value_range *vr1)
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
{
size_t i;
tree lhs = PHI_RESULT (phi);
- value_range_t *lhs_vr = get_value_range (lhs);
- value_range_t vr_result = VR_INITIALIZER;
+ value_range *lhs_vr = get_value_range (lhs);
+ value_range vr_result = VR_INITIALIZER;
bool first = true;
int edges, old_edges;
struct loop *l;
if (e->flags & EDGE_EXECUTABLE)
{
tree arg = PHI_ARG_DEF (phi, i);
- value_range_t vr_arg;
+ value_range vr_arg;
++edges;
/* If we dropped either bound to +-INF then if this is a loop
PHI node SCEV may known more about its value-range. */
- if ((cmp_min > 0 || cmp_min < 0
+ if (cmp_min > 0 || cmp_min < 0
|| cmp_max < 0 || cmp_max > 0)
- && (l = loop_containing_stmt (phi))
- && l->header == gimple_bb (phi))
- adjust_range_with_scev (&vr_result, l, phi, lhs);
-
- /* If we will end up with a (-INF, +INF) range, set it to
- VARYING. Same if the previous max value was invalid for
- the type and we end up with vr_result.min > vr_result.max. */
- if ((vrp_val_is_max (vr_result.max)
- && vrp_val_is_min (vr_result.min))
- || compare_values (vr_result.min,
- vr_result.max) > 0)
- goto varying;
+ goto scev_check;
+
+ goto infinite_check;
}
/* If the new range is different than the previous value, keep
/* Nothing changed, don't add outgoing edges. */
return SSA_PROP_NOT_INTERESTING;
- /* No match found. Set the LHS to VARYING. */
varying:
+ set_value_range_to_varying (&vr_result);
+
+scev_check:
+ /* If this is a loop PHI node SCEV may known more about its value-range.
+ scev_check can be reached from two paths, one is a fall through from above
+ "varying" label, the other is direct goto from code block which tries to
+ avoid infinite simulation. */
+ if ((l = loop_containing_stmt (phi))
+ && l->header == gimple_bb (phi))
+ adjust_range_with_scev (&vr_result, l, phi, lhs);
+
+infinite_check:
+ /* If we will end up with a (-INF, +INF) range, set it to
+ VARYING. Same if the previous max value was invalid for
+ the type and we end up with vr_result.min > vr_result.max. */
+ if ((vr_result.type == VR_RANGE || vr_result.type == VR_ANTI_RANGE)
+ && !((vrp_val_is_max (vr_result.max) && vrp_val_is_min (vr_result.min))
+ || compare_values (vr_result.min, vr_result.max) > 0))
+ goto update_range;
+
+ /* No match found. Set the LHS to VARYING. */
set_value_range_to_varying (lhs_vr);
return SSA_PROP_VARYING;
}
/* Simplify boolean operations if the source is known
to be already a boolean. */
static bool
-simplify_truth_ops_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
+simplify_truth_ops_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
{
enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
tree lhs, op0, op1;
modulo. */
static bool
-simplify_div_or_mod_using_ranges (gimple stmt)
+simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
{
enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
tree val = NULL;
tree op0 = gimple_assign_rhs1 (stmt);
tree op1 = gimple_assign_rhs2 (stmt);
- value_range_t *vr = get_value_range (op0);
+ value_range *vr = get_value_range (op0);
if (rhs_code == TRUNC_MOD_EXPR
&& TREE_CODE (op1) == INTEGER_CST
}
if (!integer_pow2p (op1))
- return false;
-
- if (TYPE_UNSIGNED (TREE_TYPE (op0)))
{
- val = integer_one_node;
+ /* X % -Y can be only optimized into X % Y either if
+ X is not INT_MIN, or Y is not -1. Fold it now, as after
+ remove_range_assertions the range info might be not available
+ anymore. */
+ if (rhs_code == TRUNC_MOD_EXPR
+ && fold_stmt (gsi, follow_single_use_edges))
+ return true;
+ return false;
}
+
+ if (TYPE_UNSIGNED (TREE_TYPE (op0)))
+ val = integer_one_node;
else
{
bool sop = false;
disjoint. Return true if we do simplify. */
static bool
-simplify_min_or_max_using_ranges (gimple stmt)
+simplify_min_or_max_using_ranges (gimple *stmt)
{
tree op0 = gimple_assign_rhs1 (stmt);
tree op1 = gimple_assign_rhs2 (stmt);
ABS_EXPR into a NEGATE_EXPR. */
static bool
-simplify_abs_using_ranges (gimple stmt)
+simplify_abs_using_ranges (gimple *stmt)
{
tree op = gimple_assign_rhs1 (stmt);
- value_range_t *vr = get_value_range (op);
+ value_range *vr = get_value_range (op);
if (vr)
{
operation is redundant. */
static bool
-simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
+simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
{
tree op0 = gimple_assign_rhs1 (stmt);
tree op1 = gimple_assign_rhs2 (stmt);
tree op = NULL_TREE;
- value_range_t vr0 = VR_INITIALIZER;
- value_range_t vr1 = VR_INITIALIZER;
+ value_range vr0 = VR_INITIALIZER;
+ value_range vr1 = VR_INITIALIZER;
wide_int may_be_nonzero0, may_be_nonzero1;
wide_int must_be_nonzero0, must_be_nonzero1;
wide_int mask;
static tree
test_for_singularity (enum tree_code cond_code, tree op0,
- tree op1, value_range_t *vr,
+ tree op1, value_range *vr,
bool *strict_overflow_p)
{
tree min = NULL;
by PRECISION and UNSIGNED_P. */
static bool
-range_fits_type_p (value_range_t *vr, unsigned dest_precision, signop dest_sgn)
+range_fits_type_p (value_range *vr, unsigned dest_precision, signop dest_sgn)
{
tree src_type;
unsigned src_precision;
&& INTEGRAL_TYPE_P (TREE_TYPE (op0))
&& is_gimple_min_invariant (op1))
{
- value_range_t *vr = get_value_range (op0);
+ value_range *vr = get_value_range (op0);
/* If we have range information for OP0, then we might be
able to simplify this conditional. */
if (TREE_CODE (op0) == SSA_NAME
&& TREE_CODE (op1) == INTEGER_CST)
{
- gimple def_stmt = SSA_NAME_DEF_STMT (op0);
+ gimple *def_stmt = SSA_NAME_DEF_STMT (op0);
tree innerop;
if (!is_gimple_assign (def_stmt)
innerop = gimple_assign_rhs1 (def_stmt);
if (TREE_CODE (innerop) == SSA_NAME
- && !POINTER_TYPE_P (TREE_TYPE (innerop)))
+ && !POINTER_TYPE_P (TREE_TYPE (innerop))
+ && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (innerop)
+ && desired_pro_or_demotion_p (TREE_TYPE (innerop), TREE_TYPE (op0)))
{
- value_range_t *vr = get_value_range (innerop);
+ value_range *vr = get_value_range (innerop);
if (range_int_cst_p (vr)
&& range_fits_type_p (vr,
else
location = gimple_location (stmt);
warning_at (location, OPT_Wstrict_overflow,
- "assuming signed overflow does not occur when "
- "simplifying conditional");
+ "assuming signed overflow does not occur when "
+ "simplifying conditional");
}
tree newconst = fold_convert (TREE_TYPE (innerop), op1);
simplify_switch_using_ranges (gswitch *stmt)
{
tree op = gimple_switch_index (stmt);
- value_range_t *vr;
+ value_range *vr;
bool take_default;
edge e;
edge_iterator ei;
/* Simplify an integral conversion from an SSA name in STMT. */
static bool
-simplify_conversion_using_ranges (gimple stmt)
+simplify_conversion_using_ranges (gimple *stmt)
{
tree innerop, middleop, finaltype;
- gimple def_stmt;
- value_range_t *innervr;
+ gimple *def_stmt;
+ value_range *innervr;
signop inner_sgn, middle_sgn, final_sgn;
unsigned inner_prec, middle_prec, final_prec;
widest_int innermin, innermed, innermax, middlemin, middlemed, middlemax;
/* Simplify a conversion from integral SSA name to float in STMT. */
static bool
-simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
+simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi,
+ gimple *stmt)
{
tree rhs1 = gimple_assign_rhs1 (stmt);
- value_range_t *vr = get_value_range (rhs1);
+ value_range *vr = get_value_range (rhs1);
machine_mode fltmode = TYPE_MODE (TREE_TYPE (gimple_assign_lhs (stmt)));
machine_mode mode;
tree tem;
/* Simplify an internal fn call using ranges if possible. */
static bool
-simplify_internal_call_using_ranges (gimple_stmt_iterator *gsi, gimple stmt)
+simplify_internal_call_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
{
enum tree_code subcode;
bool is_ubsan = false;
|| (is_ubsan && ovf))
return false;
- gimple g;
+ gimple *g;
location_t loc = gimple_location (stmt);
if (is_ubsan)
g = gimple_build_assign (gimple_call_lhs (stmt), subcode, op0, op1);
static bool
simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
{
- gimple stmt = gsi_stmt (*gsi);
+ gimple *stmt = gsi_stmt (*gsi);
if (is_gimple_assign (stmt))
{
enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
case TRUNC_MOD_EXPR:
if (TREE_CODE (rhs1) == SSA_NAME
&& INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
- return simplify_div_or_mod_using_ranges (stmt);
+ return simplify_div_or_mod_using_ranges (gsi, stmt);
break;
/* Transform ABS (X) into X or -X as appropriate. */
{
bool assignment_p = false;
tree val;
- gimple stmt = gsi_stmt (*si);
+ gimple *stmt = gsi_stmt (*si);
if (is_gimple_assign (stmt)
&& TREE_CODE_CLASS (gimple_assign_rhs_code (stmt)) == tcc_comparison)
for any overflow warnings. */
static tree
-simplify_stmt_for_jump_threading (gimple stmt, gimple within_stmt)
+simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
+ class avail_exprs_stack *avail_exprs_stack ATTRIBUTE_UNUSED)
{
if (gcond *cond_stmt = dyn_cast <gcond *> (stmt))
return vrp_evaluate_conditional (gimple_cond_code (cond_stmt),
if (gassign *assign_stmt = dyn_cast <gassign *> (stmt))
{
- value_range_t new_vr = VR_INITIALIZER;
+ value_range new_vr = VR_INITIALIZER;
tree lhs = gimple_assign_lhs (assign_stmt);
if (TREE_CODE (lhs) == SSA_NAME
mark_dfs_back_edges ();
/* Do not thread across edges we are about to remove. Just marking
- them as EDGE_DFS_BACK will do. */
+ them as EDGE_IGNORE will do. */
FOR_EACH_VEC_ELT (to_remove_edges, i, e)
- e->flags |= EDGE_DFS_BACK;
+ e->flags |= EDGE_IGNORE;
/* Allocate our unwinder stack to unwind any temporary equivalences
that might be recorded. */
point in compilation. */
FOR_EACH_BB_FN (bb, cfun)
{
- gimple last;
+ gimple *last;
/* If the generic jump threading code does not find this block
interesting, then there is nothing to do. */
it to a specific successor. */
FOR_EACH_EDGE (e, ei, bb->preds)
{
- /* Do not thread across back edges or abnormal edges
- in the CFG. */
- if (e->flags & (EDGE_DFS_BACK | EDGE_COMPLEX))
+ /* Do not thread across edges marked to ignoreor abnormal
+ edges in the CFG. */
+ if (e->flags & (EDGE_IGNORE | EDGE_COMPLEX))
continue;
thread_across_edge (dummy, e, true, equiv_stack, NULL,
}
}
+ /* Clear EDGE_IGNORE. */
+ FOR_EACH_VEC_ELT (to_remove_edges, i, e)
+ e->flags &= ~EDGE_IGNORE;
+
/* We do not actually update the CFG or SSA graphs at this point as
ASSERT_EXPRs are still in the IL and cfg cleanup code does not yet
handle ASSERT_EXPRs gracefully. */
/* Traverse all the blocks folding conditionals with known ranges. */
static void
-vrp_finalize (void)
+vrp_finalize (bool warn_array_bounds_p)
{
size_t i;
fprintf (dump_file, "\n");
}
- substitute_and_fold (op_with_constant_singleton_value_range,
- vrp_fold_stmt, false);
-
- if (warn_array_bounds && first_pass_instance)
- check_all_array_refs ();
-
- /* We must identify jump threading opportunities before we release
- the datastructures built by VRP. */
- identify_jump_threads ();
-
/* Set value range to non pointer SSA_NAMEs. */
for (i = 0; i < num_vr_values; i++)
if (vr_value[i])
vr_value[i]->max);
}
+ substitute_and_fold (op_with_constant_singleton_value_range,
+ vrp_fold_stmt, false);
+
+ if (warn_array_bounds && warn_array_bounds_p)
+ check_all_array_refs ();
+
+ /* We must identify jump threading opportunities before we release
+ the datastructures built by VRP. */
+ identify_jump_threads ();
+
/* Free allocated memory. */
for (i = 0; i < num_vr_values; i++)
if (vr_value[i])
probabilities to aid branch prediction. */
static unsigned int
-execute_vrp (void)
+execute_vrp (bool warn_array_bounds_p)
{
int i;
edge e;
vrp_initialize ();
ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
- vrp_finalize ();
+ vrp_finalize (warn_array_bounds_p);
- free_numbers_of_iterations_estimates ();
+ free_numbers_of_iterations_estimates (cfun);
/* ASSERT_EXPRs must be removed before finalizing jump threads
as finalizing jump threads calls the CFG cleanup code which
{
public:
pass_vrp (gcc::context *ctxt)
- : gimple_opt_pass (pass_data_vrp, ctxt)
+ : gimple_opt_pass (pass_data_vrp, ctxt), warn_array_bounds_p (false)
{}
/* opt_pass methods: */
opt_pass * clone () { return new pass_vrp (m_ctxt); }
+ void set_pass_param (unsigned int n, bool param)
+ {
+ gcc_assert (n == 0);
+ warn_array_bounds_p = param;
+ }
virtual bool gate (function *) { return flag_tree_vrp != 0; }
- virtual unsigned int execute (function *) { return execute_vrp (); }
+ virtual unsigned int execute (function *)
+ { return execute_vrp (warn_array_bounds_p); }
+ private:
+ bool warn_array_bounds_p;
}; // class pass_vrp
} // anon namespace