diff options
Diffstat (limited to 'lib/gcc/arm-none-eabi/13.2.1/plugin/include/value-range.h')
-rw-r--r-- | lib/gcc/arm-none-eabi/13.2.1/plugin/include/value-range.h | 1487 |
1 files changed, 1487 insertions, 0 deletions
diff --git a/lib/gcc/arm-none-eabi/13.2.1/plugin/include/value-range.h b/lib/gcc/arm-none-eabi/13.2.1/plugin/include/value-range.h new file mode 100644 index 0000000..96e59ec --- /dev/null +++ b/lib/gcc/arm-none-eabi/13.2.1/plugin/include/value-range.h @@ -0,0 +1,1487 @@ +/* Support routines for value ranges. + Copyright (C) 2019-2023 Free Software Foundation, Inc. + Contributed by Aldy Hernandez <aldyh@redhat.com> and + Andrew Macleod <amacleod@redhat.com>. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#ifndef GCC_VALUE_RANGE_H +#define GCC_VALUE_RANGE_H + +class irange; + +// Types of value ranges. +enum value_range_kind +{ + /* Empty range. */ + VR_UNDEFINED, + /* Range spans the entire domain. */ + VR_VARYING, + /* Range is [MIN, MAX]. */ + VR_RANGE, + /* Range is ~[MIN, MAX]. */ + VR_ANTI_RANGE, + /* Range is a NAN. */ + VR_NAN, + /* Range is a nice guy. */ + VR_LAST +}; + +// Discriminator between different vrange types. + +enum value_range_discriminator +{ + // Range holds an integer or pointer. + VR_IRANGE, + // Floating point range. + VR_FRANGE, + // Range holds an unsupported type. + VR_UNKNOWN +}; + +// Abstract class for ranges of any of the supported types. +// +// To query what types ranger and the entire ecosystem can support, +// use Value_Range::supports_type_p(tree type). This is a static +// method available independently of any vrange object. +// +// To query what a given vrange variant can support, use: +// irange::supports_p () +// frange::supports_p () +// etc +// +// To query what a range object can support, use: +// void foo (vrange &v, irange &i, frange &f) +// { +// if (v.supports_type_p (type)) ... +// if (i.supports_type_p (type)) ... +// if (f.supports_type_p (type)) ... +// } + +class vrange +{ + template <typename T> friend bool is_a (vrange &); + friend class Value_Range; +public: + virtual void accept (const class vrange_visitor &v) const = 0; + virtual void set (tree, tree, value_range_kind = VR_RANGE); + virtual tree type () const; + virtual bool supports_type_p (const_tree type) const; + virtual void set_varying (tree type); + virtual void set_undefined (); + virtual bool union_ (const vrange &); + virtual bool intersect (const vrange &); + virtual bool singleton_p (tree *result = NULL) const; + virtual bool contains_p (tree cst) const; + virtual bool zero_p () const; + virtual bool nonzero_p () const; + virtual void set_nonzero (tree type); + virtual void set_zero (tree type); + virtual void set_nonnegative (tree type); + virtual bool fits_p (const vrange &r) const; + + bool varying_p () const; + bool undefined_p () const; + vrange& operator= (const vrange &); + bool operator== (const vrange &) const; + bool operator!= (const vrange &r) const { return !(*this == r); } + void dump (FILE *) const; + + enum value_range_kind kind () const; // DEPRECATED + +protected: + ENUM_BITFIELD(value_range_kind) m_kind : 8; + ENUM_BITFIELD(value_range_discriminator) m_discriminator : 4; +}; + +// An integer range without any storage. + +class GTY((user)) irange : public vrange +{ + friend class vrange_allocator; + friend class irange_storage_slot; // For legacy_mode_p checks. +public: + // In-place setters. + virtual void set (tree, tree, value_range_kind = VR_RANGE) override; + void set (tree type, const wide_int_ref &, const wide_int_ref &, + value_range_kind = VR_RANGE); + virtual void set_nonzero (tree type) override; + virtual void set_zero (tree type) override; + virtual void set_nonnegative (tree type) override; + virtual void set_varying (tree type) override; + virtual void set_undefined () override; + + // Range types. + static bool supports_p (const_tree type); + virtual bool supports_type_p (const_tree type) const override; + virtual tree type () const override; + + // 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. + virtual bool zero_p () const override; + virtual bool nonzero_p () const override; + virtual bool singleton_p (tree *result = NULL) const override; + virtual bool contains_p (tree cst) const override; + + // In-place operators. + virtual bool union_ (const vrange &) override; + virtual bool intersect (const vrange &) override; + void invert (); + + // Operator overloads. + irange& operator= (const irange &); + bool operator== (const irange &) const; + bool operator!= (const irange &r) const { return !(*this == r); } + + // Misc methods. + virtual bool fits_p (const vrange &r) const override; + virtual void accept (const vrange_visitor &v) const override; + + // Nonzero masks. + wide_int get_nonzero_bits () const; + void set_nonzero_bits (const wide_int_ref &bits); + + // Deprecated legacy public methods. + 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 + bool legacy_verbose_union_ (const class irange *); // DEPRECATED + bool legacy_verbose_intersect (const irange *); // DEPRECATED + +protected: + void maybe_resize (int needed); + irange (tree *, unsigned nranges, bool resizable); + // 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. + bool irange_union (const irange &); + bool irange_intersect (const irange &); + void irange_set (tree, tree); + void irange_set_anti_range (tree, tree); + bool irange_contains_p (const irange &) const; + bool irange_single_pair_union (const irange &r); + + void normalize_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 (); + 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_to_legacy (const irange &); + void copy_legacy_to_multi_range (const irange &); + + // Hard limit on max ranges allowed. + static const int HARD_MAX_RANGES = 255; +private: + friend void gt_ggc_mx (irange *); + friend void gt_pch_nx (irange *); + friend void gt_pch_nx (irange *, gt_pointer_operator, void *); + + void irange_set_1bit_anti_range (tree, tree); + bool varying_compatible_p () const; + bool intersect_nonzero_bits (const irange &r); + bool union_nonzero_bits (const irange &r); + wide_int get_nonzero_bits_from_range () const; + bool set_range_from_nonzero_bits (); + + bool intersect (const wide_int& lb, const wide_int& ub); + unsigned char m_num_ranges; + bool m_resizable; + unsigned char m_max_ranges; + tree m_nonzero_mask; +protected: + tree *m_base; +}; + +// Here we describe an irange with N pairs of ranges. The storage for +// the pairs is embedded in the class as an array. +// +// If RESIZABLE is true, the storage will be resized on the heap when +// the number of ranges needed goes past N up to a max of +// HARD_MAX_RANGES. This new storage is freed upon destruction. + +template<unsigned N, bool RESIZABLE = false> +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 &); + virtual ~int_range (); + 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 *); + + // ?? These stubs are for ipa-prop.cc which use a value_range in a + // hash_traits. hash-traits.h defines an extern of gt_ggc_mx (T &) + // instead of picking up the gt_ggc_mx (T *) version. + friend void gt_ggc_mx (int_range<1> *&); + friend void gt_pch_nx (int_range<1> *&); + + tree m_ranges[N*2]; +}; + +// Unsupported temporaries may be created by ranger before it's known +// they're unsupported, or by vr_values::get_value_range. + +class unsupported_range : public vrange +{ +public: + unsupported_range () + { + m_discriminator = VR_UNKNOWN; + set_undefined (); + } + virtual void set_undefined () final override + { + m_kind = VR_UNDEFINED; + } + virtual void accept (const vrange_visitor &v) const override; +}; + +// The NAN state as an opaque object. The default constructor is +-NAN. + +class nan_state +{ +public: + nan_state (); + nan_state (bool pos_nan, bool neg_nan); + bool neg_p () const; + bool pos_p () const; +private: + bool m_pos_nan; + bool m_neg_nan; +}; + +// Default constructor initializing the object to +-NAN. + +inline +nan_state::nan_state () +{ + m_pos_nan = true; + m_neg_nan = true; +} + +// Constructor initializing the object to +NAN if POS_NAN is set, -NAN +// if NEG_NAN is set, or +-NAN if both are set. Otherwise POS_NAN and +// NEG_NAN are clear, and the object cannot be a NAN. + +inline +nan_state::nan_state (bool pos_nan, bool neg_nan) +{ + m_pos_nan = pos_nan; + m_neg_nan = neg_nan; +} + +// Return if +NAN is possible. + +inline bool +nan_state::pos_p () const +{ + return m_pos_nan; +} + +// Return if -NAN is possible. + +inline bool +nan_state::neg_p () const +{ + return m_neg_nan; +} + +// A floating point range. +// +// The representation is a type with a couple of endpoints, unioned +// with the set of { -NAN, +Nan }. + +class frange : public vrange +{ + friend class frange_storage_slot; + friend class vrange_printer; +public: + frange (); + frange (const frange &); + frange (tree, tree, value_range_kind = VR_RANGE); + frange (tree type); + frange (tree type, const REAL_VALUE_TYPE &min, const REAL_VALUE_TYPE &max, + value_range_kind = VR_RANGE); + static bool supports_p (const_tree type) + { + // ?? Decimal floats can have multiple representations for the + // same number. Supporting them may be as simple as just + // disabling them in singleton_p. No clue. + return SCALAR_FLOAT_TYPE_P (type) && !DECIMAL_FLOAT_TYPE_P (type); + } + virtual tree type () const override; + virtual void set (tree, tree, value_range_kind = VR_RANGE) override; + void set (tree type, const REAL_VALUE_TYPE &, const REAL_VALUE_TYPE &, + value_range_kind = VR_RANGE); + void set (tree type, const REAL_VALUE_TYPE &, const REAL_VALUE_TYPE &, + const nan_state &, value_range_kind = VR_RANGE); + void set_nan (tree type); + void set_nan (tree type, bool sign); + virtual void set_varying (tree type) override; + virtual void set_undefined () override; + virtual bool union_ (const vrange &) override; + virtual bool intersect (const vrange &) override; + virtual bool contains_p (tree) const override; + virtual bool singleton_p (tree *result = NULL) const override; + virtual bool supports_type_p (const_tree type) const override; + virtual void accept (const vrange_visitor &v) const override; + virtual bool zero_p () const override; + virtual bool nonzero_p () const override; + virtual void set_nonzero (tree type) override; + virtual void set_zero (tree type) override; + virtual void set_nonnegative (tree type) override; + frange& operator= (const frange &); + bool operator== (const frange &) const; + bool operator!= (const frange &r) const { return !(*this == r); } + const REAL_VALUE_TYPE &lower_bound () const; + const REAL_VALUE_TYPE &upper_bound () const; + nan_state get_nan_state () const; + void update_nan (); + void update_nan (bool sign); + void update_nan (tree) = delete; // Disallow silent conversion to bool. + void update_nan (const nan_state &); + void clear_nan (); + void flush_denormals_to_zero (); + + // fpclassify like API + bool known_isfinite () const; + bool known_isnan () const; + bool known_isinf () const; + bool maybe_isnan () const; + bool maybe_isnan (bool sign) const; + bool maybe_isinf () const; + bool signbit_p (bool &signbit) const; + bool nan_signbit_p (bool &signbit) const; +private: + void verify_range (); + bool normalize_kind (); + bool union_nans (const frange &); + bool intersect_nans (const frange &); + bool combine_zeros (const frange &, bool union_p); + + tree m_type; + REAL_VALUE_TYPE m_min; + REAL_VALUE_TYPE m_max; + bool m_pos_nan; + bool m_neg_nan; +}; + +inline const REAL_VALUE_TYPE & +frange::lower_bound () const +{ + gcc_checking_assert (!undefined_p () && !known_isnan ()); + return m_min; +} + +inline const REAL_VALUE_TYPE & +frange::upper_bound () const +{ + gcc_checking_assert (!undefined_p () && !known_isnan ()); + return m_max; +} + +// Return the NAN state. + +inline nan_state +frange::get_nan_state () const +{ + return nan_state (m_pos_nan, m_neg_nan); +} + +// is_a<> and as_a<> implementation for vrange. + +// Anything we haven't specialized is a hard fail. +template <typename T> +inline bool +is_a (vrange &) +{ + gcc_unreachable (); + return false; +} + +template <typename T> +inline bool +is_a (const vrange &v) +{ + // Reuse is_a <vrange> to implement the const version. + const T &derived = static_cast<const T &> (v); + return is_a <T> (const_cast<T &> (derived)); +} + +template <typename T> +inline T & +as_a (vrange &v) +{ + gcc_checking_assert (is_a <T> (v)); + return static_cast <T &> (v); +} + +template <typename T> +inline const T & +as_a (const vrange &v) +{ + gcc_checking_assert (is_a <T> (v)); + return static_cast <const T &> (v); +} + +// Specializations for the different range types. + +template <> +inline bool +is_a <irange> (vrange &v) +{ + return v.m_discriminator == VR_IRANGE; +} + +template <> +inline bool +is_a <frange> (vrange &v) +{ + return v.m_discriminator == VR_FRANGE; +} + +// For resizable ranges, resize the range up to HARD_MAX_RANGES if the +// NEEDED pairs is greater than the current capacity of the range. + +inline void +irange::maybe_resize (int needed) +{ + if (!m_resizable || m_max_ranges == HARD_MAX_RANGES) + return; + + if (needed > m_max_ranges) + { + m_max_ranges = HARD_MAX_RANGES; + tree *newmem = new tree[m_max_ranges * 2]; + memcpy (newmem, m_base, sizeof (tree) * num_pairs () * 2); + m_base = newmem; + } +} + +template<unsigned N, bool RESIZABLE> +inline +int_range<N, RESIZABLE>::~int_range () +{ + if (RESIZABLE && m_base != m_ranges) + delete m_base; +} + +// This is an "infinite" precision irange for use in temporary +// calculations. It starts with a sensible default covering 99% of +// uses, and goes up to HARD_MAX_RANGES when needed. Any allocated +// storage is freed upon destruction. +typedef int_range<3, /*RESIZABLE=*/true> int_range_max; + +class vrange_visitor +{ +public: + virtual void visit (const irange &) const { } + virtual void visit (const frange &) const { } + virtual void visit (const unsupported_range &) const { } +}; + +// 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 range object for use in temporary +// calculations for any of the handled types. The object can be +// transparently used as a vrange. + +class Value_Range +{ +public: + Value_Range (); + Value_Range (const vrange &r); + Value_Range (tree type); + Value_Range (const Value_Range &); + void set_type (tree type); + vrange& operator= (const vrange &); + bool operator== (const Value_Range &r) const; + bool operator!= (const Value_Range &r) const; + operator vrange &(); + operator const vrange &() const; + void dump (FILE *) const; + static bool supports_type_p (const_tree type); + + // Convenience methods for vrange compatibility. + void set (tree min, tree max, value_range_kind kind = VR_RANGE) + { return m_vrange->set (min, max, kind); } + tree type () { return m_vrange->type (); } + enum value_range_kind kind () { return m_vrange->kind (); } + bool varying_p () const { return m_vrange->varying_p (); } + bool undefined_p () const { return m_vrange->undefined_p (); } + void set_varying (tree type) { m_vrange->set_varying (type); } + void set_undefined () { m_vrange->set_undefined (); } + bool union_ (const vrange &r) { return m_vrange->union_ (r); } + bool intersect (const vrange &r) { return m_vrange->intersect (r); } + bool singleton_p (tree *result = NULL) const + { return m_vrange->singleton_p (result); } + bool zero_p () const { return m_vrange->zero_p (); } + wide_int lower_bound () const; // For irange/prange comparability. + wide_int upper_bound () const; // For irange/prange comparability. + void accept (const vrange_visitor &v) const { m_vrange->accept (v); } +private: + void init (tree type); + unsupported_range m_unsupported; + vrange *m_vrange; + int_range_max m_irange; + frange m_frange; +}; + +inline +Value_Range::Value_Range () +{ + m_vrange = &m_unsupported; +} + +// Copy constructor from a vrange. + +inline +Value_Range::Value_Range (const vrange &r) +{ + *this = r; +} + +// Copy constructor from a TYPE. The range of the temporary is set to +// UNDEFINED. + +inline +Value_Range::Value_Range (tree type) +{ + init (type); +} + +inline +Value_Range::Value_Range (const Value_Range &r) +{ + m_vrange = r.m_vrange; +} + +// Initialize object so it is possible to store temporaries of TYPE +// into it. + +inline void +Value_Range::init (tree type) +{ + gcc_checking_assert (TYPE_P (type)); + + if (irange::supports_p (type)) + m_vrange = &m_irange; + else if (frange::supports_p (type)) + m_vrange = &m_frange; + else + m_vrange = &m_unsupported; +} + +// Set the temporary to allow storing temporaries of TYPE. The range +// of the temporary is set to UNDEFINED. + +inline void +Value_Range::set_type (tree type) +{ + init (type); + m_vrange->set_undefined (); +} + +// Assignment operator for temporaries. Copying incompatible types is +// allowed. + +inline vrange & +Value_Range::operator= (const vrange &r) +{ + if (is_a <irange> (r)) + { + m_irange = as_a <irange> (r); + m_vrange = &m_irange; + } + else if (is_a <frange> (r)) + { + m_frange = as_a <frange> (r); + m_vrange = &m_frange; + } + else + gcc_unreachable (); + + return *m_vrange; +} + +inline bool +Value_Range::operator== (const Value_Range &r) const +{ + return *m_vrange == *r.m_vrange; +} + +inline bool +Value_Range::operator!= (const Value_Range &r) const +{ + return *m_vrange != *r.m_vrange; +} + +inline +Value_Range::operator vrange &() +{ + return *m_vrange; +} + +inline +Value_Range::operator const vrange &() const +{ + return *m_vrange; +} + +// Return TRUE if TYPE is supported by the vrange infrastructure. + +inline bool +Value_Range::supports_type_p (const_tree type) +{ + return irange::supports_p (type) || frange::supports_p (type); +} + +// 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 vrange *); +extern bool vrp_val_is_min (const_tree); +extern bool vrp_val_is_max (const_tree); +extern bool vrp_operand_equal_p (const_tree, const_tree); +inline REAL_VALUE_TYPE frange_val_min (const_tree type); +inline REAL_VALUE_TYPE frange_val_max (const_tree type); + +inline value_range_kind +vrange::kind () const +{ + return m_kind; +} + +// Number of sub-ranges in a range. + +inline unsigned +irange::num_pairs () const +{ + if (m_kind == VR_ANTI_RANGE) + return constant_p () ? 2 : 1; + else + return m_num_ranges; +} + +inline tree +irange::type () const +{ + gcc_checking_assert (m_num_ranges > 0); + 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 +irange::min () const +{ + return tree_lower_bound (0); +} + +inline tree +irange::max () const +{ + if (m_num_ranges) + return tree_upper_bound (); + else + return NULL; +} + +inline bool +irange::varying_compatible_p () const +{ + if (m_num_ranges != 1) + return false; + + tree l = m_base[0]; + tree u = m_base[1]; + tree t = TREE_TYPE (l); + + if (m_kind == VR_VARYING && t == error_mark_node) + return true; + + unsigned prec = TYPE_PRECISION (t); + signop sign = TYPE_SIGN (t); + if (INTEGRAL_TYPE_P (t)) + return (wi::to_wide (l) == wi::min_value (prec, sign) + && wi::to_wide (u) == wi::max_value (prec, sign) + && (!m_nonzero_mask || wi::to_wide (m_nonzero_mask) == -1)); + if (POINTER_TYPE_P (t)) + return (wi::to_wide (l) == 0 + && wi::to_wide (u) == wi::max_value (prec, sign) + && (!m_nonzero_mask || wi::to_wide (m_nonzero_mask) == -1)); + return true; +} + +inline void +irange::set (tree type, const wide_int_ref &min, const wide_int_ref &max, + value_range_kind kind) +{ + set (wide_int_to_tree (type, min), wide_int_to_tree (type, max), kind); +} + +inline bool +vrange::varying_p () const +{ + return m_kind == VR_VARYING; +} + +inline bool +vrange::undefined_p () const +{ + return m_kind == VR_UNDEFINED; +} + +inline bool +irange::zero_p () const +{ + return (m_kind == VR_RANGE && m_num_ranges == 1 + && integer_zerop (tree_lower_bound (0)) + && integer_zerop (tree_upper_bound (0))); +} + +inline bool +irange::nonzero_p () const +{ + if (undefined_p ()) + return false; + + tree zero = build_zero_cst (type ()); + return *this == int_range<1> (zero, zero, VR_ANTI_RANGE); +} + +inline bool +irange::supports_p (const_tree type) +{ + return INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type); +} + +inline bool +range_includes_zero_p (const irange *vr) +{ + if (vr->undefined_p ()) + return false; + + if (vr->varying_p ()) + return true; + + return vr->may_contain_p (build_zero_cst (vr->type ())); +} + +inline void +gt_ggc_mx (irange *x) +{ + for (unsigned i = 0; i < x->m_num_ranges; ++i) + { + gt_ggc_mx (x->m_base[i * 2]); + gt_ggc_mx (x->m_base[i * 2 + 1]); + } + if (x->m_nonzero_mask) + gt_ggc_mx (x->m_nonzero_mask); +} + +inline void +gt_pch_nx (irange *x) +{ + for (unsigned i = 0; i < x->m_num_ranges; ++i) + { + gt_pch_nx (x->m_base[i * 2]); + gt_pch_nx (x->m_base[i * 2 + 1]); + } + if (x->m_nonzero_mask) + gt_pch_nx (x->m_nonzero_mask); +} + +inline void +gt_pch_nx (irange *x, gt_pointer_operator op, void *cookie) +{ + for (unsigned i = 0; i < x->m_num_ranges; ++i) + { + op (&x->m_base[i * 2], NULL, cookie); + op (&x->m_base[i * 2 + 1], NULL, cookie); + } + if (x->m_nonzero_mask) + op (&x->m_nonzero_mask, NULL, cookie); +} + +template<unsigned N> +inline void +gt_ggc_mx (int_range<N> *x) +{ + gt_ggc_mx ((irange *) x); +} + +template<unsigned N> +inline void +gt_pch_nx (int_range<N> *x) +{ + gt_pch_nx ((irange *) x); +} + +template<unsigned N> +inline void +gt_pch_nx (int_range<N> *x, gt_pointer_operator op, void *cookie) +{ + gt_pch_nx ((irange *) x, op, cookie); +} + +// Constructors for irange + +inline +irange::irange (tree *base, unsigned nranges, bool resizable) +{ + m_discriminator = VR_IRANGE; + m_base = base; + m_max_ranges = nranges; + m_resizable = resizable; + set_undefined (); +} + +// Constructors for int_range<>. + +template<unsigned N, bool RESIZABLE> +inline +int_range<N, RESIZABLE>::int_range () + : irange (m_ranges, N, RESIZABLE) +{ +} + +template<unsigned N, bool RESIZABLE> +int_range<N, RESIZABLE>::int_range (const int_range &other) + : irange (m_ranges, N, RESIZABLE) +{ + irange::operator= (other); +} + +template<unsigned N, bool RESIZABLE> +int_range<N, RESIZABLE>::int_range (tree min, tree max, value_range_kind kind) + : irange (m_ranges, N, RESIZABLE) +{ + irange::set (min, max, kind); +} + +template<unsigned N, bool RESIZABLE> +int_range<N, RESIZABLE>::int_range (tree type) + : irange (m_ranges, N, RESIZABLE) +{ + set_varying (type); +} + +template<unsigned N, bool RESIZABLE> +int_range<N, RESIZABLE>::int_range (tree type, const wide_int &wmin, const wide_int &wmax, + value_range_kind kind) + : irange (m_ranges, N, RESIZABLE) +{ + tree min = wide_int_to_tree (type, wmin); + tree max = wide_int_to_tree (type, wmax); + set (min, max, kind); +} + +template<unsigned N, bool RESIZABLE> +int_range<N, RESIZABLE>::int_range (const irange &other) + : irange (m_ranges, N, RESIZABLE) +{ + irange::operator= (other); +} + +template<unsigned N, bool RESIZABLE> +int_range<N, RESIZABLE>& +int_range<N, RESIZABLE>::operator= (const int_range &src) +{ + irange::operator= (src); + return *this; +} + +inline void +irange::set_undefined () +{ + m_kind = VR_UNDEFINED; + m_num_ranges = 0; + m_nonzero_mask = NULL; +} + +inline void +irange::set_varying (tree type) +{ + m_kind = VR_VARYING; + m_num_ranges = 1; + m_nonzero_mask = NULL; + + if (INTEGRAL_TYPE_P (type)) + { + // Strict enum's require varying to be not TYPE_MIN/MAX, but rather + // min_value and max_value. + wide_int min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type)); + wide_int max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)); + if (wi::eq_p (max, wi::to_wide (TYPE_MAX_VALUE (type))) + && wi::eq_p (min, wi::to_wide (TYPE_MIN_VALUE (type)))) + { + m_base[0] = TYPE_MIN_VALUE (type); + m_base[1] = TYPE_MAX_VALUE (type); + } + else + { + m_base[0] = wide_int_to_tree (type, min); + m_base[1] = wide_int_to_tree (type, max); + } + } + 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; +} + +// 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 (m_num_ranges > 0); + 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 (m_num_ranges > 0); + 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 bool +irange::union_ (const vrange &r) +{ + dump_flags_t m_flags = dump_flags; + dump_flags &= ~TDF_DETAILS; + bool ret = irange::legacy_verbose_union_ (&as_a <irange> (r)); + dump_flags = m_flags; + return ret; +} + +inline bool +irange::intersect (const vrange &r) +{ + dump_flags_t m_flags = dump_flags; + dump_flags &= ~TDF_DETAILS; + bool ret = irange::legacy_verbose_intersect (&as_a <irange> (r)); + dump_flags = m_flags; + return ret; +} + +// 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, z); + else + irange_set (z, z); +} + +// Normalize a range to VARYING or UNDEFINED if possible. + +inline void +irange::normalize_kind () +{ + if (m_num_ranges == 0) + set_undefined (); + else if (varying_compatible_p ()) + { + if (m_kind == VR_RANGE) + m_kind = VR_VARYING; + else if (m_kind == VR_ANTI_RANGE) + set_undefined (); + } +} + +// 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); + } + if (frange::supports_p (type)) + { + REAL_VALUE_TYPE r = frange_val_max (type); + return build_real (const_cast <tree> (type), r); + } + 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)); + if (frange::supports_p (type)) + { + REAL_VALUE_TYPE r = frange_val_min (type); + return build_real (const_cast <tree> (type), r); + } + return NULL_TREE; +} + +inline +frange::frange () +{ + m_discriminator = VR_FRANGE; + set_undefined (); +} + +inline +frange::frange (const frange &src) +{ + m_discriminator = VR_FRANGE; + *this = src; +} + +inline +frange::frange (tree type) +{ + m_discriminator = VR_FRANGE; + set_varying (type); +} + +// frange constructor from REAL_VALUE_TYPE endpoints. + +inline +frange::frange (tree type, + const REAL_VALUE_TYPE &min, const REAL_VALUE_TYPE &max, + value_range_kind kind) +{ + m_discriminator = VR_FRANGE; + set (type, min, max, kind); +} + +// frange constructor from trees. + +inline +frange::frange (tree min, tree max, value_range_kind kind) +{ + m_discriminator = VR_FRANGE; + set (min, max, kind); +} + +inline tree +frange::type () const +{ + gcc_checking_assert (!undefined_p ()); + return m_type; +} + +inline void +frange::set_varying (tree type) +{ + m_kind = VR_VARYING; + m_type = type; + m_min = frange_val_min (type); + m_max = frange_val_max (type); + if (HONOR_NANS (m_type)) + { + m_pos_nan = true; + m_neg_nan = true; + } + else + { + m_pos_nan = false; + m_neg_nan = false; + } +} + +inline void +frange::set_undefined () +{ + m_kind = VR_UNDEFINED; + m_type = NULL; + m_pos_nan = false; + m_neg_nan = false; + // m_min and m_min are uninitialized as they are REAL_VALUE_TYPE ??. + if (flag_checking) + verify_range (); +} + +// Set the NAN bit and adjust the range. + +inline void +frange::update_nan () +{ + gcc_checking_assert (!undefined_p ()); + if (HONOR_NANS (m_type)) + { + m_pos_nan = true; + m_neg_nan = true; + normalize_kind (); + if (flag_checking) + verify_range (); + } +} + +// Like above, but set the sign of the NAN. + +inline void +frange::update_nan (bool sign) +{ + gcc_checking_assert (!undefined_p ()); + if (HONOR_NANS (m_type)) + { + m_pos_nan = !sign; + m_neg_nan = sign; + normalize_kind (); + if (flag_checking) + verify_range (); + } +} + +// Clear the NAN bit and adjust the range. + +inline void +frange::clear_nan () +{ + gcc_checking_assert (!undefined_p ()); + m_pos_nan = false; + m_neg_nan = false; + normalize_kind (); + if (flag_checking) + verify_range (); +} + +// Set R to maximum representable value for TYPE. + +inline REAL_VALUE_TYPE +real_max_representable (const_tree type) +{ + REAL_VALUE_TYPE r; + char buf[128]; + get_max_float (REAL_MODE_FORMAT (TYPE_MODE (type)), + buf, sizeof (buf), false); + int res = real_from_string (&r, buf); + gcc_checking_assert (!res); + return r; +} + +// Return the minimum representable value for TYPE. + +inline REAL_VALUE_TYPE +real_min_representable (const_tree type) +{ + REAL_VALUE_TYPE r = real_max_representable (type); + r = real_value_negate (&r); + return r; +} + +// Return the minimum value for TYPE. + +inline REAL_VALUE_TYPE +frange_val_min (const_tree type) +{ + if (HONOR_INFINITIES (type)) + return dconstninf; + else + return real_min_representable (type); +} + +// Return the maximum value for TYPE. + +inline REAL_VALUE_TYPE +frange_val_max (const_tree type) +{ + if (HONOR_INFINITIES (type)) + return dconstinf; + else + return real_max_representable (type); +} + +// Return TRUE if R is the minimum value for TYPE. + +inline bool +frange_val_is_min (const REAL_VALUE_TYPE &r, const_tree type) +{ + REAL_VALUE_TYPE min = frange_val_min (type); + return real_identical (&min, &r); +} + +// Return TRUE if R is the max value for TYPE. + +inline bool +frange_val_is_max (const REAL_VALUE_TYPE &r, const_tree type) +{ + REAL_VALUE_TYPE max = frange_val_max (type); + return real_identical (&max, &r); +} + +// Build a signless NAN of type TYPE. + +inline void +frange::set_nan (tree type) +{ + if (HONOR_NANS (type)) + { + m_kind = VR_NAN; + m_type = type; + m_pos_nan = true; + m_neg_nan = true; + if (flag_checking) + verify_range (); + } + else + set_undefined (); +} + +// Build a NAN of type TYPE with SIGN. + +inline void +frange::set_nan (tree type, bool sign) +{ + if (HONOR_NANS (type)) + { + m_kind = VR_NAN; + m_type = type; + m_neg_nan = sign; + m_pos_nan = !sign; + if (flag_checking) + verify_range (); + } + else + set_undefined (); +} + +// Return TRUE if range is known to be finite. + +inline bool +frange::known_isfinite () const +{ + if (undefined_p () || varying_p () || m_kind == VR_ANTI_RANGE) + return false; + return (!maybe_isnan () && !real_isinf (&m_min) && !real_isinf (&m_max)); +} + +// Return TRUE if range may be infinite. + +inline bool +frange::maybe_isinf () const +{ + if (undefined_p () || m_kind == VR_ANTI_RANGE || m_kind == VR_NAN) + return false; + if (varying_p ()) + return true; + return real_isinf (&m_min) || real_isinf (&m_max); +} + +// Return TRUE if range is known to be the [-INF,-INF] or [+INF,+INF]. + +inline bool +frange::known_isinf () const +{ + return (m_kind == VR_RANGE + && !maybe_isnan () + && real_identical (&m_min, &m_max) + && real_isinf (&m_min)); +} + +// Return TRUE if range is possibly a NAN. + +inline bool +frange::maybe_isnan () const +{ + if (undefined_p ()) + return false; + return m_pos_nan || m_neg_nan; +} + +// Return TRUE if range is possibly a NAN with SIGN. + +inline bool +frange::maybe_isnan (bool sign) const +{ + if (undefined_p ()) + return false; + if (sign) + return m_neg_nan; + return m_pos_nan; +} + +// Return TRUE if range is a +NAN or -NAN. + +inline bool +frange::known_isnan () const +{ + return m_kind == VR_NAN; +} + +// If the signbit for the range is known, set it in SIGNBIT and return +// TRUE. + +inline bool +frange::signbit_p (bool &signbit) const +{ + if (undefined_p ()) + return false; + + // NAN with unknown sign. + if (m_pos_nan && m_neg_nan) + return false; + // No NAN. + if (!m_pos_nan && !m_neg_nan) + { + if (m_min.sign == m_max.sign) + { + signbit = m_min.sign; + return true; + } + return false; + } + // NAN with known sign. + bool nan_sign = m_neg_nan; + if (known_isnan () + || (nan_sign == m_min.sign && nan_sign == m_max.sign)) + { + signbit = nan_sign; + return true; + } + return false; +} + +// If range has a NAN with a known sign, set it in SIGNBIT and return +// TRUE. + +inline bool +frange::nan_signbit_p (bool &signbit) const +{ + if (undefined_p ()) + return false; + + if (m_pos_nan == m_neg_nan) + return false; + + signbit = m_neg_nan; + return true; +} + +#endif // GCC_VALUE_RANGE_H |