#include "fold-const.h"
#include "gimple-range.h"
+// Default implementation when none has been defined.
+
+bool
+vrange::contains_p (tree) const
+{
+ return false;
+}
+
+// Default implementation when none has been defined.
+
+bool
+vrange::singleton_p (tree *) const
+{
+ return false;
+}
+
+// Assignment operator for generic ranges. Copying incompatible types
+// is not allowed.
+
+vrange &
+vrange::operator= (const vrange &src)
+{
+ if (is_a <irange> (src))
+ {
+ as_a <irange> (*this) = as_a <irange> (src);
+ return *this;
+ }
+ else
+ gcc_unreachable ();
+}
+
+// Equality operator for generic ranges.
+
+bool
+vrange::operator== (const vrange &src) const
+{
+ if (is_a <irange> (src))
+ return as_a <irange> (*this) == as_a <irange> (src);
+ gcc_unreachable ();
+}
+
+// Return TRUE if R fits in THIS.
+
+bool
+irange::fits_p (const vrange &r) const
+{
+ return m_max_ranges >= as_a <irange> (r).num_pairs ();
+}
+
+void
+irange::set_nonnegative (tree type)
+{
+ set (build_int_cst (type, 0), TYPE_MAX_VALUE (type));
+}
+
+unsupported_range::unsupported_range ()
+{
+ m_discriminator = VR_UNKNOWN;
+ set_undefined ();
+}
+
+void
+unsupported_range::set (tree, tree, value_range_kind)
+{
+ gcc_unreachable ();
+}
+
+tree
+unsupported_range::type () const
+{
+ gcc_unreachable ();
+ return nullptr;
+}
+
+void
+unsupported_range::set_undefined ()
+{
+ m_kind = VR_UNDEFINED;
+}
+
+void
+unsupported_range::set_varying (tree)
+{
+ gcc_unreachable ();
+}
+
+void
+unsupported_range::dump (FILE *file) const
+{
+ fprintf (file, "[unsupported_range] ");
+ if (undefined_p ())
+ {
+ fprintf (file, "UNDEFINED");
+ return;
+ }
+ if (varying_p ())
+ {
+ fprintf (file, "VARYING");
+ return;
+ }
+ gcc_unreachable ();
+}
+
+bool
+unsupported_range::union_ (const vrange &)
+{
+ gcc_unreachable ();
+ return false;
+}
+
+bool
+unsupported_range::intersect (const vrange &)
+{
+ gcc_unreachable ();
+ return false;
+}
+
+bool
+unsupported_range::zero_p () const
+{
+ gcc_unreachable ();
+ return false;
+}
+
+bool
+unsupported_range::nonzero_p () const
+{
+ gcc_unreachable ();
+ return false;
+}
+
+void
+unsupported_range::set_nonzero (tree)
+{
+ gcc_unreachable ();
+}
+
+void
+unsupported_range::set_zero (tree)
+{
+ gcc_unreachable ();
+}
+
+void
+unsupported_range::set_nonnegative (tree)
+{
+ gcc_unreachable ();
+}
+
+bool
+unsupported_range::fits_p (const vrange &) const
+{
+ gcc_unreachable ();
+ return false;
+}
+
// Here we copy between any two irange's. The ranges can be legacy or
// multi-ranges, and copying between any combination works correctly.
}
if (kind == VR_UNDEFINED)
{
- set_undefined ();
+ irange::set_undefined ();
return;
}
void
irange::verify_range ()
{
+ gcc_checking_assert (m_discriminator == VR_IRANGE);
if (m_kind == VR_UNDEFINED)
{
gcc_checking_assert (m_num_ranges == 0);
void
irange::dump (FILE *file) const
{
+ fprintf (file, "[irange] ");
if (undefined_p ())
{
fprintf (file, "UNDEFINED");
}
void
-irange::debug () const
+vrange::debug () const
{
dump (stderr);
fprintf (stderr, "\n");
}
void
-dump_value_range (FILE *file, const irange *vr)
+dump_value_range (FILE *file, const vrange *vr)
{
vr->dump (file);
}
DEBUG_FUNCTION void
-debug (const irange *vr)
+debug (const vrange *vr)
{
dump_value_range (stderr, vr);
fprintf (stderr, "\n");
}
DEBUG_FUNCTION void
-debug (const irange &vr)
+debug (const vrange &vr)
{
debug (&vr);
}
#ifndef GCC_VALUE_RANGE_H
#define GCC_VALUE_RANGE_H
+class irange;
+
// Types of value ranges.
enum value_range_kind
{
VR_LAST
};
-// Range of values that can be associated with an SSA_NAME.
-//
-// This is the base class without any storage.
+// Discriminator between different vrange types.
+
+enum value_range_discriminator
+{
+ // Range holds an integer or pointer.
+ VR_IRANGE,
+ // Range holds an unsupported type.
+ VR_UNKNOWN
+};
+
+// Abstract class for ranges of any of the supported types.
+
+class vrange
+{
+ template <typename T> friend bool is_a (vrange &);
+public:
+ virtual void set (tree, tree, value_range_kind = VR_RANGE) = 0;
+ virtual tree type () const = 0;
+ virtual void set_varying (tree type) = 0;
+ virtual void set_undefined () = 0;
+ virtual void dump (FILE * = stderr) const = 0;
+ virtual bool union_ (const vrange &) = 0;
+ virtual bool intersect (const vrange &) = 0;
+ virtual bool singleton_p (tree *result = NULL) const;
+ virtual bool contains_p (tree cst) const;
+ virtual bool zero_p () const = 0;
+ virtual bool nonzero_p () const = 0;
+ virtual void set_nonzero (tree type) = 0;
+ virtual void set_zero (tree type) = 0;
+ virtual void set_nonnegative (tree type) = 0;
+ virtual bool fits_p (const vrange &r) const = 0;
+
+ static bool supports_type_p (tree);
+
+ 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); }
+
+ enum value_range_kind kind () const; // DEPRECATED
+ void debug () const;
+
+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
+class GTY((user)) irange : public vrange
{
friend class irange_allocator;
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;
+ virtual tree type () const override;
// Iteration over sub-ranges.
unsigned num_pairs () const;
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.
- bool union_ (const irange &);
- bool intersect (const irange &);
+ virtual bool union_ (const vrange &) override;
+ virtual bool intersect (const vrange &) override;
void invert ();
// Operator overloads.
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 dump (FILE * = stderr) const override;
// Deprecated legacy public methods.
- enum value_range_kind kind () const; // DEPRECATED
tree min () const; // DEPRECATED
tree max () const; // DEPRECATED
bool symbolic_p () const; // DEPRECATED
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_base;
};
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. All
+// operations except construction cause a trap.
+
+class unsupported_range : public vrange
+{
+public:
+ unsupported_range ();
+ virtual void set (tree, tree, value_range_kind) override;
+ virtual tree type () const override;
+ virtual void set_varying (tree type) override;
+ virtual void set_undefined () override;
+ virtual void dump (FILE *) const override;
+ virtual bool union_ (const vrange &) override;
+ virtual bool intersect (const vrange &) override;
+ virtual bool zero_p () const override;
+ virtual bool nonzero_p () const override;
+ virtual void set_nonzero (tree) override;
+ virtual void set_zero (tree) override;
+ virtual void set_nonnegative (tree) override;
+ virtual bool fits_p (const vrange &) const override;
+};
+
+// Traits to implement vrange is_a<> and as_a<>.
+
+template<typename T>
+struct vrange_traits
+{
+ // Default to something unusable.
+ typedef void range_type;
+};
+
+template<>
+struct vrange_traits<irange>
+{
+ typedef irange range_type;
+};
+
+template <typename T>
+inline bool
+is_a (vrange &v)
+{
+ 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)
+{
+ typedef typename vrange_traits<T>::range_type range_type;
+ gcc_checking_assert (is_a <range_type> (v));
+ return static_cast <range_type &> (v);
+}
+
+template <typename T>
+inline const T &
+as_a (const vrange &v)
+{
+ typedef typename vrange_traits<T>::range_type range_type;
+ gcc_checking_assert (is_a <range_type> (v));
+ return static_cast <const range_type &> (v);
+}
+
+// Specializations for the different range types.
+
+template <>
+inline bool
+is_a <irange> (vrange &v)
+{
+ return v.m_discriminator == VR_IRANGE;
+}
+
// 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
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;
}
}
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;
}
inline
irange::irange (tree *base, unsigned nranges)
{
+ m_discriminator = VR_IRANGE;
m_base = base;
m_max_ranges = nranges;
set_undefined ();
}
inline bool
-irange::union_ (const irange &r)
+irange::union_ (const vrange &r)
{
dump_flags_t m_flags = dump_flags;
dump_flags &= ~TDF_DETAILS;
- bool ret = irange::legacy_verbose_union_ (&r);
+ bool ret = irange::legacy_verbose_union_ (&as_a <irange> (r));
dump_flags = m_flags;
return ret;
}
inline bool
-irange::intersect (const irange &r)
+irange::intersect (const vrange &r)
{
dump_flags_t m_flags = dump_flags;
dump_flags &= ~TDF_DETAILS;
- bool ret = irange::legacy_verbose_intersect (&r);
+ bool ret = irange::legacy_verbose_intersect (&as_a <irange> (r));
dump_flags = m_flags;
return ret;
}
}
}
+inline bool
+vrange::supports_type_p (tree type)
+{
+ return irange::supports_type_p (type);
+}
+
// Return the maximum value for TYPE.
inline tree