diff options
author | Aldy Hernandez <aldyh@redhat.com> | 2022-03-14 13:27:36 +0100 |
---|---|---|
committer | Aldy Hernandez <aldyh@redhat.com> | 2022-06-01 10:55:45 +0200 |
commit | 59c8e96dd02383baec4c15665985da3caadaaa5e (patch) | |
tree | 141e126d9ba14b585c2c5a8883d7f8732f33cfc3 /gcc/value-range.h | |
parent | 4f1bce19f6d51af1dfe1118cfbec19c55d3909fc (diff) | |
download | gcc-59c8e96dd02383baec4c15665985da3caadaaa5e.zip gcc-59c8e96dd02383baec4c15665985da3caadaaa5e.tar.gz gcc-59c8e96dd02383baec4c15665985da3caadaaa5e.tar.bz2 |
Implement generic range temporaries.
Now that we have generic ranges, we need a way to define generic local
temporaries on the stack for intermediate calculations in the ranger
and elsewhere. We need temporaries analogous to int_range_max, but
for any of the supported types (currently just integers, but soon
integers, pointers, and floats).
The Value_Range object is such a temporary. It is designed to be
transparently used as a vrange. It shares vrange's abstract API, and
implicitly casts itself to a vrange when passed around.
The ultimate name will be value_range, but we need to remove legacy
first for that to happen. Until then, Value_Range will do.
Sample usage is as follows. Instead of:
extern void foo (vrange &);
int_range_max t;
t.set_nonzero (type);
foo (t);
one does:
Value_Range t (type);
t.set_nonzero (type);
foo (t);
You can also delay initialization, for use in loops for example:
Value_Range t;
...
t.set_type (type);
t.set_varying (type);
Creating an supported range type, will result in an unsupported_range
object being created, which will trap if anything but set_undefined()
and undefined_p() are called on it. There's no size penalty for the
unsupported_range, since its immutable and can be shared across
instances.
Since supports_type_p() is called at construction time for each
temporary, I've removed the non-zero check from this function, which
was mostly unneeded. I fixed the handful of callers that were
passing null types, and in the process sped things up a bit.
As more range types come about, the Value_Range class will be augmented
to support them by adding the relevant bits in the initialization
code, etc.
Tested on x86-64 & ppc64le Linux.
gcc/ChangeLog:
* gimple-range-fold.h (gimple_range_type): Check type before
calling supports_type_p.
* gimple-range-path.cc (path_range_query::range_of_stmt): Same.
* value-query.cc (range_query::get_tree_range): Same.
* value-range.cc (Value_Range::lower_bound): New.
(Value_Range::upper_bound): New.
(Value_Range::dump): New.
* value-range.h (class Value_Range): New.
(irange::supports_type_p): Do not check if type is non-zero.
Diffstat (limited to 'gcc/value-range.h')
-rw-r--r-- | gcc/value-range.h | 135 |
1 files changed, 132 insertions, 3 deletions
diff --git a/gcc/value-range.h b/gcc/value-range.h index 0061f66..b7ea8c7 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -54,6 +54,7 @@ enum value_range_discriminator class vrange { template <typename T> friend bool is_a (vrange &); + friend class Value_Range; public: virtual void set (tree, tree, value_range_kind = VR_RANGE) = 0; virtual tree type () const = 0; @@ -313,6 +314,136 @@ 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); + 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 *out = stderr) const; + + // 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. +private: + void init (tree type); + static unsupported_range m_unsupported; + vrange *m_vrange; + int_range_max m_irange; + DISABLE_COPY_AND_ASSIGN (Value_Range); +}; + +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); +} + +// 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_type_p (type)) + m_vrange = &m_irange; + 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 + 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; +} + // Returns true for an old-school value_range as described above. inline bool irange::legacy_mode_p () const @@ -451,9 +582,7 @@ irange::nonzero_p () const inline bool irange::supports_type_p (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 |