aboutsummaryrefslogtreecommitdiff
path: root/gcc/value-range.h
diff options
context:
space:
mode:
authorAldy Hernandez <aldyh@redhat.com>2022-03-14 13:27:36 +0100
committerAldy Hernandez <aldyh@redhat.com>2022-06-01 10:55:45 +0200
commit59c8e96dd02383baec4c15665985da3caadaaa5e (patch)
tree141e126d9ba14b585c2c5a8883d7f8732f33cfc3 /gcc/value-range.h
parent4f1bce19f6d51af1dfe1118cfbec19c55d3909fc (diff)
downloadgcc-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.h135
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