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.h415
1 files changed, 304 insertions, 111 deletions
diff --git a/gcc/value-range.h b/gcc/value-range.h
index f0075d0..413e54b 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,116 +265,92 @@ 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(inf)
- FP_PROP_ACCESSOR(ninf)
-private:
- union {
- struct {
- unsigned char nan : 2;
- unsigned char inf : 2;
- unsigned char ninf : 2;
- } bits;
- unsigned char bytes;
- } u;
-};
-
-// Accessors for getting/setting all FP properties at once.
-
-#define FRANGE_PROP_ACCESSOR(NAME) \
- fp_prop get_##NAME () const { return m_props.get_##NAME (); } \
- void set_##NAME (fp_prop::kind f) \
- { \
- m_props.set_##NAME (f); \
- normalize_kind (); \
- }
-
// 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, const REAL_VALUE_TYPE &min, const REAL_VALUE_TYPE &max,
+ value_range_kind = VR_RANGE);
static bool supports_p (const_tree type)
{
- return SCALAR_FLOAT_TYPE_P (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_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); }
-
- // Each fp_prop can be accessed with get_PROP() and set_PROP().
- FRANGE_PROP_ACCESSOR(nan)
- FRANGE_PROP_ACCESSOR(inf)
- FRANGE_PROP_ACCESSOR(ninf)
+ const REAL_VALUE_TYPE &lower_bound () const;
+ const REAL_VALUE_TYPE &upper_bound () const;
+ void update_nan ();
+ void update_nan (bool sign);
+ void clear_nan ();
+
+ // fpclassify like API
+ 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:
void verify_range ();
bool normalize_kind ();
+ bool union_nans (const frange &);
+ bool intersect_nans (const frange &);
+ bool combine_zeros (const frange &, bool union_p);
+ void flush_denormals_to_zero ();
- 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 () && !known_isnan ());
+ return m_min;
+}
+
+inline const REAL_VALUE_TYPE &
+frange::upper_bound () const
+{
+ gcc_checking_assert (!undefined_p () && !known_isnan ());
+ return m_max;
+}
+
// is_a<> and as_a<> implementation for vrange.
// Anything we haven't specialized is a hard fail.
@@ -615,6 +593,8 @@ 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
@@ -1032,9 +1012,8 @@ vrp_val_max (const_tree type)
}
if (frange::supports_p (type))
{
- REAL_VALUE_TYPE real;
- real_inf (&real);
- return build_real (const_cast <tree> (type), real);
+ REAL_VALUE_TYPE r = frange_val_max (type);
+ return build_real (const_cast <tree> (type), r);
}
return NULL_TREE;
}
@@ -1050,55 +1029,50 @@ vrp_val_min (const_tree type)
return build_zero_cst (const_cast<tree> (type));
if (frange::supports_p (type))
{
- REAL_VALUE_TYPE real, real_ninf;
- real_inf (&real);
- real_ninf = real_value_negate (&real);
- return build_real (const_cast <tree> (type), real_ninf);
+ REAL_VALUE_TYPE r = frange_val_min (type);
+ return build_real (const_cast <tree> (type), r);
}
return NULL_TREE;
}
-// Supporting methods for frange.
-
-inline bool
-frange_props::operator== (const frange_props &other) const
+inline
+frange::frange ()
{
- return u.bytes == other.u.bytes;
+ m_discriminator = VR_FRANGE;
+ set_undefined ();
}
-inline bool
-frange_props::union_ (const frange_props &other)
+inline
+frange::frange (const frange &src)
{
- unsigned char saved = u.bytes;
- u.bytes |= other.u.bytes;
- return u.bytes != saved;
+ m_discriminator = VR_FRANGE;
+ *this = src;
}
-inline bool
-frange_props::intersect (const frange_props &other)
-{
- unsigned char saved = u.bytes;
- u.bytes &= other.u.bytes;
- return u.bytes != saved;
-}
+// frange constructor from REAL_VALUE_TYPE endpoints.
inline
-frange::frange ()
+frange::frange (tree type,
+ const REAL_VALUE_TYPE &min, const REAL_VALUE_TYPE &max,
+ value_range_kind kind)
{
m_discriminator = VR_FRANGE;
- set_undefined ();
+ set (type, min, max, kind);
}
+// frange constructor from trees.
+
inline
-frange::frange (const frange &src)
+frange::frange (tree min, tree max, value_range_kind kind)
{
m_discriminator = VR_FRANGE;
- *this = src;
+ set (min, max, kind);
}
inline tree
frange::type () const
{
+ gcc_checking_assert (!undefined_p ());
return m_type;
}
@@ -1107,7 +1081,10 @@ frange::set_varying (tree type)
{
m_kind = VR_VARYING;
m_type = type;
- m_props.set_varying ();
+ m_min = frange_val_min (type);
+ m_max = frange_val_max (type);
+ m_pos_nan = true;
+ m_neg_nan = true;
}
inline void
@@ -1115,7 +1092,223 @@ frange::set_undefined ()
{
m_kind = VR_UNDEFINED;
m_type = NULL;
- m_props.set_undefined ();
+ m_pos_nan = false;
+ m_neg_nan = false;
+ // m_min and m_min are unitialized 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 ());
+ 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 ());
+ 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 (flag_finite_math_only)
+ return real_min_representable (type);
+ else
+ return dconstninf;
+}
+
+// Return the maximum value for TYPE.
+
+inline REAL_VALUE_TYPE
+frange_val_max (const_tree type)
+{
+ if (flag_finite_math_only)
+ return real_max_representable (type);
+ else
+ return dconstinf;
+}
+
+// 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)
+{
+ m_kind = VR_NAN;
+ m_type = type;
+ 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 ();
+}
+
+// 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
+ && 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 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;
}
#endif // GCC_VALUE_RANGE_H