aboutsummaryrefslogtreecommitdiff
path: root/gcc/value-range.h
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/value-range.h')
-rw-r--r--gcc/value-range.h231
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