diff options
Diffstat (limited to 'gcc/value-range.h')
-rw-r--r-- | gcc/value-range.h | 231 |
1 files changed, 101 insertions, 130 deletions
diff --git a/gcc/value-range.h b/gcc/value-range.h index 4392de8..3a401f3 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -35,6 +35,8 @@ enum value_range_kind VR_RANGE, /* Range is ~[MIN, MAX]. */ VR_ANTI_RANGE, + /* Range is a NAN. */ + VR_NAN, /* Range is a nice guy. */ VR_LAST }; @@ -263,69 +265,10 @@ public: virtual void accept (const vrange_visitor &v) const override; }; -// Floating point property to represent possible values of a NAN, INF, etc. - -class fp_prop -{ -public: - enum kind { - UNDEFINED = 0x0, // Prop is impossible. - YES = 0x1, // Prop is definitely set. - NO = 0x2, // Prop is definitely not set. - VARYING = (YES | NO) // Prop may hold. - }; - fp_prop (kind f) : m_kind (f) { } - bool varying_p () const { return m_kind == VARYING; } - bool undefined_p () const { return m_kind == UNDEFINED; } - bool yes_p () const { return m_kind == YES; } - bool no_p () const { return m_kind == NO; } -private: - unsigned char m_kind : 2; -}; - -// Accessors for individual FP properties. - -#define FP_PROP_ACCESSOR(NAME) \ - void NAME##_set_varying () { u.bits.NAME = fp_prop::VARYING; } \ - void NAME##_set_yes () { u.bits.NAME = fp_prop::YES; } \ - void NAME##_set_no () { u.bits.NAME = fp_prop::NO; } \ - bool NAME##_varying_p () const { return u.bits.NAME == fp_prop::VARYING; } \ - bool NAME##_undefined_p () const { return u.bits.NAME == fp_prop::UNDEFINED; } \ - bool NAME##_yes_p () const { return u.bits.NAME == fp_prop::YES; } \ - bool NAME##_no_p () const { return u.bits.NAME == fp_prop::NO; } \ - fp_prop get_##NAME () const \ - { return fp_prop ((fp_prop::kind) u.bits.NAME); } \ - void set_##NAME (fp_prop::kind f) { u.bits.NAME = f; } - -// Aggregate of all the FP properties in an frange packed into one -// structure to save space. Using explicit fp_prop's in the frange, -// would take one byte per property because of padding. Instead, we -// can save all properties into one byte. - -class frange_props -{ -public: - frange_props () { set_varying (); } - void set_varying () { u.bytes = 0xff; } - void set_undefined () { u.bytes = 0; } - bool varying_p () { return u.bytes == 0xff; } - bool undefined_p () { return u.bytes == 0; } - bool union_ (const frange_props &other); - bool intersect (const frange_props &other); - bool operator== (const frange_props &other) const; - FP_PROP_ACCESSOR(nan) - FP_PROP_ACCESSOR(signbit) -private: - union { - struct { - unsigned char nan : 2; - unsigned char signbit : 2; - } bits; - unsigned char bytes; - } u; -}; - // 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 { @@ -349,6 +292,7 @@ public: void set (tree type, const REAL_VALUE_TYPE &, const REAL_VALUE_TYPE &, 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; @@ -367,42 +311,41 @@ public: bool operator!= (const frange &r) const { return !(*this == r); } const REAL_VALUE_TYPE &lower_bound () const; const REAL_VALUE_TYPE &upper_bound () const; + void update_nan (); + void clear_nan (); // fpclassify like API - bool known_finite () const; - bool maybe_inf () const; - bool known_inf () const; - bool maybe_nan () const; - bool known_nan () const; - bool known_signbit (bool &signbit) const; - - // Accessors for FP properties. - void update_nan (fp_prop::kind f); - void clear_nan () { update_nan (fp_prop::NO); } - void set_signbit (fp_prop::kind); + bool known_isfinite () const; + bool known_isnan () const; + bool known_isinf () const; + bool maybe_isnan () const; + bool maybe_isinf () const; + bool signbit_p (bool &signbit) const; private: - fp_prop get_nan () const { return m_props.get_nan (); } - fp_prop get_signbit () const { return m_props.get_signbit (); } void verify_range (); bool normalize_kind (); + bool union_nans (const frange &); + bool intersect_nans (const frange &); + bool combine_zeros (const frange &, bool union_p); - frange_props m_props; 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 ()); + gcc_checking_assert (!undefined_p () && !known_isnan ()); return m_min; } inline const REAL_VALUE_TYPE & frange::upper_bound () const { - gcc_checking_assert (!undefined_p ()); + gcc_checking_assert (!undefined_p () && !known_isnan ()); return m_max; } @@ -1082,30 +1025,6 @@ vrp_val_min (const_tree type) return NULL_TREE; } -// Supporting methods for frange. - -inline bool -frange_props::operator== (const frange_props &other) const -{ - return u.bytes == other.u.bytes; -} - -inline bool -frange_props::union_ (const frange_props &other) -{ - unsigned char saved = u.bytes; - u.bytes |= other.u.bytes; - return u.bytes != saved; -} - -inline bool -frange_props::intersect (const frange_props &other) -{ - unsigned char saved = u.bytes; - u.bytes &= other.u.bytes; - return u.bytes != saved; -} - inline frange::frange () { @@ -1154,15 +1073,42 @@ frange::set_varying (tree type) m_type = type; m_min = dconstninf; m_max = dconstinf; - m_props.set_varying (); + m_pos_nan = true; + m_neg_nan = true; } inline void frange::set_undefined () { m_kind = VR_UNDEFINED; - m_type = NULL; - m_props.set_undefined (); + if (flag_checking) + verify_range (); +} + +// Set the NAN bit and adjust the range. + +inline void +frange::update_nan () +{ + gcc_checking_assert (!undefined_p ()); + m_pos_nan = true; + m_neg_nan = true; + 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. @@ -1186,19 +1132,28 @@ real_min_representable (REAL_VALUE_TYPE *r, tree type) *r = real_value_negate (r); } -// Build a NAN of type TYPE. +// Build a signless NAN of type TYPE. inline void frange::set_nan (tree type) { - REAL_VALUE_TYPE r; - gcc_assert (real_nan (&r, "", 1, TYPE_MODE (type))); - m_kind = VR_RANGE; + m_kind = VR_NAN; m_type = type; - m_min = r; - m_max = r; - m_props.set_varying (); - m_props.nan_set_yes (); + m_pos_nan = true; + m_neg_nan = true; + if (flag_checking) + verify_range (); +} + +// Build a NAN of type TYPE with SIGN. + +inline void +frange::set_nan (tree type, bool sign) +{ + m_kind = VR_NAN; + m_type = type; + m_neg_nan = sign; + m_pos_nan = !sign; if (flag_checking) verify_range (); } @@ -1206,21 +1161,19 @@ frange::set_nan (tree type) // Return TRUE if range is known to be finite. inline bool -frange::known_finite () const +frange::known_isfinite () const { if (undefined_p () || varying_p () || m_kind == VR_ANTI_RANGE) return false; - return (!real_isnan (&m_min) - && !real_isinf (&m_min) - && !real_isinf (&m_max)); + return (!maybe_isnan () && !real_isinf (&m_min) && !real_isinf (&m_max)); } // Return TRUE if range may be infinite. inline bool -frange::maybe_inf () const +frange::maybe_isinf () const { - if (undefined_p () || m_kind == VR_ANTI_RANGE) + if (undefined_p () || m_kind == VR_ANTI_RANGE || m_kind == VR_NAN) return false; if (varying_p ()) return true; @@ -1230,7 +1183,7 @@ frange::maybe_inf () const // Return TRUE if range is known to be the [-INF,-INF] or [+INF,+INF]. inline bool -frange::known_inf () const +frange::known_isinf () const { return (m_kind == VR_RANGE && real_identical (&m_min, &m_max) @@ -1240,32 +1193,50 @@ frange::known_inf () const // Return TRUE if range is possibly a NAN. inline bool -frange::maybe_nan () const +frange::maybe_isnan () const { - return !get_nan ().no_p (); + return m_pos_nan || m_neg_nan; } // Return TRUE if range is a +NAN or -NAN. inline bool -frange::known_nan () const +frange::known_isnan () const { - return get_nan ().yes_p (); + return m_kind == VR_NAN; } // If the signbit for the range is known, set it in SIGNBIT and return // TRUE. inline bool -frange::known_signbit (bool &signbit) const +frange::signbit_p (bool &signbit) const { - // FIXME: Signed NANs are not supported yet. - if (maybe_nan ()) + if (undefined_p ()) return false; - if (get_signbit ().varying_p ()) + + // NAN with unknown sign. + if (m_pos_nan && m_neg_nan) return false; - signbit = get_signbit ().yes_p (); - return true; + // 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; } #endif // GCC_VALUE_RANGE_H |