Multi-range implementation for value_range (irange).
Implement class irange, a generic multi-range implementation for value ranges. This class is API compatible with value_range, and is meant to seamlessly coexist with it. gcc/ChangeLog: * Makefile.in (GTFILES): Move value-range.h up. * gengtype-lex.l: Set yylval to handle GTY markers on templates. * ipa-cp.c (initialize_node_lattices): Call value_range constructor. (ipcp_propagate_stage): Use in-place new so value_range construct is called. * ipa-fnsummary.c (evaluate_conditions_for_known_args): Use std vec instead of GCC's vec<>. (evaluate_properties_for_edge): Adjust for std vec. (ipa_fn_summary_t::duplicate): Same. (estimate_ipcp_clone_size_and_time): Same. * ipa-prop.c (ipa_get_value_range): Use in-place new for value_range. * ipa-prop.h (struct GTY): Remove class keyword for m_vr. * range-op.cc (empty_range_check): Rename to... (empty_range_varying): ...this and adjust for varying. (undefined_shift_range_check): Adjust for irange. (range_operator::wi_fold): Same. (range_operator::fold_range): Adjust for irange. Special case single pairs for performance. (range_operator::op1_range): Adjust for irange. (range_operator::op2_range): Same. (value_range_from_overflowed_bounds): Same. (value_range_with_overflow): Same. (create_possibly_reversed_range): Same. (range_true): Same. (range_false): Same. (range_true_and_false): Same. (get_bool_state): Adjust for irange and tweak for performance. (operator_equal::fold_range): Adjust for irange. (operator_equal::op1_range): Same. (operator_equal::op2_range): Same. (operator_not_equal::fold_range): Same. (operator_not_equal::op1_range): Same. (operator_not_equal::op2_range): Same. (build_lt): Same. (build_le): Same. (build_gt): Same. (build_ge): Same. (operator_lt::fold_range): Same. (operator_lt::op1_range): Same. (operator_lt::op2_range): Same. (operator_le::fold_range): Same. (operator_le::op1_range): Same. (operator_le::op2_range): Same. (operator_gt::fold_range): Same. (operator_gt::op1_range): Same. (operator_gt::op2_range): Same. (operator_ge::fold_range): Same. (operator_ge::op1_range): Same. (operator_ge::op2_range): Same. (operator_plus::wi_fold): Same. (operator_plus::op1_range): Same. (operator_plus::op2_range): Same. (operator_minus::wi_fold): Same. (operator_minus::op1_range): Same. (operator_minus::op2_range): Same. (operator_min::wi_fold): Same. (operator_max::wi_fold): Same. (cross_product_operator::wi_cross_product): Same. (operator_mult::op1_range): New. (operator_mult::op2_range): New. (operator_mult::wi_fold): Adjust for irange. (operator_div::wi_fold): Same. (operator_exact_divide::op1_range): Same. (operator_lshift::fold_range): Same. (operator_lshift::wi_fold): Same. (operator_lshift::op1_range): New. (operator_rshift::op1_range): New. (operator_rshift::fold_range): Adjust for irange. (operator_rshift::wi_fold): Same. (operator_cast::truncating_cast_p): Abstract out from operator_cast::fold_range. (operator_cast::fold_range): Adjust for irange and tweak for performance. (operator_cast::inside_domain_p): Abstract out from fold_range. (operator_cast::fold_pair): Same. (operator_cast::op1_range): Use abstracted methods above. Adjust for irange and tweak for performance. (operator_logical_and::fold_range): Adjust for irange. (operator_logical_and::op1_range): Same. (operator_logical_and::op2_range): Same. (unsigned_singleton_p): New. (operator_bitwise_and::remove_impossible_ranges): New. (operator_bitwise_and::fold_range): New. (wi_optimize_and_or): Adjust for irange. (operator_bitwise_and::wi_fold): Same. (set_nonzero_range_from_mask): New. (operator_bitwise_and::simple_op1_range_solver): New. (operator_bitwise_and::op1_range): Adjust for irange. (operator_bitwise_and::op2_range): Same. (operator_logical_or::fold_range): Same. (operator_logical_or::op1_range): Same. (operator_logical_or::op2_range): Same. (operator_bitwise_or::wi_fold): Same. (operator_bitwise_or::op1_range): Same. (operator_bitwise_or::op2_range): Same. (operator_bitwise_xor::wi_fold): Same. (operator_bitwise_xor::op1_range): New. (operator_bitwise_xor::op2_range): New. (operator_trunc_mod::wi_fold): Adjust for irange. (operator_logical_not::fold_range): Same. (operator_logical_not::op1_range): Same. (operator_bitwise_not::fold_range): Same. (operator_bitwise_not::op1_range): Same. (operator_cst::fold_range): Same. (operator_identity::fold_range): Same. (operator_identity::op1_range): Same. (class operator_unknown): New. (operator_unknown::fold_range): New. (class operator_abs): Adjust for irange. (operator_abs::wi_fold): Same. (operator_abs::op1_range): Same. (operator_absu::wi_fold): Same. (class operator_negate): Same. (operator_negate::fold_range): Same. (operator_negate::op1_range): Same. (operator_addr_expr::fold_range): Same. (operator_addr_expr::op1_range): Same. (pointer_plus_operator::wi_fold): Same. (pointer_min_max_operator::wi_fold): Same. (pointer_and_operator::wi_fold): Same. (pointer_or_operator::op1_range): New. (pointer_or_operator::op2_range): New. (pointer_or_operator::wi_fold): Adjust for irange. (integral_table::integral_table): Add entries for IMAGPART_EXPR and POINTER_DIFF_EXPR. (range_cast): Adjust for irange. (build_range3): New. (range3_tests): New. (widest_irange_tests): New. (multi_precision_range_tests): New. (operator_tests): New. (range_tests): New. * range-op.h (class range_operator): Adjust for irange. (range_cast): Same. * tree-vrp.c (range_fold_binary_symbolics_p): Adjust for irange and tweak for performance. (range_fold_binary_expr): Same. (masked_increment): Change to extern. * tree-vrp.h (masked_increment): New. * tree.c (cache_wide_int_in_type_cache): New function abstracted out from wide_int_to_tree_1. (wide_int_to_tree_1): Cache 0, 1, and MAX for pointers. * value-range-equiv.cc (value_range_equiv::deep_copy): Use kind method. (value_range_equiv::move): Same. (value_range_equiv::check): Adjust for irange. (value_range_equiv::intersect): Same. (value_range_equiv::union_): Same. (value_range_equiv::dump): Same. * value-range.cc (irange::operator=): Same. (irange::maybe_anti_range): New. (irange::copy_legacy_range): New. (irange::set_undefined): Adjust for irange. (irange::swap_out_of_order_endpoints): Abstract out from set(). (irange::set_varying): Adjust for irange. (irange::irange_set): New. (irange::irange_set_anti_range): New. (irange::set): Adjust for irange. (value_range::set_nonzero): Move to header file. (value_range::set_zero): Move to header file. (value_range::check): Rename to... (irange::verify_range): ...this. (value_range::num_pairs): Rename to... (irange::legacy_num_pairs): ...this, and adjust for irange. (value_range::lower_bound): Rename to... (irange::legacy_lower_bound): ...this, and adjust for irange. (value_range::upper_bound): Rename to... (irange::legacy_upper_bound): ...this, and adjust for irange. (value_range::equal_p): Rename to... (irange::legacy_equal_p): ...this. (value_range::operator==): Move to header file. (irange::equal_p): New. (irange::symbolic_p): Adjust for irange. (irange::constant_p): Same. (irange::singleton_p): Same. (irange::value_inside_range): Same. (irange::may_contain_p): Same. (irange::contains_p): Same. (irange::normalize_addresses): Same. (irange::normalize_symbolics): Same. (irange::legacy_intersect): Same. (irange::legacy_union): Same. (irange::union_): Same. (irange::intersect): Same. (irange::irange_union): New. (irange::irange_intersect): New. (subtract_one): New. (irange::invert): Adjust for irange. (dump_bound_with_infinite_markers): New. (irange::dump): Adjust for irange. (debug): Add irange versions. (range_has_numeric_bounds_p): Adjust for irange. (vrp_val_max): Move to header file. (vrp_val_min): Move to header file. (DEFINE_INT_RANGE_GC_STUBS): New. (DEFINE_INT_RANGE_INSTANCE): New. * value-range.h (class irange): New. (class int_range): New. (class value_range): Rename to a instantiation of int_range. (irange::legacy_mode_p): New. (value_range::value_range): Remove. (irange::kind): New. (irange::num_pairs): Adjust for irange. (irange::type): Adjust for irange. (irange::tree_lower_bound): New. (irange::tree_upper_bound): New. (irange::type): Adjust for irange. (irange::min): Same. (irange::max): Same. (irange::varying_p): Same. (irange::undefined_p): Same. (irange::zero_p): Same. (irange::nonzero_p): Same. (irange::supports_type_p): Same. (range_includes_zero_p): Same. (gt_ggc_mx): New. (gt_pch_nx): New. (irange::irange): New. (int_range::int_range): New. (int_range::operator=): New. (irange::set): Moved from value-range.cc and adjusted for irange. (irange::set_undefined): Same. (irange::set_varying): Same. (irange::operator==): Same. (irange::lower_bound): Same. (irange::upper_bound): Same. (irange::union_): Same. (irange::intersect): Same. (irange::set_nonzero): Same. (irange::set_zero): Same. (irange::normalize_min_max): New. (vrp_val_max): Move from value-range.cc. (vrp_val_min): Same. * vr-values.c (vr_values::get_lattice_entry): Call value_range constructor.
This commit is contained in:
parent
442b5a661e
commit
4ba9fb0a3e
15 changed files with 2892 additions and 1199 deletions
|
@ -2628,13 +2628,13 @@ GTFILES = $(CPPLIB_H) $(srcdir)/input.h $(srcdir)/coretypes.h \
|
|||
$(srcdir)/tree-ssa-alias.h \
|
||||
$(srcdir)/tree-ssanames.h \
|
||||
$(srcdir)/tree-vrp.h \
|
||||
$(srcdir)/value-range.h \
|
||||
$(srcdir)/ipa-prop.h \
|
||||
$(srcdir)/trans-mem.c \
|
||||
$(srcdir)/lto-streamer.h \
|
||||
$(srcdir)/target-globals.h \
|
||||
$(srcdir)/ipa-predicate.h \
|
||||
$(srcdir)/ipa-fnsummary.h \
|
||||
$(srcdir)/value-range.h \
|
||||
$(srcdir)/vtable-verify.c \
|
||||
$(srcdir)/asan.c \
|
||||
$(srcdir)/ubsan.c \
|
||||
|
|
|
@ -125,7 +125,10 @@ CXX_KEYWORD inline|public:|private:|protected:|template|operator|friend|static|m
|
|||
"ptr_alias"/{EOID} { return PTR_ALIAS; }
|
||||
"nested_ptr"/{EOID} { return NESTED_PTR; }
|
||||
"user"/{EOID} { return USER_GTY; }
|
||||
[0-9]+ { return NUM; }
|
||||
[0-9]+ {
|
||||
*yylval = XDUPVAR (const char, yytext, yyleng, yyleng+1);
|
||||
return NUM;
|
||||
}
|
||||
|
||||
{IWORD}({WS}{IWORD})*/{EOID} |
|
||||
"ENUM_BITFIELD"{WS}?"("{WS}?{ID}{WS}?")" {
|
||||
|
|
|
@ -1270,6 +1270,7 @@ initialize_node_lattices (struct cgraph_node *node)
|
|||
plats->ctxlat.set_to_bottom ();
|
||||
set_agg_lats_to_bottom (plats);
|
||||
plats->bits_lattice.set_to_bottom ();
|
||||
plats->m_value_range.m_vr = value_range ();
|
||||
plats->m_value_range.set_to_bottom ();
|
||||
}
|
||||
else
|
||||
|
@ -3898,8 +3899,10 @@ ipcp_propagate_stage (class ipa_topo_info *topo)
|
|||
{
|
||||
class ipa_node_params *info = IPA_NODE_REF (node);
|
||||
determine_versionability (node, info);
|
||||
info->lattices = XCNEWVEC (class ipcp_param_lattices,
|
||||
ipa_get_param_count (info));
|
||||
|
||||
unsigned nlattices = ipa_get_param_count (info);
|
||||
void *chunk = XCNEWVEC (class ipcp_param_lattices, nlattices);
|
||||
info->lattices = new (chunk) ipcp_param_lattices[nlattices];
|
||||
initialize_node_lattices (node);
|
||||
}
|
||||
ipa_size_summary *s = ipa_size_summaries->get (node);
|
||||
|
|
|
@ -82,6 +82,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#include "gimplify.h"
|
||||
#include "stringpool.h"
|
||||
#include "attribs.h"
|
||||
#include <vector>
|
||||
#include "tree-into-ssa.h"
|
||||
|
||||
/* Summaries. */
|
||||
|
@ -330,7 +331,7 @@ static void
|
|||
evaluate_conditions_for_known_args (struct cgraph_node *node,
|
||||
bool inline_p,
|
||||
vec<tree> known_vals,
|
||||
vec<value_range> known_value_ranges,
|
||||
const std::vector<value_range> &known_value_ranges,
|
||||
vec<ipa_agg_value_set> known_aggs,
|
||||
clause_t *ret_clause,
|
||||
clause_t *ret_nonspec_clause)
|
||||
|
@ -445,7 +446,7 @@ evaluate_conditions_for_known_args (struct cgraph_node *node,
|
|||
continue;
|
||||
}
|
||||
}
|
||||
if (c->operand_num < (int) known_value_ranges.length ()
|
||||
if (c->operand_num < (int) known_value_ranges.size ()
|
||||
&& !c->agg_contents
|
||||
&& !known_value_ranges[c->operand_num].undefined_p ()
|
||||
&& !known_value_ranges[c->operand_num].varying_p ()
|
||||
|
@ -554,7 +555,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
|
|||
{
|
||||
struct cgraph_node *callee = e->callee->ultimate_alias_target ();
|
||||
class ipa_fn_summary *info = ipa_fn_summaries->get (callee);
|
||||
auto_vec<value_range, 32> known_value_ranges;
|
||||
std::vector<value_range> known_value_ranges (32);
|
||||
class ipa_edge_args *args;
|
||||
|
||||
if (clause_ptr)
|
||||
|
@ -629,8 +630,12 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p,
|
|||
i));
|
||||
if (!vr.undefined_p () && !vr.varying_p ())
|
||||
{
|
||||
if (!known_value_ranges.length ())
|
||||
known_value_ranges.safe_grow_cleared (count);
|
||||
if (!known_value_ranges.size ())
|
||||
{
|
||||
known_value_ranges.resize (count);
|
||||
for (int i = 0; i < count; ++i)
|
||||
known_value_ranges[i].set_undefined ();
|
||||
}
|
||||
known_value_ranges[i] = vr;
|
||||
}
|
||||
}
|
||||
|
@ -803,7 +808,7 @@ ipa_fn_summary_t::duplicate (cgraph_node *src,
|
|||
}
|
||||
evaluate_conditions_for_known_args (dst, false,
|
||||
known_vals,
|
||||
vNULL,
|
||||
std::vector<value_range> (),
|
||||
vNULL,
|
||||
&possible_truths,
|
||||
/* We are going to specialize,
|
||||
|
@ -3687,7 +3692,8 @@ estimate_ipcp_clone_size_and_time (struct cgraph_node *node,
|
|||
clause_t clause, nonspec_clause;
|
||||
|
||||
/* TODO: Also pass known value ranges. */
|
||||
evaluate_conditions_for_known_args (node, false, known_vals, vNULL,
|
||||
evaluate_conditions_for_known_args (node, false, known_vals,
|
||||
std::vector<value_range> (),
|
||||
known_aggs, &clause, &nonspec_clause);
|
||||
ipa_call_context ctx (node, clause, nonspec_clause,
|
||||
known_vals, known_contexts,
|
||||
|
|
|
@ -2059,7 +2059,7 @@ ipa_get_value_range (value_range *tmp)
|
|||
if (*slot)
|
||||
return *slot;
|
||||
|
||||
value_range *vr = ggc_alloc<value_range> ();
|
||||
value_range *vr = new (ggc_alloc<value_range> ()) value_range;
|
||||
*vr = *tmp;
|
||||
*slot = vr;
|
||||
|
||||
|
|
|
@ -318,7 +318,7 @@ struct GTY (()) ipa_jump_func
|
|||
/* Information about value range, containing valid data only when vr_known is
|
||||
true. The pointed to structure is shared betweed different jump
|
||||
functions. Use ipa_set_jfunc_vr to set this field. */
|
||||
class value_range *m_vr;
|
||||
value_range *m_vr;
|
||||
|
||||
enum jump_func_type type;
|
||||
/* Represents a value of a jump function. pass_through is used only in jump
|
||||
|
|
1950
gcc/range-op.cc
1950
gcc/range-op.cc
File diff suppressed because it is too large
Load diff
|
@ -50,9 +50,9 @@ class range_operator
|
|||
{
|
||||
public:
|
||||
// Perform an operation between 2 ranges and return it.
|
||||
virtual bool fold_range (value_range &r, tree type,
|
||||
const value_range &lh,
|
||||
const value_range &rh) const;
|
||||
virtual bool fold_range (irange &r, tree type,
|
||||
const irange &lh,
|
||||
const irange &rh) const;
|
||||
|
||||
// Return the range for op[12] in the general case. LHS is the range for
|
||||
// the LHS of the expression, OP[12]is the range for the other
|
||||
|
@ -65,16 +65,16 @@ public:
|
|||
//
|
||||
// i.e. [LHS] = ??? + OP2
|
||||
// is re-formed as R = [LHS] - OP2.
|
||||
virtual bool op1_range (value_range &r, tree type,
|
||||
const value_range &lhs,
|
||||
const value_range &op2) const;
|
||||
virtual bool op2_range (value_range &r, tree type,
|
||||
const value_range &lhs,
|
||||
const value_range &op1) const;
|
||||
virtual bool op1_range (irange &r, tree type,
|
||||
const irange &lhs,
|
||||
const irange &op2) const;
|
||||
virtual bool op2_range (irange &r, tree type,
|
||||
const irange &lhs,
|
||||
const irange &op1) const;
|
||||
|
||||
protected:
|
||||
// Perform an integral operation between 2 sub-ranges and return it.
|
||||
virtual void wi_fold (value_range &r, tree type,
|
||||
virtual void wi_fold (irange &r, tree type,
|
||||
const wide_int &lh_lb,
|
||||
const wide_int &lh_ub,
|
||||
const wide_int &rh_lb,
|
||||
|
@ -82,7 +82,7 @@ protected:
|
|||
};
|
||||
|
||||
extern range_operator *range_op_handler (enum tree_code code, tree type);
|
||||
extern void range_cast (value_range &, tree type);
|
||||
extern void range_cast (irange &, tree type);
|
||||
extern void wi_set_zero_nonzero_bits (tree type,
|
||||
const wide_int &, const wide_int &,
|
||||
wide_int &maybe_nonzero,
|
||||
|
|
|
@ -1151,25 +1151,29 @@ static bool
|
|||
range_fold_binary_symbolics_p (value_range *vr,
|
||||
tree_code code,
|
||||
tree expr_type,
|
||||
const value_range *vr0, const value_range *vr1)
|
||||
const value_range *vr0_,
|
||||
const value_range *vr1_)
|
||||
{
|
||||
if (vr0->symbolic_p () || vr1->symbolic_p ())
|
||||
if (vr0_->symbolic_p () || vr1_->symbolic_p ())
|
||||
{
|
||||
value_range vr0 = drop_undefines_to_varying (vr0_, expr_type);
|
||||
value_range vr1 = drop_undefines_to_varying (vr1_, expr_type);
|
||||
if ((code == PLUS_EXPR || code == MINUS_EXPR))
|
||||
{
|
||||
extract_range_from_plus_minus_expr (vr, code, expr_type, vr0, vr1);
|
||||
extract_range_from_plus_minus_expr (vr, code, expr_type,
|
||||
&vr0, &vr1);
|
||||
return true;
|
||||
}
|
||||
if (POINTER_TYPE_P (expr_type) && code == POINTER_PLUS_EXPR)
|
||||
{
|
||||
extract_range_from_pointer_plus_expr (vr, code, expr_type, vr0, vr1);
|
||||
extract_range_from_pointer_plus_expr (vr, code, expr_type,
|
||||
&vr0, &vr1);
|
||||
return true;
|
||||
}
|
||||
const range_operator *op = get_range_op_handler (vr, code, expr_type);
|
||||
value_range vr0_cst (*vr0), vr1_cst (*vr1);
|
||||
vr0_cst.normalize_symbolics ();
|
||||
vr1_cst.normalize_symbolics ();
|
||||
return op->fold_range (*vr, expr_type, vr0_cst, vr1_cst);
|
||||
vr0.normalize_symbolics ();
|
||||
vr1.normalize_symbolics ();
|
||||
return op->fold_range (*vr, expr_type, vr0, vr1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1225,11 +1229,15 @@ range_fold_binary_expr (value_range *vr,
|
|||
if (!op)
|
||||
return;
|
||||
|
||||
value_range vr0 = drop_undefines_to_varying (vr0_, expr_type);
|
||||
value_range vr1 = drop_undefines_to_varying (vr1_, expr_type);
|
||||
if (range_fold_binary_symbolics_p (vr, code, expr_type, &vr0, &vr1))
|
||||
if (range_fold_binary_symbolics_p (vr, code, expr_type, vr0_, vr1_))
|
||||
return;
|
||||
|
||||
value_range vr0 (*vr0_);
|
||||
value_range vr1 (*vr1_);
|
||||
if (vr0.undefined_p ())
|
||||
vr0.set_varying (expr_type);
|
||||
if (vr1.undefined_p ())
|
||||
vr1.set_varying (expr_type);
|
||||
vr0.normalize_addresses ();
|
||||
vr1.normalize_addresses ();
|
||||
op->fold_range (*vr, expr_type, vr0, vr1);
|
||||
|
@ -1637,7 +1645,7 @@ extract_code_and_val_from_cond_with_ops (tree name, enum tree_code cond_code,
|
|||
(to transform signed values into unsigned) and at the end xor
|
||||
SGNBIT back. */
|
||||
|
||||
static wide_int
|
||||
wide_int
|
||||
masked_increment (const wide_int &val_in, const wide_int &mask,
|
||||
const wide_int &sgnbit, unsigned int prec)
|
||||
{
|
||||
|
|
|
@ -62,5 +62,7 @@ extern bool overflow_comparison_p (tree_code, tree, tree, bool, tree *);
|
|||
extern tree get_single_symbol (tree, bool *, tree *);
|
||||
extern void maybe_set_nonzero_bits (edge, tree);
|
||||
extern value_range_kind determine_value_range (tree, wide_int *, wide_int *);
|
||||
extern wide_int masked_increment (const wide_int &val_in, const wide_int &mask,
|
||||
const wide_int &sgnbit, unsigned int prec);
|
||||
|
||||
#endif /* GCC_TREE_VRP_H */
|
||||
|
|
85
gcc/tree.c
85
gcc/tree.c
|
@ -1483,6 +1483,31 @@ int_cst_hasher::equal (tree x, tree y)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Cache wide_int CST into the TYPE_CACHED_VALUES cache for TYPE.
|
||||
SLOT is the slot entry to store it in, and MAX_SLOTS is the maximum
|
||||
number of slots that can be cached for the type. */
|
||||
|
||||
static inline tree
|
||||
cache_wide_int_in_type_cache (tree type, const wide_int &cst,
|
||||
int slot, int max_slots)
|
||||
{
|
||||
gcc_checking_assert (slot >= 0);
|
||||
/* Initialize cache. */
|
||||
if (!TYPE_CACHED_VALUES_P (type))
|
||||
{
|
||||
TYPE_CACHED_VALUES_P (type) = 1;
|
||||
TYPE_CACHED_VALUES (type) = make_tree_vec (max_slots);
|
||||
}
|
||||
tree t = TREE_VEC_ELT (TYPE_CACHED_VALUES (type), slot);
|
||||
if (!t)
|
||||
{
|
||||
/* Create a new shared int. */
|
||||
t = build_new_int_cst (type, cst);
|
||||
TREE_VEC_ELT (TYPE_CACHED_VALUES (type), slot) = t;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Create an INT_CST node of TYPE and value CST.
|
||||
The returned node is always shared. For small integers we use a
|
||||
per-type vector cache, for larger ones we use a single hash table.
|
||||
|
@ -1515,6 +1540,28 @@ wide_int_to_tree_1 (tree type, const wide_int_ref &pcst)
|
|||
wide_int cst = wide_int::from (pcst, prec, sgn);
|
||||
unsigned int ext_len = get_int_cst_ext_nunits (type, cst);
|
||||
|
||||
enum tree_code code = TREE_CODE (type);
|
||||
if (code == POINTER_TYPE || code == REFERENCE_TYPE)
|
||||
{
|
||||
/* Cache NULL pointer and zero bounds. */
|
||||
if (cst == 0)
|
||||
ix = 0;
|
||||
/* Cache upper bounds of pointers. */
|
||||
else if (cst == wi::max_value (prec, sgn))
|
||||
ix = 1;
|
||||
/* Cache 1 which is used for a non-zero range. */
|
||||
else if (cst == 1)
|
||||
ix = 2;
|
||||
|
||||
if (ix >= 0)
|
||||
{
|
||||
t = cache_wide_int_in_type_cache (type, cst, ix, 3);
|
||||
/* Make sure no one is clobbering the shared constant. */
|
||||
gcc_checking_assert (TREE_TYPE (t) == type
|
||||
&& cst == wi::to_wide (t));
|
||||
return t;
|
||||
}
|
||||
}
|
||||
if (ext_len == 1)
|
||||
{
|
||||
/* We just need to store a single HOST_WIDE_INT. */
|
||||
|
@ -1524,7 +1571,7 @@ wide_int_to_tree_1 (tree type, const wide_int_ref &pcst)
|
|||
else
|
||||
hwi = cst.to_shwi ();
|
||||
|
||||
switch (TREE_CODE (type))
|
||||
switch (code)
|
||||
{
|
||||
case NULLPTR_TYPE:
|
||||
gcc_assert (hwi == 0);
|
||||
|
@ -1532,12 +1579,7 @@ wide_int_to_tree_1 (tree type, const wide_int_ref &pcst)
|
|||
|
||||
case POINTER_TYPE:
|
||||
case REFERENCE_TYPE:
|
||||
/* Cache NULL pointer and zero bounds. */
|
||||
if (hwi == 0)
|
||||
{
|
||||
limit = 1;
|
||||
ix = 0;
|
||||
}
|
||||
/* Ignore pointers, as they were already handled above. */
|
||||
break;
|
||||
|
||||
case BOOLEAN_TYPE:
|
||||
|
@ -1574,27 +1616,14 @@ wide_int_to_tree_1 (tree type, const wide_int_ref &pcst)
|
|||
|
||||
if (ix >= 0)
|
||||
{
|
||||
/* Look for it in the type's vector of small shared ints. */
|
||||
if (!TYPE_CACHED_VALUES_P (type))
|
||||
{
|
||||
TYPE_CACHED_VALUES_P (type) = 1;
|
||||
TYPE_CACHED_VALUES (type) = make_tree_vec (limit);
|
||||
}
|
||||
|
||||
t = TREE_VEC_ELT (TYPE_CACHED_VALUES (type), ix);
|
||||
if (t)
|
||||
/* Make sure no one is clobbering the shared constant. */
|
||||
gcc_checking_assert (TREE_TYPE (t) == type
|
||||
&& TREE_INT_CST_NUNITS (t) == 1
|
||||
&& TREE_INT_CST_OFFSET_NUNITS (t) == 1
|
||||
&& TREE_INT_CST_EXT_NUNITS (t) == 1
|
||||
&& TREE_INT_CST_ELT (t, 0) == hwi);
|
||||
else
|
||||
{
|
||||
/* Create a new shared int. */
|
||||
t = build_new_int_cst (type, cst);
|
||||
TREE_VEC_ELT (TYPE_CACHED_VALUES (type), ix) = t;
|
||||
}
|
||||
t = cache_wide_int_in_type_cache (type, cst, ix, limit);
|
||||
/* Make sure no one is clobbering the shared constant. */
|
||||
gcc_checking_assert (TREE_TYPE (t) == type
|
||||
&& TREE_INT_CST_NUNITS (t) == 1
|
||||
&& TREE_INT_CST_OFFSET_NUNITS (t) == 1
|
||||
&& TREE_INT_CST_EXT_NUNITS (t) == 1
|
||||
&& TREE_INT_CST_ELT (t, 0) == hwi);
|
||||
return t;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -90,13 +90,13 @@ value_range_equiv::update (tree min, tree max, value_range_kind kind)
|
|||
void
|
||||
value_range_equiv::deep_copy (const value_range_equiv *from)
|
||||
{
|
||||
set (from->min (), from->max (), from->m_equiv, from->m_kind);
|
||||
set (from->min (), from->max (), from->m_equiv, from->kind ());
|
||||
}
|
||||
|
||||
void
|
||||
value_range_equiv::move (value_range_equiv *from)
|
||||
{
|
||||
set (from->min (), from->max (), NULL, from->m_kind);
|
||||
set (from->min (), from->max (), NULL, from->kind ());
|
||||
m_equiv = from->m_equiv;
|
||||
from->m_equiv = NULL;
|
||||
}
|
||||
|
@ -127,8 +127,8 @@ value_range_equiv::set_equiv (bitmap equiv)
|
|||
void
|
||||
value_range_equiv::check ()
|
||||
{
|
||||
value_range::check ();
|
||||
switch (m_kind)
|
||||
value_range::verify_range ();
|
||||
switch (kind ())
|
||||
{
|
||||
case VR_UNDEFINED:
|
||||
case VR_VARYING:
|
||||
|
@ -206,8 +206,9 @@ value_range_equiv::intersect (const value_range_equiv *other)
|
|||
this->deep_copy (other);
|
||||
else
|
||||
{
|
||||
value_range tem = intersect_helper (this, other);
|
||||
this->update (tem.min (), tem.max (), tem.kind ());
|
||||
legacy_intersect (this, other);
|
||||
if (varying_p () || undefined_p ())
|
||||
equiv_clear ();
|
||||
|
||||
/* If the result is VR_UNDEFINED there is no need to mess with
|
||||
equivalencies. */
|
||||
|
@ -254,8 +255,9 @@ value_range_equiv::union_ (const value_range_equiv *other)
|
|||
this->deep_copy (other);
|
||||
else
|
||||
{
|
||||
value_range tem = union_helper (this, other);
|
||||
this->update (tem.min (), tem.max (), tem.kind ());
|
||||
legacy_union (this, other);
|
||||
if (varying_p () || undefined_p ())
|
||||
equiv_clear ();
|
||||
|
||||
/* The resulting set of equivalences is always the intersection of
|
||||
the two sets. */
|
||||
|
@ -277,7 +279,7 @@ void
|
|||
value_range_equiv::dump (FILE *file) const
|
||||
{
|
||||
value_range::dump (file);
|
||||
if ((m_kind == VR_RANGE || m_kind == VR_ANTI_RANGE)
|
||||
if ((kind () == VR_RANGE || kind () == VR_ANTI_RANGE)
|
||||
&& m_equiv)
|
||||
{
|
||||
bitmap_iterator bi;
|
||||
|
|
1342
gcc/value-range.cc
1342
gcc/value-range.cc
File diff suppressed because it is too large
Load diff
|
@ -1,5 +1,7 @@
|
|||
/* Support routines for value ranges.
|
||||
Copyright (C) 2019-2020 Free Software Foundation, Inc.
|
||||
Contributed by Aldy Hernandez <aldyh@redhat.com> and
|
||||
Andrew Macleod <amacleod@redhat.com>.
|
||||
|
||||
This file is part of GCC.
|
||||
|
||||
|
@ -20,7 +22,7 @@ along with GCC; see the file COPYING3. If not see
|
|||
#ifndef GCC_VALUE_RANGE_H
|
||||
#define GCC_VALUE_RANGE_H
|
||||
|
||||
/* Types of value ranges. */
|
||||
// Types of value ranges.
|
||||
enum value_range_kind
|
||||
{
|
||||
/* Empty range. */
|
||||
|
@ -36,164 +38,292 @@ enum value_range_kind
|
|||
};
|
||||
|
||||
// Range of values that can be associated with an SSA_NAME.
|
||||
//
|
||||
// This is the base class without any storage.
|
||||
|
||||
class GTY((for_user)) value_range
|
||||
class irange
|
||||
{
|
||||
public:
|
||||
value_range ();
|
||||
value_range (tree, tree, value_range_kind = VR_RANGE);
|
||||
value_range (tree type, const wide_int &, const wide_int &,
|
||||
value_range_kind = VR_RANGE);
|
||||
value_range (tree type);
|
||||
|
||||
// In-place setters.
|
||||
void set (tree, tree, value_range_kind = VR_RANGE);
|
||||
void set (tree);
|
||||
void set_nonzero (tree);
|
||||
void set_zero (tree);
|
||||
|
||||
enum value_range_kind kind () const;
|
||||
tree min () const;
|
||||
tree max () const;
|
||||
|
||||
/* Types of value ranges. */
|
||||
bool symbolic_p () const;
|
||||
bool constant_p () const;
|
||||
bool undefined_p () const;
|
||||
bool varying_p () const;
|
||||
void set_varying (tree type);
|
||||
void set_undefined ();
|
||||
|
||||
void union_ (const value_range *);
|
||||
void intersect (const value_range *);
|
||||
void union_ (const value_range &);
|
||||
void intersect (const value_range &);
|
||||
|
||||
bool operator== (const value_range &) const;
|
||||
bool operator!= (const value_range &) const /* = delete */;
|
||||
bool equal_p (const value_range &) const;
|
||||
|
||||
/* Misc methods. */
|
||||
tree type () const;
|
||||
bool may_contain_p (tree) const;
|
||||
bool zero_p () const;
|
||||
bool nonzero_p () const;
|
||||
bool singleton_p (tree *result = NULL) const;
|
||||
void dump (FILE *) const;
|
||||
void dump () const;
|
||||
|
||||
// Range types.
|
||||
static bool supports_type_p (tree);
|
||||
void normalize_symbolics ();
|
||||
void normalize_addresses ();
|
||||
tree type () const;
|
||||
|
||||
static const unsigned int m_max_pairs = 2;
|
||||
bool contains_p (tree) const;
|
||||
// Iteration over sub-ranges.
|
||||
unsigned num_pairs () const;
|
||||
wide_int lower_bound (unsigned = 0) const;
|
||||
wide_int upper_bound (unsigned) const;
|
||||
wide_int upper_bound () const;
|
||||
|
||||
// Predicates.
|
||||
bool zero_p () const;
|
||||
bool nonzero_p () const;
|
||||
bool undefined_p () const;
|
||||
bool varying_p () const;
|
||||
bool singleton_p (tree *result = NULL) const;
|
||||
bool contains_p (tree) const;
|
||||
|
||||
// In-place operators.
|
||||
void union_ (const irange &);
|
||||
void intersect (const irange &);
|
||||
void invert ();
|
||||
|
||||
// Operator overloads.
|
||||
irange& operator= (const irange &);
|
||||
bool operator== (const irange &) const;
|
||||
bool operator!= (const irange &r) const { return !(*this == r); }
|
||||
|
||||
// Misc methods.
|
||||
void dump (FILE * = stderr) const;
|
||||
|
||||
// Deprecated legacy public methods.
|
||||
enum value_range_kind kind () const; // DEPRECATED
|
||||
tree min () const; // DEPRECATED
|
||||
tree max () const; // DEPRECATED
|
||||
bool symbolic_p () const; // DEPRECATED
|
||||
bool constant_p () const; // DEPRECATED
|
||||
void normalize_symbolics (); // DEPRECATED
|
||||
void normalize_addresses (); // DEPRECATED
|
||||
bool may_contain_p (tree) const; // DEPRECATED
|
||||
void set (tree); // DEPRECATED
|
||||
bool equal_p (const irange &) const; // DEPRECATED
|
||||
void union_ (const class irange *); // DEPRECATED
|
||||
void intersect (const irange *); // DEPRECATED
|
||||
|
||||
protected:
|
||||
void check ();
|
||||
static value_range union_helper (const value_range *, const value_range *);
|
||||
static value_range intersect_helper (const value_range *,
|
||||
const value_range *);
|
||||
irange (tree *, unsigned);
|
||||
// potential promotion to public?
|
||||
tree tree_lower_bound (unsigned = 0) const;
|
||||
tree tree_upper_bound (unsigned) const;
|
||||
tree tree_upper_bound () const;
|
||||
|
||||
friend void gt_ggc_mx_value_range (void *);
|
||||
friend void gt_pch_p_11value_range (void *, void *,
|
||||
gt_pointer_operator, void *);
|
||||
friend void gt_pch_nx_value_range (void *);
|
||||
friend void gt_ggc_mx (value_range &);
|
||||
friend void gt_ggc_mx (value_range *&);
|
||||
friend void gt_pch_nx (value_range &);
|
||||
friend void gt_pch_nx (value_range *, gt_pointer_operator, void *);
|
||||
// In-place operators.
|
||||
void irange_union (const irange &);
|
||||
void irange_intersect (const irange &);
|
||||
void irange_set (tree, tree);
|
||||
void irange_set_anti_range (tree, tree);
|
||||
|
||||
enum value_range_kind m_kind;
|
||||
tree m_min;
|
||||
tree m_max;
|
||||
bool swap_out_of_order_endpoints (tree &min, tree &max, value_range_kind &);
|
||||
bool normalize_min_max (tree type, tree min, tree max, value_range_kind);
|
||||
|
||||
bool legacy_mode_p () const;
|
||||
bool legacy_equal_p (const irange &) const;
|
||||
void legacy_union (irange *, const irange *);
|
||||
void legacy_intersect (irange *, const irange *);
|
||||
void verify_range ();
|
||||
unsigned legacy_num_pairs () const;
|
||||
wide_int legacy_lower_bound (unsigned = 0) const;
|
||||
wide_int legacy_upper_bound (unsigned) const;
|
||||
int value_inside_range (tree) const;
|
||||
bool maybe_anti_range () const;
|
||||
void copy_legacy_range (const irange &);
|
||||
|
||||
private:
|
||||
int value_inside_range (tree) const;
|
||||
unsigned char m_num_ranges;
|
||||
unsigned char m_max_ranges;
|
||||
ENUM_BITFIELD(value_range_kind) m_kind : 8;
|
||||
tree *m_base;
|
||||
};
|
||||
|
||||
extern bool range_has_numeric_bounds_p (const value_range *);
|
||||
// Here we describe an irange with N pairs of ranges. The storage for
|
||||
// the pairs is embedded in the class as an array.
|
||||
|
||||
template<unsigned N>
|
||||
class GTY((user)) int_range : public irange
|
||||
{
|
||||
public:
|
||||
int_range ();
|
||||
int_range (tree, tree, value_range_kind = VR_RANGE);
|
||||
int_range (tree type, const wide_int &, const wide_int &,
|
||||
value_range_kind = VR_RANGE);
|
||||
int_range (tree type);
|
||||
int_range (const int_range &);
|
||||
int_range (const irange &);
|
||||
int_range& operator= (const int_range &);
|
||||
private:
|
||||
template <unsigned X> friend void gt_ggc_mx (int_range<X> *);
|
||||
template <unsigned X> friend void gt_pch_nx (int_range<X> *);
|
||||
template <unsigned X> friend void gt_pch_nx (int_range<X> *,
|
||||
gt_pointer_operator, void *);
|
||||
// ?? hash-traits.h has its own extern for these, which is causing
|
||||
// them to never be picked up by the templates. For now, define
|
||||
// elsewhere.
|
||||
//template<unsigned X> friend void gt_ggc_mx (int_range<X> *&);
|
||||
//template<unsigned X> friend void gt_pch_nx (int_range<X> *&);
|
||||
friend void gt_ggc_mx (int_range<1> *&);
|
||||
friend void gt_pch_nx (int_range<1> *&);
|
||||
|
||||
tree m_ranges[N*2];
|
||||
};
|
||||
|
||||
// This is a special int_range<1> with only one pair, plus
|
||||
// VR_ANTI_RANGE magic to describe slightly more than can be described
|
||||
// in one pair. It is described in the code as a "legacy range" (as
|
||||
// opposed to multi-ranges which have multiple sub-ranges). It is
|
||||
// provided for backward compatibility with code that has not been
|
||||
// converted to multi-range irange's.
|
||||
//
|
||||
// There are copy operators to seamlessly copy to/fro multi-ranges.
|
||||
typedef int_range<1> value_range;
|
||||
|
||||
// This is an "infinite" precision irange for use in temporary
|
||||
// calculations.
|
||||
typedef int_range<255> widest_irange;
|
||||
|
||||
// Returns true for an old-school value_range as described above.
|
||||
inline bool
|
||||
irange::legacy_mode_p () const
|
||||
{
|
||||
return m_max_ranges == 1;
|
||||
}
|
||||
|
||||
extern bool range_has_numeric_bounds_p (const irange *);
|
||||
extern bool ranges_from_anti_range (const value_range *,
|
||||
value_range *, value_range *);
|
||||
extern void dump_value_range (FILE *, const value_range *);
|
||||
extern void dump_value_range (FILE *, const irange *);
|
||||
extern bool vrp_val_is_min (const_tree);
|
||||
extern bool vrp_val_is_max (const_tree);
|
||||
extern tree vrp_val_min (const_tree);
|
||||
extern tree vrp_val_max (const_tree);
|
||||
extern bool vrp_operand_equal_p (const_tree, const_tree);
|
||||
|
||||
inline
|
||||
value_range::value_range ()
|
||||
{
|
||||
m_kind = VR_UNDEFINED;
|
||||
m_min = m_max = NULL;
|
||||
}
|
||||
|
||||
inline value_range_kind
|
||||
value_range::kind () const
|
||||
irange::kind () const
|
||||
{
|
||||
return m_kind;
|
||||
if (legacy_mode_p ())
|
||||
return m_kind;
|
||||
|
||||
if (undefined_p ())
|
||||
return VR_UNDEFINED;
|
||||
|
||||
if (varying_p ())
|
||||
return VR_VARYING;
|
||||
|
||||
return VR_RANGE;
|
||||
}
|
||||
|
||||
// Number of sub-ranges in a range.
|
||||
|
||||
inline unsigned
|
||||
irange::num_pairs () const
|
||||
{
|
||||
if (!legacy_mode_p ())
|
||||
return m_num_ranges;
|
||||
else
|
||||
return legacy_num_pairs ();
|
||||
}
|
||||
|
||||
inline tree
|
||||
value_range::type () const
|
||||
irange::type () const
|
||||
{
|
||||
return TREE_TYPE (min ());
|
||||
gcc_checking_assert (!undefined_p ());
|
||||
return TREE_TYPE (m_base[0]);
|
||||
}
|
||||
|
||||
// Return the lower bound of a sub-range expressed as a tree. PAIR is
|
||||
// the sub-range in question.
|
||||
|
||||
inline tree
|
||||
irange::tree_lower_bound (unsigned pair) const
|
||||
{
|
||||
return m_base[pair * 2];
|
||||
}
|
||||
|
||||
// Return the upper bound of a sub-range expressed as a tree. PAIR is
|
||||
// the sub-range in question.
|
||||
|
||||
inline tree
|
||||
irange::tree_upper_bound (unsigned pair) const
|
||||
{
|
||||
return m_base[pair * 2 + 1];
|
||||
}
|
||||
|
||||
// Return the highest bound of a range expressed as a tree.
|
||||
|
||||
inline tree
|
||||
irange::tree_upper_bound () const
|
||||
{
|
||||
gcc_checking_assert (m_num_ranges);
|
||||
return tree_upper_bound (m_num_ranges - 1);
|
||||
}
|
||||
|
||||
inline tree
|
||||
value_range::min () const
|
||||
irange::min () const
|
||||
{
|
||||
return m_min;
|
||||
return tree_lower_bound (0);
|
||||
}
|
||||
|
||||
inline tree
|
||||
value_range::max () const
|
||||
irange::max () const
|
||||
{
|
||||
return m_max;
|
||||
if (m_num_ranges)
|
||||
return tree_upper_bound ();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
inline bool
|
||||
value_range::varying_p () const
|
||||
irange::varying_p () const
|
||||
{
|
||||
return m_kind == VR_VARYING;
|
||||
if (legacy_mode_p ())
|
||||
return m_kind == VR_VARYING;
|
||||
|
||||
if (m_num_ranges != 1)
|
||||
return false;
|
||||
|
||||
tree l = m_base[0];
|
||||
tree u = m_base[1];
|
||||
tree t = TREE_TYPE (l);
|
||||
if (INTEGRAL_TYPE_P (t))
|
||||
return l == TYPE_MIN_VALUE (t) && u == TYPE_MAX_VALUE (t);
|
||||
if (POINTER_TYPE_P (t))
|
||||
return wi::to_wide (l) == 0
|
||||
&& wi::to_wide (u) == wi::max_value (TYPE_PRECISION (t),
|
||||
TYPE_SIGN (t));
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
inline bool
|
||||
value_range::undefined_p () const
|
||||
irange::undefined_p () const
|
||||
{
|
||||
if (!legacy_mode_p ())
|
||||
return m_num_ranges == 0;
|
||||
|
||||
if (CHECKING_P && legacy_mode_p ())
|
||||
{
|
||||
if (m_kind == VR_UNDEFINED)
|
||||
gcc_checking_assert (m_num_ranges == 0);
|
||||
else
|
||||
gcc_checking_assert (m_num_ranges != 0);
|
||||
}
|
||||
return m_kind == VR_UNDEFINED;
|
||||
}
|
||||
|
||||
inline bool
|
||||
value_range::zero_p () const
|
||||
irange::zero_p () const
|
||||
{
|
||||
return (m_kind == VR_RANGE
|
||||
&& integer_zerop (m_min)
|
||||
&& integer_zerop (m_max));
|
||||
return (m_kind == VR_RANGE && m_num_ranges == 1
|
||||
&& integer_zerop (tree_lower_bound (0))
|
||||
&& integer_zerop (tree_upper_bound (0)));
|
||||
}
|
||||
|
||||
inline bool
|
||||
value_range::nonzero_p () const
|
||||
irange::nonzero_p () const
|
||||
{
|
||||
if (m_kind == VR_ANTI_RANGE
|
||||
&& !TYPE_UNSIGNED (type ())
|
||||
&& integer_zerop (m_min)
|
||||
&& integer_zerop (m_max))
|
||||
return true;
|
||||
if (undefined_p ())
|
||||
return false;
|
||||
|
||||
return (m_kind == VR_RANGE
|
||||
&& TYPE_UNSIGNED (type ())
|
||||
&& integer_onep (m_min)
|
||||
&& vrp_val_is_max (m_max));
|
||||
tree zero = build_zero_cst (type ());
|
||||
return *this == int_range<1> (zero, zero, VR_ANTI_RANGE);
|
||||
}
|
||||
|
||||
inline bool
|
||||
value_range::supports_type_p (tree type)
|
||||
irange::supports_type_p (tree type)
|
||||
{
|
||||
if (type && (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)))
|
||||
return type;
|
||||
|
@ -201,7 +331,7 @@ value_range::supports_type_p (tree type)
|
|||
}
|
||||
|
||||
inline bool
|
||||
range_includes_zero_p (const value_range *vr)
|
||||
range_includes_zero_p (const irange *vr)
|
||||
{
|
||||
if (vr->undefined_p ())
|
||||
return false;
|
||||
|
@ -212,4 +342,281 @@ range_includes_zero_p (const value_range *vr)
|
|||
return vr->may_contain_p (build_zero_cst (vr->type ()));
|
||||
}
|
||||
|
||||
template<unsigned N>
|
||||
static inline void
|
||||
gt_ggc_mx (int_range<N> *x)
|
||||
{
|
||||
for (unsigned i = 0; i < N; ++i)
|
||||
{
|
||||
gt_ggc_mx (x->m_ranges[i * 2]);
|
||||
gt_ggc_mx (x->m_ranges[i * 2 + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned N>
|
||||
static inline void
|
||||
gt_pch_nx (int_range<N> *x)
|
||||
{
|
||||
for (unsigned i = 0; i < N; ++i)
|
||||
{
|
||||
gt_pch_nx (x->m_ranges[i * 2]);
|
||||
gt_pch_nx (x->m_ranges[i * 2 + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
template<unsigned N>
|
||||
static inline void
|
||||
gt_pch_nx (int_range<N> *x, gt_pointer_operator op, void *cookie)
|
||||
{
|
||||
for (unsigned i = 0; i < N; ++i)
|
||||
{
|
||||
op (&x->m_ranges[i * 2], cookie);
|
||||
op (&x->m_ranges[i * 2 + 1], cookie);
|
||||
}
|
||||
}
|
||||
|
||||
// Constructors for irange
|
||||
|
||||
inline
|
||||
irange::irange (tree *base, unsigned nranges)
|
||||
{
|
||||
m_base = base;
|
||||
m_num_ranges = 0;
|
||||
m_max_ranges = nranges;
|
||||
if (legacy_mode_p ())
|
||||
m_kind = VR_UNDEFINED;
|
||||
else
|
||||
m_kind = VR_RANGE;
|
||||
}
|
||||
|
||||
// Constructors for int_range<>.
|
||||
|
||||
template<unsigned N>
|
||||
inline
|
||||
int_range<N>::int_range ()
|
||||
: irange (m_ranges, N)
|
||||
{
|
||||
}
|
||||
|
||||
template<unsigned N>
|
||||
int_range<N>::int_range (const int_range &other)
|
||||
: irange (m_ranges, N)
|
||||
{
|
||||
irange::operator= (other);
|
||||
}
|
||||
|
||||
template<unsigned N>
|
||||
int_range<N>::int_range (tree min, tree max, value_range_kind kind)
|
||||
: irange (m_ranges, N)
|
||||
{
|
||||
irange::set (min, max, kind);
|
||||
}
|
||||
|
||||
template<unsigned N>
|
||||
int_range<N>::int_range (tree type)
|
||||
: irange (m_ranges, N)
|
||||
{
|
||||
set_varying (type);
|
||||
}
|
||||
|
||||
template<unsigned N>
|
||||
int_range<N>::int_range (tree type, const wide_int &wmin, const wide_int &wmax,
|
||||
value_range_kind kind)
|
||||
: irange (m_ranges, N)
|
||||
{
|
||||
tree min = wide_int_to_tree (type, wmin);
|
||||
tree max = wide_int_to_tree (type, wmax);
|
||||
set (min, max, kind);
|
||||
}
|
||||
|
||||
template<unsigned N>
|
||||
int_range<N>::int_range (const irange &other)
|
||||
: irange (m_ranges, N)
|
||||
{
|
||||
irange::operator= (other);
|
||||
}
|
||||
|
||||
template<unsigned N>
|
||||
int_range<N>&
|
||||
int_range<N>::operator= (const int_range &src)
|
||||
{
|
||||
irange::operator= (src);
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void
|
||||
irange::set (tree val)
|
||||
{
|
||||
set (val, val);
|
||||
}
|
||||
|
||||
inline void
|
||||
irange::set_undefined ()
|
||||
{
|
||||
m_num_ranges = 0;
|
||||
if (legacy_mode_p ())
|
||||
m_kind = VR_UNDEFINED;
|
||||
}
|
||||
|
||||
inline void
|
||||
irange::set_varying (tree type)
|
||||
{
|
||||
if (legacy_mode_p ())
|
||||
m_kind = VR_VARYING;
|
||||
|
||||
m_num_ranges = 1;
|
||||
if (INTEGRAL_TYPE_P (type))
|
||||
{
|
||||
m_base[0] = TYPE_MIN_VALUE (type);
|
||||
m_base[1] = TYPE_MAX_VALUE (type);
|
||||
}
|
||||
else if (POINTER_TYPE_P (type))
|
||||
{
|
||||
m_base[0] = build_int_cst (type, 0);
|
||||
m_base[1] = build_int_cst (type, -1);
|
||||
}
|
||||
else
|
||||
m_base[0] = m_base[1] = error_mark_node;
|
||||
}
|
||||
|
||||
inline bool
|
||||
irange::operator== (const irange &r) const
|
||||
{
|
||||
return equal_p (r);
|
||||
}
|
||||
|
||||
// Return the lower bound of a sub-range. PAIR is the sub-range in
|
||||
// question.
|
||||
|
||||
inline wide_int
|
||||
irange::lower_bound (unsigned pair) const
|
||||
{
|
||||
if (legacy_mode_p ())
|
||||
return legacy_lower_bound (pair);
|
||||
gcc_checking_assert (!undefined_p ());
|
||||
gcc_checking_assert (pair + 1 <= num_pairs ());
|
||||
return wi::to_wide (tree_lower_bound (pair));
|
||||
}
|
||||
|
||||
// Return the upper bound of a sub-range. PAIR is the sub-range in
|
||||
// question.
|
||||
|
||||
inline wide_int
|
||||
irange::upper_bound (unsigned pair) const
|
||||
{
|
||||
if (legacy_mode_p ())
|
||||
return legacy_upper_bound (pair);
|
||||
gcc_checking_assert (!undefined_p ());
|
||||
gcc_checking_assert (pair + 1 <= num_pairs ());
|
||||
return wi::to_wide (tree_upper_bound (pair));
|
||||
}
|
||||
|
||||
// Return the highest bound of a range.
|
||||
|
||||
inline wide_int
|
||||
irange::upper_bound () const
|
||||
{
|
||||
unsigned pairs = num_pairs ();
|
||||
gcc_checking_assert (pairs > 0);
|
||||
return upper_bound (pairs - 1);
|
||||
}
|
||||
|
||||
inline void
|
||||
irange::union_ (const irange &r)
|
||||
{
|
||||
dump_flags_t m_flags = dump_flags;
|
||||
dump_flags &= ~TDF_DETAILS;
|
||||
irange::union_ (&r);
|
||||
dump_flags = m_flags;
|
||||
}
|
||||
|
||||
inline void
|
||||
irange::intersect (const irange &r)
|
||||
{
|
||||
dump_flags_t m_flags = dump_flags;
|
||||
dump_flags &= ~TDF_DETAILS;
|
||||
irange::intersect (&r);
|
||||
dump_flags = m_flags;
|
||||
}
|
||||
|
||||
// Set value range VR to a nonzero range of type TYPE.
|
||||
|
||||
inline void
|
||||
irange::set_nonzero (tree type)
|
||||
{
|
||||
tree zero = build_int_cst (type, 0);
|
||||
if (legacy_mode_p ())
|
||||
set (zero, zero, VR_ANTI_RANGE);
|
||||
else
|
||||
irange_set_anti_range (zero, zero);
|
||||
}
|
||||
|
||||
// Set value range VR to a ZERO range of type TYPE.
|
||||
|
||||
inline void
|
||||
irange::set_zero (tree type)
|
||||
{
|
||||
tree z = build_int_cst (type, 0);
|
||||
if (legacy_mode_p ())
|
||||
set (z);
|
||||
else
|
||||
irange_set (z, z);
|
||||
}
|
||||
|
||||
// Normalize [MIN, MAX] into VARYING and ~[MIN, MAX] into UNDEFINED.
|
||||
//
|
||||
// Avoid using TYPE_{MIN,MAX}_VALUE because -fstrict-enums can
|
||||
// restrict those to a subset of what actually fits in the type.
|
||||
// Instead use the extremes of the type precision which will allow
|
||||
// compare_range_with_value() to check if a value is inside a range,
|
||||
// whereas if we used TYPE_*_VAL, said function would just punt upon
|
||||
// seeing a VARYING.
|
||||
|
||||
inline bool
|
||||
irange::normalize_min_max (tree type, tree min, tree max,
|
||||
value_range_kind kind)
|
||||
{
|
||||
unsigned prec = TYPE_PRECISION (type);
|
||||
signop sign = TYPE_SIGN (type);
|
||||
if (wi::eq_p (wi::to_wide (min), wi::min_value (prec, sign))
|
||||
&& wi::eq_p (wi::to_wide (max), wi::max_value (prec, sign)))
|
||||
{
|
||||
if (kind == VR_RANGE)
|
||||
set_varying (type);
|
||||
else if (kind == VR_ANTI_RANGE)
|
||||
set_undefined ();
|
||||
else
|
||||
gcc_unreachable ();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return the maximum value for TYPE.
|
||||
|
||||
inline tree
|
||||
vrp_val_max (const_tree type)
|
||||
{
|
||||
if (INTEGRAL_TYPE_P (type))
|
||||
return TYPE_MAX_VALUE (type);
|
||||
if (POINTER_TYPE_P (type))
|
||||
{
|
||||
wide_int max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type));
|
||||
return wide_int_to_tree (const_cast<tree> (type), max);
|
||||
}
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
// Return the minimum value for TYPE.
|
||||
|
||||
inline tree
|
||||
vrp_val_min (const_tree type)
|
||||
{
|
||||
if (INTEGRAL_TYPE_P (type))
|
||||
return TYPE_MIN_VALUE (type);
|
||||
if (POINTER_TYPE_P (type))
|
||||
return build_zero_cst (const_cast<tree> (type));
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
#endif // GCC_VALUE_RANGE_H
|
||||
|
|
|
@ -92,7 +92,8 @@ vr_values::get_lattice_entry (const_tree var)
|
|||
return vr;
|
||||
|
||||
/* Create a default value range. */
|
||||
vr_value[ver] = vr = vrp_value_range_pool.allocate ();
|
||||
vr = new (vrp_value_range_pool.allocate ()) value_range_equiv;
|
||||
vr_value[ver] = vr;
|
||||
|
||||
/* After propagation finished return varying. */
|
||||
if (values_propagated)
|
||||
|
|
Loading…
Add table
Reference in a new issue