From 71f2928e282eb7863de8426e41c38a90c436d41d Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Mon, 7 Mar 2022 14:48:58 +0100 Subject: Make irange::intersect(wide_int, wide_int) private. This method should have been private, and somehow seeped into the API. Tested and benchmarked on x86-64 Linux. gcc/ChangeLog: * gimple-range-cache.h (non_null_ref::adjust_range): Do not use irange::intersect (wide_int, wide_int). * gimple-range-fold.cc (adjust_pointer_diff_expr): Same. (adjust_imagpart_expr): Same. * value-range.h (irange::intersect (wide_int, wide_int)): Make private. --- gcc/value-range.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index d4cba22..fe7795b 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -73,7 +73,6 @@ public: // In-place operators. void union_ (const irange &); void intersect (const irange &); - void intersect (const wide_int& lb, const wide_int& ub); void invert (); // Operator overloads. @@ -135,6 +134,7 @@ private: void irange_set_1bit_anti_range (tree, tree); bool varying_compatible_p () const; + void 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; -- cgit v1.1 From 17dea11cf4388fb2cd8c3894d3ce5583765e71a4 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Mon, 7 Mar 2022 14:49:57 +0100 Subject: Call set_undefined from irange constructor. Small clean up to use set_undefined instead of duplicating the functionality therein. Tested on x86-64 Linux. gcc/ChangeLog: * value-range.h (irange::irange): Use set_undefined. --- gcc/value-range.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index fe7795b..b64e024 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -397,9 +397,8 @@ inline irange::irange (tree *base, unsigned nranges) { m_base = base; - m_num_ranges = 0; m_max_ranges = nranges; - m_kind = VR_UNDEFINED; + set_undefined (); } // Constructors for int_range<>. -- cgit v1.1 From c13fd1b8fd8eef009370a629bd2ca2bbdb2f828d Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Mon, 14 Mar 2022 09:57:48 +0100 Subject: Remove various deprecated methods in class irange. This patch cleans up some irange methods in preparation for other cleanups later in the cycle. First, we prefer the reference overloads for union and intersect as the pointer versions have been deprecated for a couple releases. Also, I've renamed the legacy union/intersect whose only function was to provide additional verbosity for VRP into legacy_verbose_{union,intersect}. This is a temporary rename to serve as a visual reminder of which of the methods are bound for the chopping block when the legacy code gets removed later this cycle. Tested on x86-64 Linux. gcc/ChangeLog: * gimple-fold.cc (size_must_be_zero_p): Use reference instead of pointer * gimple-ssa-evrp-analyze.cc (evrp_range_analyzer::record_ranges_from_incoming_edge): Rename intersect to legacy_verbose_intersect. * ipa-cp.cc (ipcp_vr_lattice::meet_with_1): Use reference instead of pointer. * tree-ssa-dom.cc (dom_jt_simplifier::simplify): Use value_range instead of value_range_equiv. * tree-vrp.cc (extract_range_from_plus_minus_expr): Use reference instead of pointer. (find_case_label_range): Same. * value-range-equiv.cc (value_range_equiv::intersect): Rename to... (value_range_equiv::legacy_verbose_intersect): ...this. (value_range_equiv::union_): Rename to... (value_range_equiv::legacy_verbose_union_): ...this. * value-range-equiv.h (class value_range_equiv): Rename union and intersect to legacy_verbose_{intersect,union}. * value-range.cc (irange::union_): Rename to... (irange::legacy_verbose_union_): ...this. (irange::intersect): Rename to... (irange::legacy_verbose_intersect): ...this. * value-range.h (irange::union_): Rename union_ to legacy_verbose_union. (irange::intersect): Rename intersect to legacy_verbose_intersect. * vr-values.cc (vr_values::update_value_range): Same. (vr_values::extract_range_for_var_from_comparison_expr): Same. (vr_values::extract_range_from_cond_expr): Rename union_ to legacy_verbose_union. (vr_values::extract_range_from_phi_node): Same. --- gcc/value-range.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index b64e024..90a395f 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -96,8 +96,8 @@ public: 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 + void legacy_verbose_union_ (const class irange *); // DEPRECATED + void legacy_verbose_intersect (const irange *); // DEPRECATED protected: irange (tree *, unsigned); @@ -549,7 +549,7 @@ irange::union_ (const irange &r) { dump_flags_t m_flags = dump_flags; dump_flags &= ~TDF_DETAILS; - irange::union_ (&r); + irange::legacy_verbose_union_ (&r); dump_flags = m_flags; } @@ -558,7 +558,7 @@ irange::intersect (const irange &r) { dump_flags_t m_flags = dump_flags; dump_flags &= ~TDF_DETAILS; - irange::intersect (&r); + irange::legacy_verbose_intersect (&r); dump_flags = m_flags; } -- cgit v1.1 From 1d3d7e88aac0db20a4b59044f9b7cd35e847e8d3 Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Mon, 9 May 2022 13:20:06 -0400 Subject: Add a return value to intersect and speed it up. Return true if the intersection of ranges changed the original value. Speed up the case when there is no change by calling an efficient contains routine. * value-range.cc (irange::legacy_verbose_intersect): Add return value. (irange::irange_contains_p): New. (irange::irange_intersect): Add return value. * value-range.h (class irange): Adjust prototypes. --- gcc/value-range.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index 90a395f..4198602 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -72,7 +72,7 @@ public: // In-place operators. void union_ (const irange &); - void intersect (const irange &); + bool intersect (const irange &); void invert (); // Operator overloads. @@ -97,7 +97,7 @@ public: void set (tree); // DEPRECATED bool equal_p (const irange &) const; // DEPRECATED void legacy_verbose_union_ (const class irange *); // DEPRECATED - void legacy_verbose_intersect (const irange *); // DEPRECATED + bool legacy_verbose_intersect (const irange *); // DEPRECATED protected: irange (tree *, unsigned); @@ -108,9 +108,10 @@ protected: // In-place operators. void irange_union (const irange &); - void irange_intersect (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; void normalize_kind (); @@ -134,7 +135,7 @@ private: void irange_set_1bit_anti_range (tree, tree); bool varying_compatible_p () const; - void intersect (const wide_int& lb, const wide_int& ub); + 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; @@ -553,13 +554,14 @@ irange::union_ (const irange &r) dump_flags = m_flags; } -inline void +inline bool irange::intersect (const irange &r) { dump_flags_t m_flags = dump_flags; dump_flags &= ~TDF_DETAILS; - irange::legacy_verbose_intersect (&r); + bool ret = irange::legacy_verbose_intersect (&r); dump_flags = m_flags; + return ret; } // Set value range VR to a nonzero range of type TYPE. -- cgit v1.1 From f3204ce1ae6b97f7e79d633844d61d021da8502e Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Mon, 9 May 2022 13:32:31 -0400 Subject: Return a bool result for union, and add performance improvements. Union_ returns a boolean indicating if the operation changes the range. Also optimize the common single-pair UNION single-pair case. * gimple-range-edge.cc (calc_switch_ranges): Check union return value. * value-range.cc (irange::legacy_verbose_union_): Add return value. (irange::irange_single_pair_union): New. (irange::irange_union): Add return value. * value-range.h (class irange): Adjust prototypes. --- gcc/value-range.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index 4198602..ec59d2e 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -71,7 +71,7 @@ public: bool contains_p (tree) const; // In-place operators. - void union_ (const irange &); + bool union_ (const irange &); bool intersect (const irange &); void invert (); @@ -96,7 +96,7 @@ public: bool may_contain_p (tree) const; // DEPRECATED void set (tree); // DEPRECATED bool equal_p (const irange &) const; // DEPRECATED - void legacy_verbose_union_ (const class irange *); // DEPRECATED + bool legacy_verbose_union_ (const class irange *); // DEPRECATED bool legacy_verbose_intersect (const irange *); // DEPRECATED protected: @@ -107,11 +107,12 @@ protected: tree tree_upper_bound () const; // In-place operators. - void irange_union (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 (); @@ -545,13 +546,14 @@ irange::upper_bound () const return upper_bound (pairs - 1); } -inline void +inline bool irange::union_ (const irange &r) { dump_flags_t m_flags = dump_flags; dump_flags &= ~TDF_DETAILS; - irange::legacy_verbose_union_ (&r); + bool ret = irange::legacy_verbose_union_ (&r); dump_flags = m_flags; + return ret; } inline bool -- cgit v1.1 From 4f1bce19f6d51af1dfe1118cfbec19c55d3909fc Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Mon, 14 Mar 2022 14:04:56 +0100 Subject: Implement abstract vrange class. This is a series of patches making ranger type agnostic in preparation for contributing support for other types of ranges (pointers and floats initially). The first step in this process is to implement vrange, an abstract class that will be exclusively used by ranger, and from which all ranges will inherit. Vrange provides the minimum operations for ranger to work. The current virtual methods are what we've used to implement frange (floats) and prange (pointers), but we may restrict the virtual methods further as other ranges come about (i.e. set_nonnegative() has no meaning for a future string range). This patchset also provides a mechanism for declaring local type agnostic ranges that can transparently hold an irange, frange, prange's, etc, and a dispatch mechanism for range-ops to work with various range types. More details in the relevant patches. FUTURE PLAN =========== The plan after this is to contribute a bare bones implementation for floats (frange) that will provide relationals, followed by a separation of integers and pointers (irange and prange). Once this is in place, we can further enhance both floats and pointers. For example, pointer tracking, pointer plus optimizations, and keeping track of NaN's, etc. Once frange and prange come live, all ranger clients will immediately benefit from these enhancements. For instance, in our local branch, the threader is already float aware with regards to relationals. We expect to wait a few weeks before starting to contribute further enhancements to give the tree a time to stabilize, and Andrew time to rebase his upcoming patches :-P. NOTES ===== In discussions with Andrew, it has become clear that with vrange coming about, supports_type_p() is somewhat ambiguous. Prior to vrange it has been used to (a) determine if a type is supported by ranger, (b) as a short-cut for checking if a type is pointer or integer, as well as (c) to see if a given range can hold a type. These things have had the same meaning in irange, but are slightly different with vrange. I will address this in a follow-up patch. Speaking of supported types, we now provide an unsupported_range for passing around ranges for unsupported types. We've been silently doing this for a while, in both vr-values by creating VARYING for unsupported types with error_mark_node end points, and in ranger when we pass an unsupported range before we realize in range_of_expr that it's unsupported. This class just formalizes what we've already been doing in an irange, but making it explicit that you can't do anything with these ranges except pass them. Any other operation traps. There is no GTY support for vrange yet, as we don't store it long term. When we contribute support for global ranges (think SSA_NAME_RANGE_INFO but for generic ranges), we will include it. There was just no need to pollute this patchset with it. TESTING ======= The patchset has been tested on x86-64 Linux as well as ppc64 Linux. I have also verified that we fold the same number of conditionals in evrp as well as thread the same number of paths. There should be no user visible changes. We have also benchmarked the work, with the final numbers being an *improvement* of 1.92% for evrp, and 0.82% for VRP. Overall compilation has a miniscule improvement. This is despite the extra indirection level. The improvements are mostly because of small cleanups required for the generalization of ranges. As a sanity check, I stuck kcachegrind on a few sample .ii files to see where the time was being gained. Most of the gain came from gimple_range_global() being 19% faster. This function is called a lot, and it was constructing a legacy value_range, then returning it by value, which the caller then had to convert to an irange. This is in line with other pending work: anytime we get rid of legacy, we gain time. I will wait a few days before committing to welcome any comments. gcc/ChangeLog: * value-range-equiv.cc (value_range_equiv::set): New. * value-range-equiv.h (class value_range_equiv): Make set method virtual. Remove default bitmap argument from set method. * value-range.cc (vrange::contains_p): New. (vrange::singleton_p): New. (vrange::operator=): New. (vrange::operator==): New. (irange::fits_p): Move to .cc file. (irange::set_nonnegative): New. (unsupported_range::unsupported_range): New. (unsupported_range::set): New. (unsupported_range::type): New. (unsupported_range::set_undefined): New. (unsupported_range::set_varying): New. (unsupported_range::dump): New. (unsupported_range::union_): New. (unsupported_range::intersect): New. (unsupported_range::zero_p): New. (unsupported_range::nonzero_p): New. (unsupported_range::set_nonzero): New. (unsupported_range::set_zero): New. (unsupported_range::set_nonnegative): New. (unsupported_range::fits_p): New. (irange::set): Call irange::set_undefined. (irange::verify_range): Check discriminator field. (irange::dump): Dump [irange] marker. (irange::debug): Move to... (vrange::debug): ...here. (dump_value_range): Accept vrange. (debug): Same. * value-range.h (enum value_range_discriminator): New. (class vrange): New. (class unsupported_range): New. (struct vrange_traits): New. (is_a): New. (as_a): New. (class irange): Inherit from vrange. (dump_value_range): Adjust for vrange. (irange::kind): Rename to... (vrange::kind): ...this. (irange::varying_p): Rename to... (vrange::varying_p): ...this. (irange::undefined_p): Rename to... (vrange::undefined_p): ...this. (irange::irange): Set discriminator. (irange::union_): Convert to irange before passing to irange method. (irange::intersect): Same. (vrange::supports_type_p): New. * vr-values.cc (vr_values::extract_range_from_binary_expr): Pass NULL bitmap argument to value_range_equiv::set. (vr_values::extract_range_basic): Same. --- gcc/value-range.h | 195 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 164 insertions(+), 31 deletions(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index ec59d2e..0061f66 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,71 @@ 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 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; @@ -63,16 +112,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. - bool union_ (const irange &); - bool intersect (const irange &); + virtual bool union_ (const vrange &) override; + virtual bool intersect (const vrange &) override; void invert (); // Operator overloads. @@ -81,12 +128,10 @@ 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 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 @@ -139,7 +184,6 @@ private: 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; }; @@ -173,6 +217,88 @@ 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. 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 +struct vrange_traits +{ + // Default to something unusable. + typedef void range_type; +}; + +template<> +struct vrange_traits +{ + typedef irange range_type; +}; + +template +inline bool +is_a (vrange &v) +{ + gcc_unreachable (); + return false; +} + +template +inline bool +is_a (const vrange &v) +{ + // Reuse is_a to implement the const version. + const T &derived = static_cast (v); + return is_a (const_cast (derived)); +} + +template +inline T & +as_a (vrange &v) +{ + typedef typename vrange_traits::range_type range_type; + gcc_checking_assert (is_a (v)); + return static_cast (v); +} + +template +inline const T & +as_a (const vrange &v) +{ + typedef typename vrange_traits::range_type range_type; + gcc_checking_assert (is_a (v)); + return static_cast (v); +} + +// Specializations for the different range types. + +template <> +inline bool +is_a (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 @@ -197,13 +323,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; } @@ -293,13 +419,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; } @@ -398,6 +524,7 @@ gt_pch_nx (int_range *x, gt_pointer_operator op, void *cookie) inline irange::irange (tree *base, unsigned nranges) { + m_discriminator = VR_IRANGE; m_base = base; m_max_ranges = nranges; set_undefined (); @@ -547,21 +674,21 @@ irange::upper_bound () const } 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 (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 (r)); dump_flags = m_flags; return ret; } @@ -608,6 +735,12 @@ irange::normalize_kind () } } +inline bool +vrange::supports_type_p (tree type) +{ + return irange::supports_type_p (type); +} + // Return the maximum value for TYPE. inline tree -- cgit v1.1 From 59c8e96dd02383baec4c15665985da3caadaaa5e Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Mon, 14 Mar 2022 13:27:36 +0100 Subject: 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. --- gcc/value-range.h | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 132 insertions(+), 3 deletions(-) (limited to 'gcc/value-range.h') 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 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 (r)) + { + m_irange = as_a (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 -- cgit v1.1 From d8474337a0b2bf1b3c84863957cef1da92811ffe Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Sun, 22 May 2022 20:17:39 +0200 Subject: Revamp irange_allocator to handle vranges. This patch revamps the range allocator to handle generic vrange's. I've cleaned it up somehow to make it obvious the various things you can allocate with it. I've also moved away from overloads into distinct names when appropriate. The various entry points are now: // Allocate a range of TYPE. vrange *alloc_vrange (tree type); // Allocate a memory block of BYTES. void *alloc (unsigned bytes); // Return a clone of SRC. template T *clone (const T &src); It is now possible to allocate a clone of an irange, or any future range types: irange *i = allocator.clone (some_irange); frange *f = allocator.clone (some_frange); You can actually do so without the <>, but I find it clearer to specify the vrange type. So with it you can allocate a specific range type, or vrange, or a block of memory. I have rewritten the C style casts to C++ casts, since casts tend to be hints of problematic designs. With the C++ casts you can at least grep for them easier. Speak of which, the next patch, which converts ranger to vrange, will further clean this space by removing some unnecessary casts. Tested on x86-64 Linux and ppc64le Linux. * gimple-range-cache.cc (sbr_vector::sbr_vector): Adjust for vrange allocator. (sbr_vector::grow): Same. (sbr_vector::set_bb_range): Same. (sbr_sparse_bitmap::sbr_sparse_bitmap): Same. (sbr_sparse_bitmap::set_bb_range): Same. (block_range_cache::~block_range_cache): Same. (block_range_cache::set_bb_range): Same. (ssa_global_cache::ssa_global_cache): Same. (ssa_global_cache::~ssa_global_cache): Same. (ssa_global_cache::set_global_range): Same. * gimple-range-cache.h (block_range_cache): Same. (ssa_global_cache): Same. * gimple-range-edge.cc (gimple_outgoing_range::calc_switch_ranges): Same. * gimple-range-edge.h (gimple_outgoing_range): Same. * gimple-range-infer.cc (infer_range_manager::get_nonzero): Same. (infer_range_manager::add_range): Same. * gimple-range-infer.h (class infer_range_manager): Same. * value-range.h (class irange_allocator): Rename to... (class vrange_allocator): ...this. (irange_allocator::irange_allocator): New. (vrange_allocator::vrange_allocator): New. (irange_allocator::~irange_allocator): New. (vrange_allocator::~vrange_allocator): New. (irange_allocator::get_memory): Rename to... (vrange_allocator::alloc): ...this. (vrange_allocator::alloc_vrange): Rename from... (irange_allocator::allocate): ...this. (vrange_allocator::alloc_irange): New. --- gcc/value-range.h | 82 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 30 deletions(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index b7ea8c7..5cd0e0e 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -92,7 +92,7 @@ protected: class GTY((user)) irange : public vrange { - friend class irange_allocator; + friend class vrange_allocator; public: // In-place setters. virtual void set (tree, tree, value_range_kind = VR_RANGE) override; @@ -897,56 +897,63 @@ vrp_val_min (const_tree type) 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). +// This is the range storage class. It is used to allocate the +// minimum amount of storage needed for a given range. Storage is +// automatically freed at destruction of the class. -class irange_allocator +class vrange_allocator { 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); + vrange_allocator (); + ~vrange_allocator (); + // Allocate a range of TYPE. + vrange *alloc_vrange (tree type); + // Allocate a memory block of BYTES. + void *alloc (unsigned bytes); + // Return a clone of SRC. + template T *clone (const T &src); private: - DISABLE_COPY_AND_ASSIGN (irange_allocator); + irange *alloc_irange (unsigned pairs); + DISABLE_COPY_AND_ASSIGN (vrange_allocator); struct obstack m_obstack; }; inline -irange_allocator::irange_allocator () +vrange_allocator::vrange_allocator () { obstack_init (&m_obstack); } inline -irange_allocator::~irange_allocator () +vrange_allocator::~vrange_allocator () { obstack_free (&m_obstack, NULL); } // Provide a hunk of memory from the obstack. + inline void * -irange_allocator::get_memory (unsigned num_bytes) +vrange_allocator::alloc (unsigned bytes) { - void *r = obstack_alloc (&m_obstack, num_bytes); - return r; + return obstack_alloc (&m_obstack, bytes); +} + +// Return a new range to hold ranges of TYPE. The newly allocated +// range is initialized to VR_UNDEFINED. + +inline vrange * +vrange_allocator::alloc_vrange (tree type) +{ + if (irange::supports_type_p (type)) + return alloc_irange (2); + + gcc_unreachable (); } // Return a new range with NUM_PAIRS. inline irange * -irange_allocator::allocate (unsigned num_pairs) +vrange_allocator::alloc_irange (unsigned num_pairs) { // Never allocate 0 pairs. // Don't allocate 1 either, or we get legacy value_range's. @@ -956,17 +963,32 @@ irange_allocator::allocate (unsigned num_pairs) size_t nbytes = sizeof (tree) * 2 * num_pairs; // 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); + void *r = alloc (sizeof (irange)); + tree *mem = static_cast (alloc (nbytes)); return new (r) irange (mem, num_pairs); } +// Return a clone of an irange. + +template <> inline irange * -irange_allocator::allocate (const irange &src) +vrange_allocator::clone (const irange &src) { - irange *r = allocate (src.num_pairs ()); + irange *r = alloc_irange (src.num_pairs ()); *r = src; return r; } +// Return a clone of a vrange. + +template <> +inline vrange * +vrange_allocator::clone (const vrange &src) +{ + if (is_a (src)) + return clone (as_a (src)); + + gcc_unreachable (); +} + #endif // GCC_VALUE_RANGE_H -- cgit v1.1 From a9058b08381cd76e8d21364f0f5ccddb3777c3fd Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Tue, 31 May 2022 14:04:51 +0200 Subject: Implement vrange::supports_type_p. [I have conservatively assumed that both the loop-ch and loop-unswitch passes, which also use the ranger, only support integers and pointers. If the goal is to handle other types as well, irange::supports_p() should be Value_Range::supports_type_p(), and any uses of int_range_max should be converted to Value_Range. I can help in the conversion if you'd like.] As discussed, this patch disambiguates the use of supports_type_p throughout, as what ranger supports is a totally different question than what a given range variant (irange, frange, etc) supports. Unfortunately we need both a static method and a virtual method, and they can't be named the same. The uses are documented in the vrange class: +// 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. +// +// 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)) ... +// } The value_range_equiv::supports_p() method can be use to determine what legacy VRP supports, as irange::supports_p() will no longer be applicable in the evrp analyzer code base once irange and prange are split. Tested on x86-64 Linux. gcc/ChangeLog: * gimple-range-edge.cc (gimple_outgoing_range_stmt_p): Adjust for an object level supports_type_p for irange and a static Value_Range::supports_type_p. * gimple-range-fold.cc (fold_using_range::range_of_range_op): Same. (fold_using_range::range_of_address): Same. (fold_using_range::range_of_builtin_call): Same. * gimple-range-fold.h (gimple_range_type): Same. (gimple_range_ssa_p): Same. * gimple-range-path.cc (path_range_query::internal_range_of_expr): Same. (path_range_query::range_of_stmt): Same. (path_range_query::add_to_imports): Same. * gimple-range.cc (gimple_ranger::range_on_edge): Same. (gimple_ranger::export_global_ranges): Same. * gimple-ssa-evrp-analyze.cc (evrp_range_analyzer::record_ranges_from_phis): Same. * range-op.cc (range_operator::wi_fold): Same. (range_operator::fold_range): Same. * tree-ssa-loop-ch.cc (entry_loop_condition_is_static): Same. * tree-ssa-loop-unswitch.cc (struct unswitch_predicate): Same. (evaluate_control_stmt_using_entry_checks): Same. * tree-ssa-threadedge.cc (hybrid_jt_simplifier::compute_ranges_from_state): Same. * tree-vrp.cc (supported_types_p): Same. * value-query.cc (range_query::value_of_expr): Same. (range_query::value_on_edge): Same. (range_query::value_of_stmt): Same. (range_query::get_tree_range): Same. (get_range_global): Same. (global_range_query::range_of_expr): Same. * value-range-equiv.h (class value_range_equiv): Same. * value-range.cc (irange::supports_type_p): Same. (unsupported_range::supports_type_p): Same. * value-range.h (enum value_range_discriminator): Same. (Value_Range::init): Same. (Value_Range::supports_type_p): Same. (irange::supports_type_p): Same. (irange::supports_p): Same. (vrange::supports_type_p): Same. (vrange_allocator::alloc_vrange): Same. --- gcc/value-range.h | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index 5cd0e0e..69cf6c3 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -50,6 +50,23 @@ enum value_range_discriminator }; // 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. +// +// 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 { @@ -58,6 +75,7 @@ class vrange public: virtual void set (tree, tree, value_range_kind = VR_RANGE) = 0; virtual tree type () const = 0; + virtual bool supports_type_p (tree type) const = 0; virtual void set_varying (tree type) = 0; virtual void set_undefined () = 0; virtual void dump (FILE * = stderr) const = 0; @@ -72,8 +90,6 @@ public: 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 &); @@ -103,7 +119,8 @@ public: virtual void set_undefined () override; // Range types. - static bool supports_type_p (tree); + static bool supports_p (tree type); + virtual bool supports_type_p (tree type) const override; virtual tree type () const override; // Iteration over sub-ranges. @@ -228,6 +245,7 @@ public: unsupported_range (); virtual void set (tree, tree, value_range_kind) override; virtual tree type () const override; + virtual bool supports_type_p (tree type) const override; virtual void set_varying (tree type) override; virtual void set_undefined () override; virtual void dump (FILE *) const override; @@ -331,6 +349,7 @@ public: operator vrange &(); operator const vrange &() const; void dump (FILE *out = stderr) const; + static bool supports_type_p (tree type); // Convenience methods for vrange compatability. void set (tree min, tree max, value_range_kind kind = VR_RANGE) @@ -387,7 +406,7 @@ Value_Range::init (tree type) { gcc_checking_assert (TYPE_P (type)); - if (irange::supports_type_p (type)) + if (irange::supports_p (type)) m_vrange = &m_irange; else m_vrange = &m_unsupported; @@ -444,6 +463,14 @@ 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 (tree type) +{ + return irange::supports_p (type); +} + // Returns true for an old-school value_range as described above. inline bool irange::legacy_mode_p () const @@ -580,7 +607,7 @@ irange::nonzero_p () const } inline bool -irange::supports_type_p (tree type) +irange::supports_p (tree type) { return INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type); } @@ -864,12 +891,6 @@ irange::normalize_kind () } } -inline bool -vrange::supports_type_p (tree type) -{ - return irange::supports_type_p (type); -} - // Return the maximum value for TYPE. inline tree @@ -944,7 +965,7 @@ vrange_allocator::alloc (unsigned bytes) inline vrange * vrange_allocator::alloc_vrange (tree type) { - if (irange::supports_type_p (type)) + if (irange::supports_p (type)) return alloc_irange (2); gcc_unreachable (); -- cgit v1.1 From 89b0276d3fafdd254e17beee3c86ec00edcf28a2 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 1 Jun 2022 16:58:36 +0200 Subject: Flesh out unsupported_range. It's cleaner to have the unsupported_range fully fleshed out, instead of trapping on every operation. It can also serve as the basis for the default vrange methods that frange and prange will inherit. This patch implements most methods, including union and intersect, to handle an UNDEFINED and a VARYING range. Since this can serve as the basis for other classes, I have moved everything into the vrange class, making the unsupported_range trivial. Note that vrange is still an abstract class, as I have purposely left the dump() method abstract. Also, I have made the unsupported range in the temporary class (Value_Range) a method field, instead of a static member. This way the temporary can set UNDEFINED and VARYING as needed. Tested on x86-64 Linux. gcc/ChangeLog: * value-range.cc (vrange::contains_p): Implement. (vrange::type): Return void. (vrange::supports_type_p): Implement. (irange::fits_p): Same. (vrange::set_undefined): Same. (irange::set_nonnegative): Same. (vrange::set_varying): Same. (vrange::union_): Same. (unsupported_range::set): Move to vrange. (unsupported_range::type): Move to vrange. (vrange::intersect): Implement for varying and undefined. (vrange::zero_p): Implement. (unsupported_range::supports_type_p): Move to vrange. (vrange::nonzero_p): Implement. (unsupported_range::set_undefined): Move to vrange. (unsupported_range::set_varying): Same. (unsupported_range::dump): Same. (unsupported_range::union_): Same. Implement for varying and undefined. (unsupported_range::intersect): Move to vrange. (unsupported_range::zero_p): Same. (unsupported_range::nonzero_p): Same. (unsupported_range::set_nonzero): Same. (unsupported_range::set_zero): Same. (unsupported_range::set_nonnegative): Same. (unsupported_range::fits_p): Same. * value-range.h (class vrange): Remove abstract markers for most methods. (class unsupported_range): Remove most methods as they will now be inherited from vrange. --- gcc/value-range.h | 44 +++++++++++++++----------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index 69cf6c3..61e6a18 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -73,22 +73,22 @@ class vrange template 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; - virtual bool supports_type_p (tree type) const = 0; - virtual void set_varying (tree type) = 0; - virtual void set_undefined () = 0; + virtual void set (tree, tree, value_range_kind = VR_RANGE); + virtual tree type () const; + virtual bool supports_type_p (tree type) const; + virtual void set_varying (tree type); + virtual void set_undefined (); virtual void dump (FILE * = stderr) const = 0; - virtual bool union_ (const vrange &) = 0; - virtual bool intersect (const vrange &) = 0; + 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 = 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; + 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; @@ -236,27 +236,13 @@ private: }; // 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. +// they're unsupported, or by vr_values::get_value_range. class unsupported_range : public vrange { public: unsupported_range (); - virtual void set (tree, tree, value_range_kind) override; - virtual tree type () const override; - virtual bool supports_type_p (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<>. @@ -369,7 +355,7 @@ public: wide_int upper_bound () const; // For irange/prange compatability. private: void init (tree type); - static unsupported_range m_unsupported; + unsupported_range m_unsupported; vrange *m_vrange; int_range_max m_irange; DISABLE_COPY_AND_ASSIGN (Value_Range); -- cgit v1.1 From f4fa81ba63299030d068327f3d90920de8c54d1c Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Wed, 1 Jun 2022 17:41:10 +0200 Subject: Remove unneeded vrange_traits. The traits struct is no longer needed. Tested on x86-64 Linux. gcc/ChangeLog: * value-range.h (struct vrange_traits): Remove. (is_a): Rewrite without vrange_traits. (as_a): Same. --- gcc/value-range.h | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index 61e6a18..26e41ed 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -245,24 +245,12 @@ public: virtual void dump (FILE *) const override; }; -// Traits to implement vrange is_a<> and as_a<>. - -template -struct vrange_traits -{ - // Default to something unusable. - typedef void range_type; -}; - -template<> -struct vrange_traits -{ - typedef irange range_type; -}; +// is_a<> and as_a<> implementation for vrange. +// Anything we haven't specialized is a hard fail. template inline bool -is_a (vrange &v) +is_a (vrange &) { gcc_unreachable (); return false; @@ -281,18 +269,16 @@ template inline T & as_a (vrange &v) { - typedef typename vrange_traits::range_type range_type; - gcc_checking_assert (is_a (v)); - return static_cast (v); + gcc_checking_assert (is_a (v)); + return static_cast (v); } template inline const T & as_a (const vrange &v) { - typedef typename vrange_traits::range_type range_type; - gcc_checking_assert (is_a (v)); - return static_cast (v); + gcc_checking_assert (is_a (v)); + return static_cast (v); } // Specializations for the different range types. -- cgit v1.1 From 0fd3c7063db52b8f509a9572ff8078a0f91176da Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Thu, 2 Jun 2022 19:52:41 +0200 Subject: Misc range temporary fixes. This fixes a couples places that were using int_range_max, but needed a generic temporary. Found while merging the frange work. Also, copying between range temporaries is actually useful :). Tested on x86-64 Linux. gcc/ChangeLog: * gimple-range-cache.cc (ranger_cache::range_from_dom): Use Value_Range. * gimple-range.cc (gimple_ranger::register_inferred_ranges): Same. * value-range.h (Value_Range::Value_Range): Implement copy constructor for Value_Range. --- gcc/value-range.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index 26e41ed..dc6f6b0 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -314,6 +314,7 @@ 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; @@ -344,7 +345,6 @@ private: unsupported_range m_unsupported; vrange *m_vrange; int_range_max m_irange; - DISABLE_COPY_AND_ASSIGN (Value_Range); }; inline @@ -370,6 +370,12 @@ 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. -- cgit v1.1 From fa22c9c7a979655efaff888138107324afc510c5 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 10 Jun 2022 15:02:51 +0200 Subject: Implement ggc_vrange_allocator. This patch makes the vrange_allocator an abstract class, and uses it to implement the obstack allocator as well as a new GC allocator. The GC bits will be used to implement the vrange storage class for global ranges, which will be contributed in the next week or so. Tested and benchmarked on x86-64 Linux. gcc/ChangeLog: * gimple-range-cache.cc (block_range_cache::block_range_cache): Rename vrange_allocator to obstack_vrange_allocator. (ssa_global_cache::ssa_global_cache): Same. * gimple-range-edge.h (class gimple_outgoing_range): Same. * gimple-range-infer.h (class infer_range_manager): Same. * value-range.h (class vrange_allocator): Make abstract. (class obstack_vrange_allocator): Inherit from vrange_allocator. (class ggc_vrange_allocator): New. --- gcc/value-range.h | 57 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 21 deletions(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index dc6f6b0..627d221 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -903,39 +903,54 @@ vrp_val_min (const_tree type) class vrange_allocator { public: - vrange_allocator (); - ~vrange_allocator (); + vrange_allocator () { } + virtual ~vrange_allocator () { } // Allocate a range of TYPE. vrange *alloc_vrange (tree type); // Allocate a memory block of BYTES. - void *alloc (unsigned bytes); + virtual void *alloc (unsigned bytes) = 0; + virtual void free (void *p) = 0; // Return a clone of SRC. template T *clone (const T &src); private: irange *alloc_irange (unsigned pairs); - DISABLE_COPY_AND_ASSIGN (vrange_allocator); - struct obstack m_obstack; + void operator= (const vrange_allocator &) = delete; }; -inline -vrange_allocator::vrange_allocator () +class obstack_vrange_allocator : public vrange_allocator { - obstack_init (&m_obstack); -} - -inline -vrange_allocator::~vrange_allocator () -{ - obstack_free (&m_obstack, NULL); -} - -// Provide a hunk of memory from the obstack. +public: + obstack_vrange_allocator () + { + obstack_init (&m_obstack); + } + virtual ~obstack_vrange_allocator () final override + { + obstack_free (&m_obstack, NULL); + } + virtual void *alloc (unsigned bytes) final override + { + return obstack_alloc (&m_obstack, bytes); + } + virtual void free (void *) final override { } +private: + obstack m_obstack; +}; -inline void * -vrange_allocator::alloc (unsigned bytes) +class ggc_vrange_allocator : public vrange_allocator { - return obstack_alloc (&m_obstack, bytes); -} +public: + ggc_vrange_allocator () { } + virtual ~ggc_vrange_allocator () final override { } + virtual void *alloc (unsigned bytes) final override + { + return ggc_internal_alloc (bytes); + } + virtual void free (void *p) final override + { + return ggc_free (p); + } +}; // Return a new range to hold ranges of TYPE. The newly allocated // range is initialized to VR_UNDEFINED. -- cgit v1.1 From 3ae9def08565c36af2dc0bff495545ee1e9db642 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Sun, 3 Jul 2022 15:25:38 +0200 Subject: Move range allocator code to value-range-storage.* Now that vrange_storage is in its own file, I think it's prudent to move all the vrange allocator code there since it's all related. The users of value-range.h do not need to know the implementation details of the storage facilities. Tested and benchmarked on x86-64 Linux. gcc/ChangeLog: * gimple-range-cache.cc: Include value-range-storage.h. * gimple-range-cache.h (class block_range_cache): Add "class" to m_range_allocator. * gimple-range-edge.cc (gimple_outgoing_range::gimple_outgoing_range): Allocate allocator. (gimple_outgoing_range::~gimple_outgoing_range): Free allocator. (gimple_outgoing_range::calc_switch_ranges): Dereference allocator. * gimple-range-edge.h: Add "class" to m_range_allocator. * gimple-range-infer.cc (infer_range_manager::infer_range_manager): Allocate allocator. (infer_range_manager::~infer_range_manager): Free allocator. (infer_range_manager::get_nonzero): Dereference allocator. (infer_range_manager::add_range): Same. * gimple-range-infer.h (class vrange_allocator): Add "class" to m_range_allocator. * value-range-storage.h (class vrange_allocator): Move from value-range.h. (class obstack_vrange_allocator): Same. (class ggc_vrange_allocator): Same. (vrange_allocator::alloc_vrange): Same. (vrange_allocator::alloc_irange): Same. * value-range.h (class vrange_allocator): Move to value-range-storage.h. (class obstack_vrange_allocator): Same. (class ggc_vrange_allocator): Same. --- gcc/value-range.h | 109 ------------------------------------------------------ 1 file changed, 109 deletions(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index 627d221..8ee7793 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -896,113 +896,4 @@ vrp_val_min (const_tree type) return NULL_TREE; } -// This is the range storage class. It is used to allocate the -// minimum amount of storage needed for a given range. Storage is -// automatically freed at destruction of the class. - -class vrange_allocator -{ -public: - vrange_allocator () { } - virtual ~vrange_allocator () { } - // Allocate a range of TYPE. - vrange *alloc_vrange (tree type); - // Allocate a memory block of BYTES. - virtual void *alloc (unsigned bytes) = 0; - virtual void free (void *p) = 0; - // Return a clone of SRC. - template T *clone (const T &src); -private: - irange *alloc_irange (unsigned pairs); - void operator= (const vrange_allocator &) = delete; -}; - -class obstack_vrange_allocator : public vrange_allocator -{ -public: - obstack_vrange_allocator () - { - obstack_init (&m_obstack); - } - virtual ~obstack_vrange_allocator () final override - { - obstack_free (&m_obstack, NULL); - } - virtual void *alloc (unsigned bytes) final override - { - return obstack_alloc (&m_obstack, bytes); - } - virtual void free (void *) final override { } -private: - obstack m_obstack; -}; - -class ggc_vrange_allocator : public vrange_allocator -{ -public: - ggc_vrange_allocator () { } - virtual ~ggc_vrange_allocator () final override { } - virtual void *alloc (unsigned bytes) final override - { - return ggc_internal_alloc (bytes); - } - virtual void free (void *p) final override - { - return ggc_free (p); - } -}; - -// Return a new range to hold ranges of TYPE. The newly allocated -// range is initialized to VR_UNDEFINED. - -inline vrange * -vrange_allocator::alloc_vrange (tree type) -{ - if (irange::supports_p (type)) - return alloc_irange (2); - - gcc_unreachable (); -} - -// Return a new range with NUM_PAIRS. - -inline irange * -vrange_allocator::alloc_irange (unsigned num_pairs) -{ - // Never allocate 0 pairs. - // Don't allocate 1 either, or we get legacy value_range's. - if (num_pairs < 2) - num_pairs = 2; - - size_t nbytes = sizeof (tree) * 2 * num_pairs; - - // Allocate the irange and required memory for the vector. - void *r = alloc (sizeof (irange)); - tree *mem = static_cast (alloc (nbytes)); - return new (r) irange (mem, num_pairs); -} - -// Return a clone of an irange. - -template <> -inline irange * -vrange_allocator::clone (const irange &src) -{ - irange *r = alloc_irange (src.num_pairs ()); - *r = src; - return r; -} - -// Return a clone of a vrange. - -template <> -inline vrange * -vrange_allocator::clone (const vrange &src) -{ - if (is_a (src)) - return clone (as_a (src)); - - gcc_unreachable (); -} - #endif // GCC_VALUE_RANGE_H -- cgit v1.1 From bbe836bc7c557b3f4119e03d24cb61f23906cba9 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Sun, 3 Jul 2022 18:22:11 +0200 Subject: Remove some deprecated irange methods. Tested on x86-64 Linux. gcc/ChangeLog: * ipa-cp.cc (ipcp_vr_lattice::meet_with_1): Use operator!=. * ipa-prop.cc (struct ipa_vr_ggc_hash_traits): Same. * tree-ssa-loop-unswitch.cc (struct unswitch_predicate): Use set with two arguments. (find_unswitching_predicates_for_bb): Same. * tree-vrp.cc (range_fold_unary_symbolics_p): Same. * value-range-equiv.cc (value_range_equiv::equal_p): Use operator==. * value-range.cc (irange::equal_p): Rename to... (irange::operator==): ...this. * value-range.h (irange::set): Remove. (irange::operator==): Remove. (irange::set_zero): Use set with two arguments. * vr-values.cc (vr_values::extract_range_from_binary_expr): Same. (vr_values::extract_range_from_unary_expr): Same. (check_for_binary_op_overflow): Same. (bounds_of_var_in_loop): Same. --- gcc/value-range.h | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index 8ee7793..fd67031 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -157,8 +157,6 @@ 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 bool legacy_verbose_union_ (const class irange *); // DEPRECATED bool legacy_verbose_intersect (const irange *); // DEPRECATED @@ -720,12 +718,6 @@ int_range::operator= (const int_range &src) } inline void -irange::set (tree val) -{ - set (val, val); -} - -inline void irange::set_undefined () { m_kind = VR_UNDEFINED; @@ -765,12 +757,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. @@ -846,7 +832,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); } -- cgit v1.1 From 4e82205b68024f5c1a9006fe2b62e1a0fa7f1245 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 1 Jul 2022 13:20:42 +0200 Subject: Integrate nonzero bits with irange. The nonzero bits and integer ranges compliment each other quite well, and it only makes sense to make the mask a first class citizen in the irange. We do a half assed job of keeping ranges and nonzero bits somewhat in sync in SSA_NAME_RANGE_INFO, and the goal has always been to integrate them properly. This patch does that, in preparation for streaming out full-resolution iranges between passes (think SSA_NAME_RANGE_INFO). Having nonzero bits in the irange allows us to get better results from things like irange::contains_p() and keeping them in the irange allows us to propagate the bits throughout with the ranger. This patch provides the bare infrastructure, without any optimizations to range-ops, etc. Those will come as follow-ups. A few notes: Legacy SSA_NAME_RANGE_INFO updates the nonzero bits every time a range is set. Here instead, we don't update the nonzero bits on a new range, but calculate it on the fly when irange::get_nonzero_bits() is called. The goal is to only store nonzero bits that provide meaningful information that can't be gleaned from the range itself. But you can always call get_nonzero_bits() and get the full information. Nonzero bits are not supported in legacy mode. The mask may be set as a consequence of propagation or reading global ranges, but no one from legacy land should be querying irange::get_nonzero_bits. There is an assert enforcing this. However, legacy/global set_nonzero_bits() continue to work as before. There is no change to legacy behavior. There is virtually no performance change with this patch, as there are no consumers. The next patch I post will be the SSA_NAME_RANGE_INFO conversion to the new world, in which I will discuss performance proper. Hint: I'll be chewing up the time budget we gained with the vrange conversion. Tested and benchmarked on x86-64 Linux. gcc/ChangeLog: * value-range-storage.cc (irange_storage_slot::set_irange): Set nonzero bits in irange. (irange_storage_slot::get_irange): Get nonzero bits from irange. * value-range.cc (irange::operator=): Set nonzero bits. (irange::irange_set): Same. (irange::irange_set_anti_range): Same. (irange::set): Same. (irange::verify_range): Same. (irange::legacy_equal_p): Check nonzero bits. (irange::equal_p): Same. (irange::contains_p): Handle nonzero bits. (irange::irange_union): Same. (irange::irange_intersect): Same. (irange::dump): Same. (irange::set_nonzero_bits): New. (irange::get_nonzero_bits): New. (irange::intersect_nonzero_bits): New. (irange::union_nonzero_bits): New. (irange::dump_bitmasks): New. * value-range.h (class irange): Add m_nonzero_mask. (gt_ggc_mx): Handle nonzero bits. (gt_pch_nx): Same. (irange::set_undefined): Set nonzero bits. (irange::set_varying): Same. (irange::normalize_kind): Call set_undefined. --- gcc/value-range.h | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index fd67031..2e48d92 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -109,6 +109,7 @@ protected: class GTY((user)) irange : public vrange { friend class vrange_allocator; + friend class irange_storage_slot; // For legacy_mode_p checks. public: // In-place setters. virtual void set (tree, tree, value_range_kind = VR_RANGE) override; @@ -149,6 +150,10 @@ public: virtual bool fits_p (const vrange &r) const override; virtual void dump (FILE * = stderr) const override; + // Nonzero masks. + wide_int get_nonzero_bits () const; + void set_nonzero_bits (const wide_int_ref &bits); + // Deprecated legacy public methods. tree min () const; // DEPRECATED tree max () const; // DEPRECATED @@ -196,10 +201,15 @@ private: void irange_set_1bit_anti_range (tree, tree); bool varying_compatible_p () const; + void set_nonzero_bits (tree bits) { m_nonzero_mask = bits; } + bool intersect_nonzero_bits (const irange &r); + bool union_nonzero_bits (const irange &r); + void dump_bitmasks (FILE *) const; bool intersect (const wide_int& lb, const wide_int& ub); unsigned char m_num_ranges; unsigned char m_max_ranges; + tree m_nonzero_mask; tree *m_base; }; @@ -608,6 +618,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 @@ -618,6 +630,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 @@ -628,6 +642,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 @@ -722,6 +738,7 @@ irange::set_undefined () { m_kind = VR_UNDEFINED; m_num_ranges = 0; + m_nonzero_mask = NULL; } inline void @@ -729,6 +746,7 @@ irange::set_varying (tree type) { m_kind = VR_VARYING; m_num_ranges = 1; + m_nonzero_mask = NULL; if (INTEGRAL_TYPE_P (type)) { @@ -843,7 +861,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) -- cgit v1.1 From c106825b936446c346d49ef10952e40370753b9d Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Sat, 9 Jul 2022 17:43:47 +0200 Subject: Cleanups to irange::nonzero bit code. In discussions with Andrew we realized varying_p() was returning true for a range of the entire domain with a non-empty nonzero mask. This is confusing as varying_p() should only return true when absolutely no information is available. A nonzero mask that has any cleared bits is extra information and must return false for varying_p(). This patch fixes this oversight. Now a range of the entire domain with nonzero bits, is internally set to VR_RANGE (with the appropriate end points set). VR_VARYING ranges must have a null nonzero mask. Also, the union and intersect code were not quite right in the presence of nonzero masks. Sometimes we would drop masks to -1 unnecessarily. I was trying to be too smart in avoiding extra work when the mask was NULL, but there's also an implicit mask in the range that must be taken into account. For example, [0,0] may have no nonzero bits set explicitly, but the mask is really 0x0. This will all be simpler when we drop trees, because the nonzero bits will always be set, even if -1. Finally, I've added unit tests to the nonzero mask code. This should help us maintain sanity going forward. There should be no visible changes, as the main consumer of this code is the SSA_NAME_RANGE_INFO patchset which has yet to be committed. Tested on x86-64 Linux. gcc/ChangeLog: * value-range.cc (irange::operator=): Call verify_range. (irange::irange_set): Normalize kind after everything else has been set. (irange::irange_set_anti_range): Same. (irange::set): Same. (irange::verify_range): Disallow nonzero masks for VARYING. (irange::irange_union): Call verify_range. Handle nonzero masks better. (irange::irange_intersect): Same. (irange::set_nonzero_bits): Calculate mask if either range has an explicit mask. (irange::intersect_nonzero_bits): Same. (irange::union_nonzero_bits): Same. (range_tests_nonzero_bits): New. (range_tests): Call range_tests_nonzero_bits. * value-range.h (class irange): Remove set_nonzero_bits method with trees. (irange::varying_compatible_p): Set nonzero mask. --- gcc/value-range.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index 2e48d92..0e34118 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -201,7 +201,7 @@ private: void irange_set_1bit_anti_range (tree, tree); bool varying_compatible_p () const; - void set_nonzero_bits (tree bits) { m_nonzero_mask = bits; } + void set_nonzero_bits (tree mask); bool intersect_nonzero_bits (const irange &r); bool union_nonzero_bits (const irange &r); void dump_bitmasks (FILE *) const; @@ -555,7 +555,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)); -- cgit v1.1 From 91a7f30662cd8da14f0ae5eec1ce13aa29f1817c Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Thu, 14 Jul 2022 19:01:34 +0200 Subject: Implement visitor pattern for vrange. We frequently do operations on the various (upcoming) range types. The cascading if/switch statements of is_a<> are getting annoying and repetitive. The classic visitor pattern provides a clean way to implement classes handling various range types without the need for endless conditionals. It also helps us keep polluting the vrange API with functionality that should frankly live elsewhere. In a follow-up patch I will add pretty printing facilities for vrange and unify them with the dumping code. This is a prime candidate for the pattern, as the code isn't performance sensitive. Other instances (?? the dispatch code in range-ops ??) may still benefit from the hand coded conditionals, since they elide vtables in favor of the discriminator bit in vrange. Tested on x86-64 Linux. gcc/ChangeLog: * value-range.cc (irange::accept): New. (unsupported_range::accept): New. * value-range.h (class vrange_visitor): New. (class vrange): Add accept method. (class unsupported_range): Same. (class Value_Range): Same. --- gcc/value-range.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index 0e34118..a7da8c5 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -73,6 +73,7 @@ class vrange template 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 (tree type) const; @@ -149,6 +150,7 @@ public: // Misc methods. virtual bool fits_p (const vrange &r) const override; virtual void dump (FILE * = stderr) const override; + virtual void accept (const vrange_visitor &v) const override; // Nonzero masks. wide_int get_nonzero_bits () const; @@ -251,6 +253,7 @@ class unsupported_range : public vrange public: unsupported_range (); virtual void dump (FILE *) const override; + virtual void accept (const vrange_visitor &v) const override; }; // is_a<> and as_a<> implementation for vrange. @@ -298,6 +301,13 @@ is_a (vrange &v) return v.m_discriminator == VR_IRANGE; } +class vrange_visitor +{ +public: + virtual void visit (const irange &) 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 @@ -348,6 +358,7 @@ public: 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; -- cgit v1.1 From 64864aa9e6ea347a4f9c7027941be898ce993f85 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Thu, 14 Jul 2022 19:04:09 +0200 Subject: Convert vrange dumping facilities to pretty_printer. We need to dump global ranges from the gimple pretty printer code, but all the vrange dumping facilities work with FILE handles. This patch converts all the dumping methods to work with pretty printers, and provides a wrapper so the FILE * methods continue to work for debugging. I also cleaned up the code a bit. Tested on x86-64 Linux. gcc/ChangeLog: * Makefile.in (OBJS): Add value-range-pretty-print.o. * pretty-print.h (pp_vrange): New. * value-range.cc (vrange::dump): Call pp version. (unsupported_range::dump): Move to its own file. (dump_bound_with_infinite_markers): Same. (irange::dump): Same. (irange::dump_bitmasks): Same. (vrange::debug): Remove. * value-range.h: Remove virtual designation for dump methods. Remove dump_bitmasks method. * value-range-pretty-print.cc: New file. * value-range-pretty-print.h: New file. --- gcc/value-range.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index a7da8c5..4af92fd 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -79,7 +79,6 @@ public: virtual bool supports_type_p (tree type) const; virtual void set_varying (tree type); virtual void set_undefined (); - virtual void dump (FILE * = stderr) const = 0; virtual bool union_ (const vrange &); virtual bool intersect (const vrange &); virtual bool singleton_p (tree *result = NULL) const; @@ -96,9 +95,9 @@ public: vrange& operator= (const vrange &); bool operator== (const vrange &) const; bool operator!= (const vrange &r) const { return !(*this == r); } + void dump (FILE *) const; enum value_range_kind kind () const; // DEPRECATED - void debug () const; protected: ENUM_BITFIELD(value_range_kind) m_kind : 8; @@ -149,7 +148,6 @@ public: // Misc methods. virtual bool fits_p (const vrange &r) const override; - virtual void dump (FILE * = stderr) const override; virtual void accept (const vrange_visitor &v) const override; // Nonzero masks. @@ -206,7 +204,6 @@ private: void set_nonzero_bits (tree mask); bool intersect_nonzero_bits (const irange &r); bool union_nonzero_bits (const irange &r); - void dump_bitmasks (FILE *) const; bool intersect (const wide_int& lb, const wide_int& ub); unsigned char m_num_ranges; @@ -252,7 +249,6 @@ class unsupported_range : public vrange { public: unsupported_range (); - virtual void dump (FILE *) const override; virtual void accept (const vrange_visitor &v) const override; }; @@ -339,7 +335,7 @@ public: bool operator!= (const Value_Range &r) const; operator vrange &(); operator const vrange &() const; - void dump (FILE *out = stderr) const; + void dump (FILE *) const; static bool supports_type_p (tree type); // Convenience methods for vrange compatability. -- cgit v1.1 From 1a10bd84a5d103f6e1fdcd960f8377e3d099d773 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Sun, 24 Jul 2022 19:42:11 +0200 Subject: frange class to represent floating point ranges This implements a basic frange class to represent floating point ranges. Although it is meant to be a base for further development, it is enough to handle relations and propagate NAN and other properties. For ranger clients to become floating point aware, we still need the range-op entries, which I will submit later this week. Since those entries require specialized FP knowledge, I will ask for a review from the FP experts before committing. Once range-op entries come live, all ranger clients that have been converted to the type agnostic vrange API will become FP aware: evrp, DOM, the threaders, loop-ch, etc. (Still missing is loop unswitching, as a lot of the int_range* temporaries should be Value_Range. I don't have enough cycles to convert loop unswitching, but could gladly give guidance. It should be straightforward for those familiar with the code ;-)). Samples things we handle: * We can set the FP properties (!NAN, !INF, etc) at assignment from constants (and propagate them throughout the CFG): float z = 0.0; if (__builtin_isnan (z)) link_error (); * The relation oracle works in tandem with the FP ranges: if (x > y) ; else if (!__builtin_isnan (x) && !__builtin_isnan (y)) { // If x and y are not NAN, the x <= y relationship holds, and the // following conditional can be folded away. if (x <= y) bar (); } * We know the true side of all ordered conditionals (except !=) implies !NAN: if (x > y) { if (__builtin_isnan (x) || __builtin_isnan (y)) link_error (); } Range-ops also works correctly with -ffinite-math-only, and avoids checking for NANs, etc. I believe this is enough to get a fully fleshed out floating point support for evrp and friends, but doing so is beyond my limited FP knowledge. For example, frange could be enhanced to track constant endpoints, and we could track other FP properties aside from NAN. Further discussion is gladly welcome. Tested on x86-64 Linux. gcc/ChangeLog: * value-range-pretty-print.cc (vrange_printer::visit): New. (vrange_printer::print_frange_prop): New. * value-range-pretty-print.h (class vrange_printer): Add visit and print_frange_prop. * value-range-storage.h (vrange_allocator::alloc_vrange): Handle frange. (vrange_allocator::alloc_frange): New. * value-range.cc (vrange::operator=): Handle frange. (vrange::operator==): Same. (frange::accept): New. (frange::set): New. (frange::normalize_kind): New. (frange::union_): New. (frange::intersect): New. (frange::operator=): New. (frange::operator==): New. (frange::supports_type_p): New. (frange::verify_range): New. * value-range.h (enum value_range_discriminator): Handle frange. (class fp_prop): New. (FP_PROP_ACCESSOR): New. (class frange_props): New. (FRANGE_PROP_ACCESSOR): New. (class frange): New. (Value_Range::init): Handle frange. (Value_Range::operator=): Same. (Value_Range::supports_type_p): Same. (frange_props::operator==): New. (frange_props::union_): New. (frange_props::intersect): New (frange::frange): New. (frange::type): New. (frange::set_varying): New. (frange::set_undefined): New. --- gcc/value-range.h | 194 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 193 insertions(+), 1 deletion(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index 4af92fd..e43fbe3 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -45,6 +45,8 @@ enum value_range_discriminator { // Range holds an integer or pointer. VR_IRANGE, + // Floating point range. + VR_FRANGE, // Range holds an unsupported type. VR_UNKNOWN }; @@ -252,6 +254,117 @@ public: 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 (tree type) + { + // Disabled until floating point range-ops come live. + return 0 && 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 (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 (); + void 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. @@ -297,10 +410,18 @@ is_a (vrange &v) return v.m_discriminator == VR_IRANGE; } +template <> +inline bool +is_a (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 { } }; @@ -360,6 +481,7 @@ private: unsupported_range m_unsupported; vrange *m_vrange; int_range_max m_irange; + frange m_frange; }; inline @@ -401,6 +523,8 @@ Value_Range::init (tree 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; } @@ -426,6 +550,11 @@ Value_Range::operator= (const vrange &r) m_irange = as_a (r); m_vrange = &m_irange; } + else if (is_a (r)) + { + m_frange = as_a (r); + m_vrange = &m_frange; + } else gcc_unreachable (); @@ -461,7 +590,7 @@ Value_Range::operator const vrange &() const inline bool Value_Range::supports_type_p (tree type) { - return irange::supports_p (type); + return irange::supports_p (type) || frange::supports_p (type); } // Returns true for an old-school value_range as described above. @@ -881,6 +1010,69 @@ irange::normalize_kind () } } + +// Supporting methods for frange. + +inline bool +frange_props::operator== (const frange_props &other) const +{ + return u.bytes == other.u.bytes; +} + +inline bool +frange_props::union_ (const frange_props &other) +{ + unsigned char saved = u.bytes; + u.bytes |= other.u.bytes; + return u.bytes != saved; +} + +inline bool +frange_props::intersect (const frange_props &other) +{ + unsigned char saved = u.bytes; + u.bytes &= other.u.bytes; + return u.bytes != saved; +} + +inline +frange::frange () +{ + m_discriminator = VR_FRANGE; + m_type = nullptr; + set_undefined (); +} + +inline +frange::frange (const frange &src) +{ + m_discriminator = VR_FRANGE; + *this = src; +} + +inline tree +frange::type () const +{ + return m_type; +} + +inline void +frange::set_varying (tree type) +{ + m_kind = VR_VARYING; + m_type = type; + m_props.set_varying (); +} + +inline void +frange::set_undefined () +{ + m_kind = VR_UNDEFINED; + m_type = NULL; + m_props.set_undefined (); +} + + // Return the maximum value for TYPE. inline tree -- cgit v1.1 From 7e029e067d81f714419cd196fdd506b06881e0c9 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Sun, 31 Jul 2022 13:36:59 +0200 Subject: const_tree conversion of vrange::supports_* Make all vrange::supports_*_p methods const_tree as they can end up being called from functions that are const_tree. Tested on x86-64 Linux. gcc/ChangeLog: * value-range.cc (vrange::supports_type_p): Use const_tree. (irange::supports_type_p): Same. (frange::supports_type_p): Same. * value-range.h (Value_Range::supports_type_p): Same. (irange::supports_p): Same. --- gcc/value-range.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index e43fbe3..c6ab955 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -78,7 +78,7 @@ 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 (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 &); @@ -122,8 +122,8 @@ public: virtual void set_undefined () override; // Range types. - static bool supports_p (tree type); - virtual bool supports_type_p (tree type) const override; + 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. @@ -336,7 +336,7 @@ class frange : public vrange public: frange (); frange (const frange &); - static bool supports_p (tree type) + static bool supports_p (const_tree type) { // Disabled until floating point range-ops come live. return 0 && SCALAR_FLOAT_TYPE_P (type); @@ -347,7 +347,7 @@ public: virtual void set_undefined () override; virtual bool union_ (const vrange &) override; virtual bool intersect (const vrange &) override; - virtual bool supports_type_p (tree type) const 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; @@ -457,7 +457,7 @@ public: operator vrange &(); operator const vrange &() const; void dump (FILE *) const; - static bool supports_type_p (tree type); + 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) @@ -588,7 +588,7 @@ Value_Range::operator const vrange &() const // Return TRUE if TYPE is supported by the vrange infrastructure. inline bool -Value_Range::supports_type_p (tree type) +Value_Range::supports_type_p (const_tree type) { return irange::supports_p (type) || frange::supports_p (type); } @@ -730,7 +730,7 @@ irange::nonzero_p () const } inline bool -irange::supports_p (tree type) +irange::supports_p (const_tree type) { return INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type); } -- cgit v1.1 From 3f05605364f6f17b84842a8a5960d465b4448bae Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Sun, 31 Jul 2022 13:43:36 +0200 Subject: Cleanups to frange. These are some assorted cleanups to the frange class to make it easier to drop in an implementation with FP endpoints: * frange::set() had some asserts limiting the type of arguments passed. There's no reason why we can't handle all the variants. Worse comes to worse, we can always return a VARYING which is conservative and correct. * frange::normalize_kind() now returns a boolean that can be used in union and intersection to indicate that the range changed. * Implement vrp_val_max and vrp_val_min for floats. Also, move them earlier in the header file so frange can use them. Tested on x86-64 Linux. gcc/ChangeLog: * value-range.cc (tree_compare): New. (frange::set): Make more general. (frange::normalize_kind): Cleanup and return bool. (frange::union_): Use normalize_kind return value. (frange::intersect): Same. (frange::verify_range): Remove unnecessary else. * value-range.h (vrp_val_max): Move before frange class. (vrp_val_min): Same. (frange::frange): Remove set to m_type. --- gcc/value-range.h | 70 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 40 insertions(+), 30 deletions(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index c6ab955..390fcb8 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -359,7 +359,7 @@ public: FRANGE_PROP_ACCESSOR(ninf) private: void verify_range (); - void normalize_kind (); + bool normalize_kind (); frange_props m_props; tree m_type; @@ -1010,6 +1010,45 @@ irange::normalize_kind () } } +// Return the maximum value for TYPE. + +inline tree +vrp_val_max (const_tree type) +{ + if (INTEGRAL_TYPE_P (type)) + return TYPE_MAX_VALUE (type); + if (POINTER_TYPE_P (type)) + { + wide_int max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)); + return wide_int_to_tree (const_cast (type), max); + } + if (frange::supports_p (type)) + { + REAL_VALUE_TYPE real; + real_inf (&real); + return build_real (const_cast (type), real); + } + return NULL_TREE; +} + +// Return the minimum value for TYPE. + +inline tree +vrp_val_min (const_tree type) +{ + if (INTEGRAL_TYPE_P (type)) + return TYPE_MIN_VALUE (type); + if (POINTER_TYPE_P (type)) + return build_zero_cst (const_cast (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 (type), real_ninf); + } + return NULL_TREE; +} // Supporting methods for frange. @@ -1039,7 +1078,6 @@ inline frange::frange () { m_discriminator = VR_FRANGE; - m_type = nullptr; set_undefined (); } @@ -1072,32 +1110,4 @@ frange::set_undefined () m_props.set_undefined (); } - -// Return the maximum value for TYPE. - -inline tree -vrp_val_max (const_tree type) -{ - if (INTEGRAL_TYPE_P (type)) - return TYPE_MAX_VALUE (type); - if (POINTER_TYPE_P (type)) - { - wide_int max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type)); - return wide_int_to_tree (const_cast (type), max); - } - return NULL_TREE; -} - -// Return the minimum value for TYPE. - -inline tree -vrp_val_min (const_tree type) -{ - if (INTEGRAL_TYPE_P (type)) - return TYPE_MIN_VALUE (type); - if (POINTER_TYPE_P (type)) - return build_zero_cst (const_cast (type)); - return NULL_TREE; -} - #endif // GCC_VALUE_RANGE_H -- cgit v1.1 From 24012539ae3410174b3e755b580a16de826d56a6 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Mon, 25 Jul 2022 16:47:48 +0200 Subject: Implement basic range operators to enable floating point VRP. Without further ado, here is the implementation for floating point range operators, plus the switch to enable all ranger clients to handle floats. These are bare bone implementations good enough for relation operators to work, while keeping the NAN bits up to date in the frange. There is also minimal support for keeping track of +-INF when it is obvious. Tested on x86-64 Linux. gcc/ChangeLog: * range-op-float.cc (finite_operands_p): New. (frelop_early_resolve): New. (default_frelop_fold_range): New. (class foperator_equal): New. (class foperator_not_equal): New. (class foperator_lt): New. (class foperator_le): New. (class foperator_gt): New. (class foperator_ge): New. (class foperator_unordered): New. (class foperator_ordered): New. (class foperator_relop_unknown): New. (floating_op_table::floating_op_table): Add above classes to floating op table. * value-range.h (frange::supports_p): Enable. gcc/testsuite/ChangeLog: * g++.dg/opt/pr94589-2.C: XFAIL. * gcc.dg/tree-ssa/vrp-float-1.c: New test. * gcc.dg/tree-ssa/vrp-float-11.c: New test. * gcc.dg/tree-ssa/vrp-float-3.c: New test. * gcc.dg/tree-ssa/vrp-float-4.c: New test. * gcc.dg/tree-ssa/vrp-float-6.c: New test. * gcc.dg/tree-ssa/vrp-float-7.c: New test. * gcc.dg/tree-ssa/vrp-float-8.c: New test. --- gcc/value-range.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index 390fcb8..305e2ca 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -338,8 +338,7 @@ public: frange (const frange &); static bool supports_p (const_tree type) { - // Disabled until floating point range-ops come live. - return 0 && SCALAR_FLOAT_TYPE_P (type); + return SCALAR_FLOAT_TYPE_P (type); } virtual tree type () const override; virtual void set (tree, tree, value_range_kind = VR_RANGE) override; -- cgit v1.1 From 47964e766270f349f5b171bcd68ff7c1e60d85d8 Mon Sep 17 00:00:00 2001 From: Aldy Hernandez Date: Fri, 5 Aug 2022 08:04:10 +0200 Subject: Inline unsupported_range constructor. An unsupported_range temporary is instantiated in every Value_Range for completeness sake and should be mostly a NOP. However, it's showing up in the callgrind stats, because it's not inline. This fixes the oversight. PR tree-optimization/106514 gcc/ChangeLog: * value-range.cc (unsupported_range::unsupported_range): Move... * value-range.h (unsupported_range::unsupported_range): ...here. (unsupported_range::set_undefined): New. --- gcc/value-range.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index 305e2ca..856947d 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -250,7 +250,15 @@ private: class unsupported_range : public vrange { public: - unsupported_range (); + 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; }; -- cgit v1.1 From 83bacf93844116c43d8a671b279875713f37e351 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Tue, 16 Aug 2022 11:15:30 +0200 Subject: VR: add more virtual dtors Add 2 virtual destructors in order to address: gcc/alloc-pool.h:522:5: warning: destructor called on non-final 'value_range_equiv' that has virtual functions but non-virtual destructor [-Wdelete-non-abstract-non-virtual-dtor] gcc/ggc.h:166:3: warning: destructor called on non-final 'int_range<1>' that has virtual functions but non-virtual destructor [-Wdelete-non-abstract-non-virtual-dtor] gcc/ChangeLog: * value-range-equiv.h (class value_range_equiv): Add virtual destructor. * value-range.h: Likewise. --- gcc/value-range.h | 1 + 1 file changed, 1 insertion(+) (limited to 'gcc/value-range.h') diff --git a/gcc/value-range.h b/gcc/value-range.h index 856947d..f0075d0 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -228,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 friend void gt_ggc_mx (int_range *); -- cgit v1.1