From 4ba9fb0a3e65254cb5d8cb0a3bc67bbef8ed2fcf Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Thu, 30 Jul 2020 11:30:18 +0200 Subject: 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. --- gcc/value-range.h | 597 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 502 insertions(+), 95 deletions(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index 0a9dc6f..e3282c4 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -1,5 +1,7 @@ /* Support routines for value ranges. Copyright (C) 2019-2020 Free Software Foundation, Inc. + Contributed by Aldy Hernandez and + Andrew Macleod . 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 *); - - 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 *); - - enum value_range_kind m_kind; - tree m_min; - tree m_max; + 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; + + // 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); + + 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 +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 friend void gt_ggc_mx (int_range *); + template friend void gt_pch_nx (int_range *); + template friend void gt_pch_nx (int_range *, + 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 friend void gt_ggc_mx (int_range *&); + //template friend void gt_pch_nx (int_range *&); + 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 () +inline value_range_kind +irange::kind () const +{ + 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 { - m_kind = VR_UNDEFINED; - m_min = m_max = NULL; + if (!legacy_mode_p ()) + return m_num_ranges; + else + return legacy_num_pairs (); } -inline value_range_kind -value_range::kind () const +inline tree +irange::type () const +{ + 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_kind; + return m_base[pair * 2 + 1]; } +// Return the highest bound of a range expressed as a tree. + inline tree -value_range::type () const +irange::tree_upper_bound () const { - return TREE_TYPE (min ()); + 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 +static inline void +gt_ggc_mx (int_range *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 +static inline void +gt_pch_nx (int_range *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 +static inline void +gt_pch_nx (int_range *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 +inline +int_range::int_range () + : irange (m_ranges, N) +{ +} + +template +int_range::int_range (const int_range &other) + : irange (m_ranges, N) +{ + irange::operator= (other); +} + +template +int_range::int_range (tree min, tree max, value_range_kind kind) + : irange (m_ranges, N) +{ + irange::set (min, max, kind); +} + +template +int_range::int_range (tree type) + : irange (m_ranges, N) +{ + set_varying (type); +} + +template +int_range::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 +int_range::int_range (const irange &other) + : irange (m_ranges, N) +{ + irange::operator= (other); +} + +template +int_range& +int_range::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 (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 (type)); + return NULL_TREE; +} + #endif // GCC_VALUE_RANGE_H -- cgit v1.1