aboutsummaryrefslogtreecommitdiff
path: root/gcc/value-range.h
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-08-24 16:50:14 +0000
committerGitHub <noreply@github.com>2022-08-24 16:50:14 +0000
commitd3cf195ab46d7effe806990aa6b7a409bf8e46df (patch)
treeeb33d22a749417ad62a3fc87c2dc8cfb3452632a /gcc/value-range.h
parent825a44b40ce6cfa76470e53d0746b1e64b99ee5b (diff)
parent2e77960b14527ff216fa188479de9142fbb9d34c (diff)
downloadgcc-d3cf195ab46d7effe806990aa6b7a409bf8e46df.zip
gcc-d3cf195ab46d7effe806990aa6b7a409bf8e46df.tar.gz
gcc-d3cf195ab46d7effe806990aa6b7a409bf8e46df.tar.bz2
Merge #1498
1498: Merge from GCC upstream r=philberty a=philberty Lets see if it builds. Co-authored-by: GCC Administrator <gccadmin@gcc.gnu.org> Co-authored-by: Dimitrije Milošević <dimitrije.milosevic@syrmia.com> Co-authored-by: Aldy Hernandez <aldyh@redhat.com> Co-authored-by: Jakub Jelinek <jakub@redhat.com> Co-authored-by: Martin Liska <mliska@suse.cz> Co-authored-by: Roger Sayle <roger@nextmovesoftware.com> Co-authored-by: Sam Feifer <sfeifer@redhat.com> Co-authored-by: Andrew Stubbs <ams@codesourcery.com> Co-authored-by: Jose E. Marchesi <jose.marchesi@oracle.com> Co-authored-by: H.J. Lu <hjl.tools@gmail.com> Co-authored-by: David Malcolm <dmalcolm@redhat.com> Co-authored-by: Richard Biener <rguenther@suse.de> Co-authored-by: Immad Mir <mirimmad@outlook.com>
Diffstat (limited to 'gcc/value-range.h')
-rw-r--r--gcc/value-range.h642
1 files changed, 528 insertions, 114 deletions
diff --git a/gcc/value-range.h b/gcc/value-range.h
index d4cba22..f0075d0 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -22,6 +22,8 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_VALUE_RANGE_H
#define GCC_VALUE_RANGE_H
+class irange;
+
// Types of value ranges.
enum value_range_kind
{
@@ -37,24 +39,92 @@ enum value_range_kind
VR_LAST
};
-// Range of values that can be associated with an SSA_NAME.
+// 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.
//
-// This is the base class without any storage.
+// 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;
-class GTY((user)) irange
+ 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 irange_allocator;
+ friend class vrange_allocator;
+ friend class irange_storage_slot; // For legacy_mode_p checks.
public:
// In-place setters.
- void set (tree, tree, value_range_kind = VR_RANGE);
- void set_nonzero (tree);
- void set_zero (tree);
- void set_varying (tree type);
- void set_undefined ();
+ virtual void set (tree, tree, value_range_kind = VR_RANGE) override;
+ 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_type_p (tree);
- tree type () const;
+ 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;
@@ -63,17 +133,14 @@ public:
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;
+ 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.
- void union_ (const irange &);
- void intersect (const irange &);
- void intersect (const wide_int& lb, const wide_int& ub);
+ virtual bool union_ (const vrange &) override;
+ virtual bool intersect (const vrange &) override;
void invert ();
// Operator overloads.
@@ -82,12 +149,14 @@ public:
bool operator!= (const irange &r) const { return !(*this == r); }
// Misc methods.
- bool fits_p (const irange &r) { return m_max_ranges >= r.num_pairs (); }
- void dump (FILE * = stderr) const;
- void debug () const;
+ 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.
- enum value_range_kind kind () const; // DEPRECATED
tree min () const; // DEPRECATED
tree max () const; // DEPRECATED
bool symbolic_p () const; // DEPRECATED
@@ -95,10 +164,8 @@ public:
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
+ bool legacy_verbose_union_ (const class irange *); // DEPRECATED
+ bool legacy_verbose_intersect (const irange *); // DEPRECATED
protected:
irange (tree *, unsigned);
@@ -108,10 +175,12 @@ protected:
tree tree_upper_bound () const;
// In-place operators.
- void irange_union (const irange &);
- void irange_intersect (const irange &);
+ 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 ();
@@ -134,10 +203,14 @@ private:
void irange_set_1bit_anti_range (tree, tree);
bool varying_compatible_p () const;
+ void set_nonzero_bits (tree mask);
+ bool intersect_nonzero_bits (const irange &r);
+ bool union_nonzero_bits (const irange &r);
+ bool intersect (const wide_int& lb, const wide_int& ub);
unsigned char m_num_ranges;
unsigned char m_max_ranges;
- ENUM_BITFIELD(value_range_kind) m_kind : 8;
+ tree m_nonzero_mask;
tree *m_base;
};
@@ -155,6 +228,7 @@ public:
int_range (tree type);
int_range (const int_range &);
int_range (const irange &);
+ virtual ~int_range () = default;
int_range& operator= (const int_range &);
private:
template <unsigned X> friend void gt_ggc_mx (int_range<X> *);
@@ -171,6 +245,194 @@ private:
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;
+};
+
+// 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.
+
+class frange : public vrange
+{
+ friend class frange_storage_slot;
+public:
+ frange ();
+ frange (const frange &);
+ static bool supports_p (const_tree type)
+ {
+ return SCALAR_FLOAT_TYPE_P (type);
+ }
+ virtual tree type () const override;
+ virtual void set (tree, tree, value_range_kind = VR_RANGE) override;
+ 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 supports_type_p (const_tree type) const override;
+ virtual void accept (const vrange_visitor &v) const 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)
+private:
+ void verify_range ();
+ bool normalize_kind ();
+
+ frange_props m_props;
+ tree m_type;
+};
+
+// 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;
+}
+
+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
@@ -185,6 +447,160 @@ typedef int_range<1> value_range;
// calculations.
typedef int_range<255> int_range_max;
+// 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 compatability.
+ 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 compatability.
+ wide_int upper_bound () const; // For irange/prange compatability.
+ 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
@@ -195,13 +611,13 @@ irange::legacy_mode_p () const
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 irange *);
+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 value_range_kind
-irange::kind () const
+vrange::kind () const
{
return m_kind;
}
@@ -283,7 +699,8 @@ irange::varying_compatible_p () const
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));
+ && wi::to_wide (u) == wi::max_value (prec, sign)
+ && !m_nonzero_mask);
if (POINTER_TYPE_P (t))
return (wi::to_wide (l) == 0
&& wi::to_wide (u) == wi::max_value (prec, sign));
@@ -291,13 +708,13 @@ irange::varying_compatible_p () const
}
inline bool
-irange::varying_p () const
+vrange::varying_p () const
{
return m_kind == VR_VARYING;
}
inline bool
-irange::undefined_p () const
+vrange::undefined_p () const
{
return m_kind == VR_UNDEFINED;
}
@@ -321,11 +738,9 @@ irange::nonzero_p () const
}
inline bool
-irange::supports_type_p (tree type)
+irange::supports_p (const_tree type)
{
- if (type && (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)))
- return type;
- return false;
+ return INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type);
}
inline bool
@@ -348,6 +763,8 @@ gt_ggc_mx (irange *x)
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
@@ -358,6 +775,8 @@ gt_pch_nx (irange *x)
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
@@ -368,6 +787,8 @@ gt_pch_nx (irange *x, gt_pointer_operator op, void *cookie)
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>
@@ -396,10 +817,10 @@ gt_pch_nx (int_range<N> *x, gt_pointer_operator op, void *cookie)
inline
irange::irange (tree *base, unsigned nranges)
{
+ m_discriminator = VR_IRANGE;
m_base = base;
- m_num_ranges = 0;
m_max_ranges = nranges;
- m_kind = VR_UNDEFINED;
+ set_undefined ();
}
// Constructors for int_range<>.
@@ -458,16 +879,11 @@ int_range<N>::operator= (const int_range &src)
}
inline void
-irange::set (tree val)
-{
- set (val, val);
-}
-
-inline void
irange::set_undefined ()
{
m_kind = VR_UNDEFINED;
m_num_ranges = 0;
+ m_nonzero_mask = NULL;
}
inline void
@@ -475,6 +891,7 @@ irange::set_varying (tree type)
{
m_kind = VR_VARYING;
m_num_ranges = 1;
+ m_nonzero_mask = NULL;
if (INTEGRAL_TYPE_P (type))
{
@@ -503,12 +920,6 @@ irange::set_varying (tree type)
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.
@@ -545,22 +956,24 @@ irange::upper_bound () const
return upper_bound (pairs - 1);
}
-inline void
-irange::union_ (const irange &r)
+inline bool
+irange::union_ (const vrange &r)
{
dump_flags_t m_flags = dump_flags;
dump_flags &= ~TDF_DETAILS;
- irange::union_ (&r);
+ bool ret = irange::legacy_verbose_union_ (&as_a <irange> (r));
dump_flags = m_flags;
+ return ret;
}
-inline void
-irange::intersect (const irange &r)
+inline bool
+irange::intersect (const vrange &r)
{
dump_flags_t m_flags = dump_flags;
dump_flags &= ~TDF_DETAILS;
- irange::intersect (&r);
+ 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.
@@ -582,7 +995,7 @@ irange::set_zero (tree type)
{
tree z = build_int_cst (type, 0);
if (legacy_mode_p ())
- set (z);
+ set (z, z);
else
irange_set (z, z);
}
@@ -593,7 +1006,7 @@ inline void
irange::normalize_kind ()
{
if (m_num_ranges == 0)
- m_kind = VR_UNDEFINED;
+ set_undefined ();
else if (varying_compatible_p ())
{
if (m_kind == VR_RANGE)
@@ -617,6 +1030,12 @@ vrp_val_max (const_tree 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 real;
+ real_inf (&real);
+ return build_real (const_cast <tree> (type), real);
+ }
return NULL_TREE;
}
@@ -629,79 +1048,74 @@ vrp_val_min (const_tree 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 real, real_ninf;
+ real_inf (&real);
+ real_ninf = real_value_negate (&real);
+ return build_real (const_cast <tree> (type), real_ninf);
+ }
return NULL_TREE;
}
-// This is the irange storage class. It is used to allocate the
-// minimum amount of storage needed for a given irange. Storage is
-// automatically freed at destruction of the storage class.
-//
-// It is meant for long term storage, as opposed to int_range_max
-// which is meant for intermediate temporary results on the stack.
-//
-// The newly allocated irange is initialized to the empty set
-// (undefined_p() is true).
+// Supporting methods for frange.
-class irange_allocator
+inline bool
+frange_props::operator== (const frange_props &other) const
{
-public:
- irange_allocator ();
- ~irange_allocator ();
- // Return a new range with NUM_PAIRS.
- irange *allocate (unsigned num_pairs);
- // Return a copy of SRC with the minimum amount of sub-ranges needed
- // to represent it.
- irange *allocate (const irange &src);
- void *get_memory (unsigned num_bytes);
-private:
- DISABLE_COPY_AND_ASSIGN (irange_allocator);
- struct obstack m_obstack;
-};
+ return u.bytes == other.u.bytes;
+}
-inline
-irange_allocator::irange_allocator ()
+inline bool
+frange_props::union_ (const frange_props &other)
{
- obstack_init (&m_obstack);
+ unsigned char saved = u.bytes;
+ u.bytes |= other.u.bytes;
+ return u.bytes != saved;
}
-inline
-irange_allocator::~irange_allocator ()
+inline bool
+frange_props::intersect (const frange_props &other)
{
- obstack_free (&m_obstack, NULL);
+ unsigned char saved = u.bytes;
+ u.bytes &= other.u.bytes;
+ return u.bytes != saved;
}
-// Provide a hunk of memory from the obstack.
-inline void *
-irange_allocator::get_memory (unsigned num_bytes)
+inline
+frange::frange ()
{
- void *r = obstack_alloc (&m_obstack, num_bytes);
- return r;
+ m_discriminator = VR_FRANGE;
+ set_undefined ();
}
-// Return a new range with NUM_PAIRS.
-
-inline irange *
-irange_allocator::allocate (unsigned num_pairs)
+inline
+frange::frange (const frange &src)
{
- // Never allocate 0 pairs.
- // Don't allocate 1 either, or we get legacy value_range's.
- if (num_pairs < 2)
- num_pairs = 2;
+ m_discriminator = VR_FRANGE;
+ *this = src;
+}
- size_t nbytes = sizeof (tree) * 2 * num_pairs;
+inline tree
+frange::type () const
+{
+ return m_type;
+}
- // Allocate the irange and required memory for the vector.
- void *r = obstack_alloc (&m_obstack, sizeof (irange));
- tree *mem = (tree *) obstack_alloc (&m_obstack, nbytes);
- return new (r) irange (mem, num_pairs);
+inline void
+frange::set_varying (tree type)
+{
+ m_kind = VR_VARYING;
+ m_type = type;
+ m_props.set_varying ();
}
-inline irange *
-irange_allocator::allocate (const irange &src)
+inline void
+frange::set_undefined ()
{
- irange *r = allocate (src.num_pairs ());
- *r = src;
- return r;
+ m_kind = VR_UNDEFINED;
+ m_type = NULL;
+ m_props.set_undefined ();
}
#endif // GCC_VALUE_RANGE_H