Message ID | 20220530132751.1752112-2-aldyh@redhat.com |
---|---|
State | New |
Headers | show |
Series | [1/5] Implement abstract vrange class. | expand |
On 5/30/22 09:27, Aldy Hernandez wrote: > 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 tmp_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, tmp_range will do. > I was going to suggest maybe renaming value_range to legacy_range or something, and then start using value_range for ranges of any time. Then it occurred to me that numerous places which use value_range will/can continue to use value_range going forward.. ie value_range vr; if (!rvals->range_of_expr (vr, name, stmt)) return -1; would be unaffected, to it would be pointless turmoil to rename that and then rename it back to value_range. I also notice there are already a few instance of local variable named tmp_range, which make name renames annoying. Perhaps we should use Value_Range or something like that in the interim for the multi-type ranges? Then the rename is trivial down the road, formatting will be unaffected, and then we're kinda sorta using the end_goal name? Andrew
On Mon, May 30, 2022 at 4:56 PM Andrew MacLeod <amacleod@redhat.com> wrote: > > On 5/30/22 09:27, Aldy Hernandez wrote: > > 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 tmp_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, tmp_range will do. > > > I was going to suggest maybe renaming value_range to legacy_range or > something, and then start using value_range for ranges of any time. > Then it occurred to me that numerous places which use value_range > will/can continue to use value_range going forward.. ie > > value_range vr; > if (!rvals->range_of_expr (vr, name, stmt)) > return -1; > > would be unaffected, to it would be pointless turmoil to rename that and > then rename it back to value_range. > > I also notice there are already a few instance of local variable named > tmp_range, which make name renames annoying. Perhaps we should use > Value_Range or something like that in the interim for the multi-type > ranges? Then the rename is trivial down the road, formatting will be > unaffected, and then we're kinda sorta using the end_goal name? OMG that is so ugly! Although I guess it would be temporary. Speaking of which, how far away are we from enabling ranger in VRP1? Because once we do that, we can start nuking legacy and cleaning all this up. Aldy
On 5/31/22 02:21, Aldy Hernandez wrote: > On Mon, May 30, 2022 at 4:56 PM Andrew MacLeod <amacleod@redhat.com> wrote: >> On 5/30/22 09:27, Aldy Hernandez wrote: >>> 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 tmp_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, tmp_range will do. >>> >> I was going to suggest maybe renaming value_range to legacy_range or >> something, and then start using value_range for ranges of any time. >> Then it occurred to me that numerous places which use value_range >> will/can continue to use value_range going forward.. ie >> >> value_range vr; >> if (!rvals->range_of_expr (vr, name, stmt)) >> return -1; >> >> would be unaffected, to it would be pointless turmoil to rename that and >> then rename it back to value_range. >> >> I also notice there are already a few instance of local variable named >> tmp_range, which make name renames annoying. Perhaps we should use >> Value_Range or something like that in the interim for the multi-type >> ranges? Then the rename is trivial down the road, formatting will be >> unaffected, and then we're kinda sorta using the end_goal name? > OMG that is so ugly! Although I guess it would be temporary. > > Speaking of which, how far away are we from enabling ranger in VRP1? > Because once we do that, we can start nuking legacy and cleaning all > this up. > > Aldy > Im thinking about making the switch mid juneish... i still have a few verifications to make. We want to leave legacy for at least a while so we can manually switch back to it for investigation of any issues that come up during the transition. so id expect early august time frame before trying to remove legacy.... at least legacy VRP. thats my thoughts anyway. Andrew Andrew
Final patch committed. tmp_range has been renamed to Value_Range. Value_Range::init() has been renamed to set_type() which is more obvious. Default constructor for Value_Range now points the vrange to the unsupported_range object, so we always have an object available. Re-tested on x86-64 Linux. On Tue, May 31, 2022 at 8:21 AM Aldy Hernandez <aldyh@redhat.com> wrote: > > On Mon, May 30, 2022 at 4:56 PM Andrew MacLeod <amacleod@redhat.com> wrote: > > > > On 5/30/22 09:27, Aldy Hernandez wrote: > > > 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 tmp_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, tmp_range will do. > > > > > I was going to suggest maybe renaming value_range to legacy_range or > > something, and then start using value_range for ranges of any time. > > Then it occurred to me that numerous places which use value_range > > will/can continue to use value_range going forward.. ie > > > > value_range vr; > > if (!rvals->range_of_expr (vr, name, stmt)) > > return -1; > > > > would be unaffected, to it would be pointless turmoil to rename that and > > then rename it back to value_range. > > > > I also notice there are already a few instance of local variable named > > tmp_range, which make name renames annoying. Perhaps we should use > > Value_Range or something like that in the interim for the multi-type > > ranges? Then the rename is trivial down the road, formatting will be > > unaffected, and then we're kinda sorta using the end_goal name? > > OMG that is so ugly! Although I guess it would be temporary. > > Speaking of which, how far away are we from enabling ranger in VRP1? > Because once we do that, we can start nuking legacy and cleaning all > this up. > > Aldy
diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h index 53a5bf85dd4..20cb73dabb9 100644 --- a/gcc/gimple-range-fold.h +++ b/gcc/gimple-range-fold.h @@ -81,7 +81,7 @@ gimple_range_type (const gimple *s) type = TREE_TYPE (type); } } - if (irange::supports_type_p (type)) + if (type && irange::supports_type_p (type)) return type; return NULL_TREE; } diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc index 459d3797da7..66f433dd1d5 100644 --- a/gcc/gimple-range-path.cc +++ b/gcc/gimple-range-path.cc @@ -755,7 +755,7 @@ path_range_query::range_of_stmt (irange &r, gimple *stmt, tree) { tree type = gimple_range_type (stmt); - if (!irange::supports_type_p (type)) + if (!type || !irange::supports_type_p (type)) return false; // If resolving unknowns, fold the statement making use of any diff --git a/gcc/value-query.cc b/gcc/value-query.cc index 9ccd802457b..26e3858103b 100644 --- a/gcc/value-query.cc +++ b/gcc/value-query.cc @@ -249,7 +249,8 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt) if (UNARY_CLASS_P (expr)) { range_operator *op = range_op_handler (TREE_CODE (expr), type); - if (op) + tree op0_type = TREE_TYPE (TREE_OPERAND (expr, 0)); + if (op && irange::supports_type_p (op0_type)) { int_range_max r0; range_of_expr (r0, TREE_OPERAND (expr, 0), stmt); diff --git a/gcc/value-range.cc b/gcc/value-range.cc index 97ff0614f48..c5f326ab479 100644 --- a/gcc/value-range.cc +++ b/gcc/value-range.cc @@ -30,6 +30,42 @@ along with GCC; see the file COPYING3. If not see #include "fold-const.h" #include "gimple-range.h" +// Convenience function only available for integers and pointers. + +wide_int +tmp_range::lower_bound () const +{ + if (is_a <irange> (*m_vrange)) + return as_a <irange> (*m_vrange).lower_bound (); + gcc_unreachable (); +} + +// Convenience function only available for integers and pointers. + +wide_int +tmp_range::upper_bound () const +{ + if (is_a <irange> (*m_vrange)) + return as_a <irange> (*m_vrange).upper_bound (); + gcc_unreachable (); +} + +void +tmp_range::dump (FILE *out) const +{ + if (m_vrange) + m_vrange->dump (out); + else + fprintf (out, "NULL"); +} + +DEBUG_FUNCTION void +debug (const tmp_range &r) +{ + r.dump (stderr); + fprintf (stderr, "\n"); +} + // Default implementation when none has been defined. bool @@ -186,6 +222,8 @@ unsupported_range::fits_p (const vrange &) const return false; } +unsupported_range tmp_range::m_unsupported; + // Here we copy between any two irange's. The ranges can be legacy or // multi-ranges, and copying between any combination works correctly. diff --git a/gcc/value-range.h b/gcc/value-range.h index 0061f667092..d51998145da 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 tmp_range; public: virtual void set (tree, tree, value_range_kind = VR_RANGE) = 0; virtual tree type () const = 0; @@ -313,6 +314,131 @@ 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 tmp_range +{ +public: + tmp_range (); + tmp_range (const vrange &r); + tmp_range (tree type); + bool init (tree type); + vrange& operator= (const vrange &); + bool operator== (const tmp_range &r) const; + bool operator!= (const tmp_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: + static unsupported_range m_unsupported; + vrange *m_vrange; + int_range_max m_irange; + DISABLE_COPY_AND_ASSIGN (tmp_range); +}; + +// This default constructor leaves the temporary uninitialized. Use +// init() to initialize. + +inline +tmp_range::tmp_range () +{ + m_vrange = nullptr; +} + +// Copy constructor from a vrange. + +inline +tmp_range::tmp_range (const vrange &r) +{ + *this = r; +} + +// Copy constructor from a tree TYPE. +// +// Note that unlike the similarly named int_range<> constructor which +// defaults to VARYING, this constructor defaults to UNDEFINED. +// Defaulting to VARYING had an unfortunate performance penalty. We +// could remove the int_range<> (type) constructor if this is +// confusing. + +inline +tmp_range::tmp_range (tree type) +{ + init (type); +} + +// Initialize object so it is possible to store temporaries of TYPE +// into it. The range of the temporary is undefined after this call, +// and must be explicitly set (set_varying, set_undefined, etc). + +inline bool +tmp_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; + return true; +} + +inline vrange & +tmp_range::operator= (const vrange &r) +{ + if (is_a <irange> (r)) + { + m_irange = as_a <irange> (r); + m_vrange = &m_irange; + return *m_vrange; + } + else + gcc_unreachable (); +} + +inline bool +tmp_range::operator== (const tmp_range &r) const +{ + return *m_vrange == *r.m_vrange; +} + +inline bool +tmp_range::operator!= (const tmp_range &r) const +{ + return *m_vrange != *r.m_vrange; +} + +inline +tmp_range::operator vrange &() +{ + return *m_vrange; +} + +inline +tmp_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 +577,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