public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 1/5] Implement abstract vrange class.
@ 2022-05-30 13:27 Aldy Hernandez
  2022-05-30 13:27 ` [PATCH 2/5] Implement generic range temporaries Aldy Hernandez
                   ` (4 more replies)
  0 siblings, 5 replies; 14+ messages in thread
From: Aldy Hernandez @ 2022-05-30 13:27 UTC (permalink / raw)
  To: GCC patches

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-equiv.cc |   6 ++
 gcc/value-range-equiv.h  |   3 +-
 gcc/value-range.cc       | 168 ++++++++++++++++++++++++++++++++-
 gcc/value-range.h        | 195 ++++++++++++++++++++++++++++++++-------
 gcc/vr-values.cc         |   6 +-
 5 files changed, 338 insertions(+), 40 deletions(-)

diff --git a/gcc/value-range-equiv.cc b/gcc/value-range-equiv.cc
index 77c6f5ca99d..b0ae1288a09 100644
--- a/gcc/value-range-equiv.cc
+++ b/gcc/value-range-equiv.cc
@@ -50,6 +50,12 @@ value_range_equiv::set (tree min, tree max, bitmap equiv,
     check ();
 }
 
+void
+value_range_equiv::set (tree min, tree max, value_range_kind kind)
+{
+  set (min, max, m_equiv, kind);
+}
+
 void
 value_range_equiv::set (tree val)
 {
diff --git a/gcc/value-range-equiv.h b/gcc/value-range-equiv.h
index 0aa1069cb61..743ceb2b227 100644
--- a/gcc/value-range-equiv.h
+++ b/gcc/value-range-equiv.h
@@ -41,9 +41,10 @@ class GTY((user)) value_range_equiv : public value_range
   void move (value_range_equiv *);
 
   /* Leaves equiv bitmap alone.  */
+  virtual void set (tree, tree, value_range_kind = VR_RANGE) override;
   void update (tree, tree, value_range_kind = VR_RANGE);
   /* Deep-copies equiv bitmap argument.  */
-  void set (tree, tree, bitmap = NULL, value_range_kind = VR_RANGE);
+  void set (tree, tree, bitmap, value_range_kind = VR_RANGE);
   void set (tree);
 
   bool operator== (const value_range_equiv &) const /* = delete */;
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 2e7385aecc2..97ff0614f48 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -30,6 +30,162 @@ along with GCC; see the file COPYING3.  If not see
 #include "fold-const.h"
 #include "gimple-range.h"
 
+// Default implementation when none has been defined.
+
+bool
+vrange::contains_p (tree) const
+{
+  return false;
+}
+
+// Default implementation when none has been defined.
+
+bool
+vrange::singleton_p (tree *) const
+{
+  return false;
+}
+
+// Assignment operator for generic ranges.  Copying incompatible types
+// is not allowed.
+
+vrange &
+vrange::operator= (const vrange &src)
+{
+  if (is_a <irange> (src))
+    {
+      as_a <irange> (*this) = as_a <irange> (src);
+      return *this;
+    }
+  else
+    gcc_unreachable ();
+}
+
+// Equality operator for generic ranges.
+
+bool
+vrange::operator== (const vrange &src) const
+{
+  if (is_a <irange> (src))
+    return as_a <irange> (*this) == as_a <irange> (src);
+  gcc_unreachable ();
+}
+
+// Return TRUE if R fits in THIS.
+
+bool
+irange::fits_p (const vrange &r) const
+{
+  return m_max_ranges >= as_a <irange> (r).num_pairs ();
+}
+
+void
+irange::set_nonnegative (tree type)
+{
+  set (build_int_cst (type, 0), TYPE_MAX_VALUE (type));
+}
+
+unsupported_range::unsupported_range ()
+{
+  m_discriminator = VR_UNKNOWN;
+  set_undefined ();
+}
+
+void
+unsupported_range::set (tree, tree, value_range_kind)
+{
+  gcc_unreachable ();
+}
+
+tree
+unsupported_range::type () const
+{
+  gcc_unreachable ();
+  return nullptr;
+}
+
+void
+unsupported_range::set_undefined ()
+{
+  m_kind = VR_UNDEFINED;
+}
+
+void
+unsupported_range::set_varying (tree)
+{
+  gcc_unreachable ();
+}
+
+void
+unsupported_range::dump (FILE *file) const
+{
+  fprintf (file, "[unsupported_range] ");
+  if (undefined_p ())
+    {
+      fprintf (file, "UNDEFINED");
+      return;
+    }
+  if (varying_p ())
+    {
+      fprintf (file, "VARYING");
+      return;
+    }
+  gcc_unreachable ();
+}
+
+bool
+unsupported_range::union_ (const vrange &)
+{
+  gcc_unreachable ();
+  return false;
+}
+
+bool
+unsupported_range::intersect (const vrange &)
+{
+  gcc_unreachable ();
+  return false;
+}
+
+bool
+unsupported_range::zero_p () const
+{
+  gcc_unreachable ();
+  return false;
+}
+
+bool
+unsupported_range::nonzero_p () const
+{
+  gcc_unreachable ();
+  return false;
+}
+
+void
+unsupported_range::set_nonzero (tree)
+{
+  gcc_unreachable ();
+}
+
+void
+unsupported_range::set_zero (tree)
+{
+  gcc_unreachable ();
+}
+
+void
+unsupported_range::set_nonnegative (tree)
+{
+  gcc_unreachable ();
+}
+
+bool
+unsupported_range::fits_p (const vrange &) const
+{
+  gcc_unreachable ();
+  return false;
+}
+
 // Here we copy between any two irange's.  The ranges can be legacy or
 // multi-ranges, and copying between any combination works correctly.
 
@@ -291,7 +447,7 @@ irange::set (tree min, tree max, value_range_kind kind)
     }
   if (kind == VR_UNDEFINED)
     {
-      set_undefined ();
+      irange::set_undefined ();
       return;
     }
 
@@ -370,6 +526,7 @@ irange::set (tree min, tree max, value_range_kind kind)
 void
 irange::verify_range ()
 {
+  gcc_checking_assert (m_discriminator == VR_IRANGE);
   if (m_kind == VR_UNDEFINED)
     {
       gcc_checking_assert (m_num_ranges == 0);
@@ -2087,6 +2244,7 @@ dump_bound_with_infinite_markers (FILE *file, tree bound)
 void
 irange::dump (FILE *file) const
 {
+  fprintf (file, "[irange] ");
   if (undefined_p ())
     {
       fprintf (file, "UNDEFINED");
@@ -2121,27 +2279,27 @@ irange::dump (FILE *file) const
 }
 
 void
-irange::debug () const
+vrange::debug () const
 {
   dump (stderr);
   fprintf (stderr, "\n");
 }
 
 void
-dump_value_range (FILE *file, const irange *vr)
+dump_value_range (FILE *file, const vrange *vr)
 {
   vr->dump (file);
 }
 
 DEBUG_FUNCTION void
-debug (const irange *vr)
+debug (const vrange *vr)
 {
   dump_value_range (stderr, vr);
   fprintf (stderr, "\n");
 }
 
 DEBUG_FUNCTION void
-debug (const irange &vr)
+debug (const vrange &vr)
 {
   debug (&vr);
 }
diff --git a/gcc/value-range.h b/gcc/value-range.h
index ec59d2e4f23..0061f667092 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 <typename T> friend bool is_a (vrange &);
+public:
+  virtual void set (tree, tree, value_range_kind = VR_RANGE) = 0;
+  virtual tree type () const = 0;
+  virtual void set_varying (tree type) = 0;
+  virtual void set_undefined () = 0;
+  virtual void dump (FILE * = stderr) const = 0;
+  virtual bool union_ (const vrange &) = 0;
+  virtual bool intersect (const vrange &) = 0;
+  virtual bool singleton_p (tree *result = NULL) const;
+  virtual bool contains_p (tree cst) const;
+  virtual bool zero_p () const = 0;
+  virtual bool nonzero_p () const = 0;
+  virtual void set_nonzero (tree type) = 0;
+  virtual void set_zero (tree type) = 0;
+  virtual void set_nonnegative (tree type) = 0;
+  virtual bool fits_p (const vrange &r) const = 0;
+
+  static bool supports_type_p (tree);
+
+  bool varying_p () const;
+  bool undefined_p () const;
+  vrange& operator= (const vrange &);
+  bool operator== (const vrange &) const;
+  bool operator!= (const vrange &r) const { return !(*this == r); }
+
+  enum value_range_kind kind () const;		// DEPRECATED
+  void debug () const;
+
+protected:
+  ENUM_BITFIELD(value_range_kind) m_kind : 8;
+  ENUM_BITFIELD(value_range_discriminator) m_discriminator : 4;
+};
+
+// An integer range without any storage.
 
-class GTY((user)) irange
+class GTY((user)) irange : public vrange
 {
   friend class irange_allocator;
 public:
   // In-place setters.
-  void set (tree, tree, value_range_kind = VR_RANGE);
-  void set_nonzero (tree);
-  void set_zero (tree);
-  void set_varying (tree type);
-  void set_undefined ();
+  virtual void set (tree, tree, value_range_kind = VR_RANGE) override;
+  virtual void set_nonzero (tree type) override;
+  virtual void set_zero (tree type) override;
+  virtual void set_nonnegative (tree type) override;
+  virtual void set_varying (tree type) override;
+  virtual void set_undefined () override;
 
   // Range types.
   static bool supports_type_p (tree);
-  tree type () const;
+  virtual tree type () const override;
 
   // Iteration over sub-ranges.
   unsigned num_pairs () const;
@@ -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<typename T>
+struct vrange_traits
+{
+  // Default to something unusable.
+  typedef void range_type;
+};
+
+template<>
+struct vrange_traits<irange>
+{
+  typedef irange range_type;
+};
+
+template <typename T>
+inline bool
+is_a (vrange &v)
+{
+  gcc_unreachable ();
+  return false;
+}
+
+template <typename T>
+inline bool
+is_a (const vrange &v)
+{
+  // Reuse is_a <vrange> to implement the const version.
+  const T &derived = static_cast<const T &> (v);
+  return is_a <T> (const_cast<T &> (derived));
+}
+
+template <typename T>
+inline T &
+as_a (vrange &v)
+{
+  typedef typename vrange_traits<T>::range_type range_type;
+  gcc_checking_assert (is_a <range_type> (v));
+  return static_cast <range_type &> (v);
+}
+
+template <typename T>
+inline const T &
+as_a (const vrange &v)
+{
+  typedef typename vrange_traits<T>::range_type range_type;
+  gcc_checking_assert (is_a <range_type> (v));
+  return static_cast <const range_type &> (v);
+}
+
+// Specializations for the different range types.
+
+template <>
+inline bool
+is_a <irange> (vrange &v)
+{
+  return v.m_discriminator == VR_IRANGE;
+}
+
 // This is a special int_range<1> with only one pair, plus
 // VR_ANTI_RANGE magic to describe slightly more than can be described
 // in one pair.  It is described in the code as a "legacy range" (as
@@ -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<N> *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 <irange> (r));
   dump_flags = m_flags;
   return ret;
 }
 
 inline bool
-irange::intersect (const irange &r)
+irange::intersect (const vrange &r)
 {
   dump_flags_t m_flags = dump_flags;
   dump_flags &= ~TDF_DETAILS;
-  bool ret = irange::legacy_verbose_intersect (&r);
+  bool ret = irange::legacy_verbose_intersect (&as_a <irange> (r));
   dump_flags = m_flags;
   return ret;
 }
@@ -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
diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc
index 47faa4ff938..6f8583c8d01 100644
--- a/gcc/vr-values.cc
+++ b/gcc/vr-values.cc
@@ -883,7 +883,7 @@ vr_values::extract_range_from_binary_expr (value_range_equiv *vr,
 	      wide_int wmax = wi::to_wide (max, TYPE_PRECISION (TREE_TYPE (max)));
 	      tree range_min = build_zero_cst (expr_type);
 	      tree range_max = wide_int_to_tree (expr_type, wmax - 1);
-	      vr->set (range_min, range_max);
+	      vr->set (range_min, range_max, NULL);
 	      return;
 	    }
      }
@@ -1275,7 +1275,7 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
 		      /* This is the boolean return value whether compare and
 			 exchange changed anything or not.  */
 		      vr->set (build_int_cst (type, 0),
-			       build_int_cst (type, 1));
+			       build_int_cst (type, 1), NULL);
 		      return;
 		    }
 		  break;
@@ -1297,7 +1297,7 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
 			vr->set_varying (type);
 		      else
 			vr->set (build_int_cst (type, 0),
-				 build_int_cst (type, 1));
+				 build_int_cst (type, 1), NULL);
 		    }
 		  else if (types_compatible_p (type, TREE_TYPE (op0))
 			   && types_compatible_p (type, TREE_TYPE (op1)))
-- 
2.36.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 2/5] Implement generic range temporaries.
  2022-05-30 13:27 [PATCH 1/5] Implement abstract vrange class Aldy Hernandez
@ 2022-05-30 13:27 ` Aldy Hernandez
  2022-05-30 14:56   ` Andrew MacLeod
  2022-05-30 13:27 ` [PATCH 3/5] Convert range-op.* to vrange Aldy Hernandez
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 14+ messages in thread
From: Aldy Hernandez @ 2022-05-30 13:27 UTC (permalink / raw)
  To: GCC patches

Now that we have generic ranges, we need a way to define generic local
temporaries on the stack for intermediate calculations in the ranger
and elsewhere.  We need temporaries analogous to int_range_max, but
for any of the supported types (currently just integers, but soon
integers, pointers, and floats).

The tmp_range object is such a temporary.  It is designed to be
transparently used as a vrange.  It shares vrange's abstract API, and
implicitly casts itself to a vrange when passed around.

The ultimate name will be value_range, but we need to remove legacy
first for that to happen.  Until then, tmp_range will do.

Sample usage is as follows.  Instead of:

	extern void foo (vrange &);

	int_range_max t;
	t.set_nonzero (type);
	foo (t);

one does:

	tmp_range t (type);
	t.set_nonzero (type);
	foo (t);

You can also delay initialization, for use in loops for example:

	tmp_range t;
	...
	t.init (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 tmp_range class will be augmented
to support them by adding the relevant bits in the initialization
code.

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 (tmp_range::lower_bound): New.
	(tmp_range::upper_bound): New.
	(tmp_range::dump): New.
	* value-range.h (class tmp_range): New.
	(irange::supports_type_p): Do not check if type is non-zero.
---
 gcc/gimple-range-fold.h  |   2 +-
 gcc/gimple-range-path.cc |   2 +-
 gcc/value-query.cc       |   3 +-
 gcc/value-range.cc       |  38 ++++++++++++
 gcc/value-range.h        | 130 ++++++++++++++++++++++++++++++++++++++-
 5 files changed, 169 insertions(+), 6 deletions(-)

diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h
index 53a5bf85dd4..20cb73dabb9 100644
--- a/gcc/gimple-range-fold.h
+++ b/gcc/gimple-range-fold.h
@@ -81,7 +81,7 @@ gimple_range_type (const gimple *s)
 	    type = TREE_TYPE (type);
 	}
     }
-  if (irange::supports_type_p (type))
+  if (type && irange::supports_type_p (type))
     return type;
   return NULL_TREE;
 }
diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc
index 459d3797da7..66f433dd1d5 100644
--- a/gcc/gimple-range-path.cc
+++ b/gcc/gimple-range-path.cc
@@ -755,7 +755,7 @@ path_range_query::range_of_stmt (irange &r, gimple *stmt, tree)
 {
   tree type = gimple_range_type (stmt);
 
-  if (!irange::supports_type_p (type))
+  if (!type || !irange::supports_type_p (type))
     return false;
 
   // If resolving unknowns, fold the statement making use of any
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 9ccd802457b..26e3858103b 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -249,7 +249,8 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
   if (UNARY_CLASS_P (expr))
     {
       range_operator *op = range_op_handler (TREE_CODE (expr), type);
-      if (op)
+      tree op0_type = TREE_TYPE (TREE_OPERAND (expr, 0));
+      if (op && irange::supports_type_p (op0_type))
 	{
 	  int_range_max r0;
 	  range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 97ff0614f48..c5f326ab479 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -30,6 +30,42 @@ along with GCC; see the file COPYING3.  If not see
 #include "fold-const.h"
 #include "gimple-range.h"
 
+// Convenience function only available for integers and pointers.
+
+wide_int
+tmp_range::lower_bound () const
+{
+  if (is_a <irange> (*m_vrange))
+    return as_a <irange> (*m_vrange).lower_bound ();
+  gcc_unreachable ();
+}
+
+// Convenience function only available for integers and pointers.
+
+wide_int
+tmp_range::upper_bound () const
+{
+  if (is_a <irange> (*m_vrange))
+    return as_a <irange> (*m_vrange).upper_bound ();
+  gcc_unreachable ();
+}
+
+void
+tmp_range::dump (FILE *out) const
+{
+  if (m_vrange)
+    m_vrange->dump (out);
+  else
+    fprintf (out, "NULL");
+}
+
+DEBUG_FUNCTION void
+debug (const tmp_range &r)
+{
+  r.dump (stderr);
+  fprintf (stderr, "\n");
+}
+
 // Default implementation when none has been defined.
 
 bool
@@ -186,6 +222,8 @@ unsupported_range::fits_p (const vrange &) const
   return false;
 }
 
+unsupported_range tmp_range::m_unsupported;
+
 // Here we copy between any two irange's.  The ranges can be legacy or
 // multi-ranges, and copying between any combination works correctly.
 
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 0061f667092..d51998145da 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -54,6 +54,7 @@ enum value_range_discriminator
 class vrange
 {
   template <typename T> friend bool is_a (vrange &);
+  friend class tmp_range;
 public:
   virtual void set (tree, tree, value_range_kind = VR_RANGE) = 0;
   virtual tree type () const = 0;
@@ -313,6 +314,131 @@ typedef int_range<1> value_range;
 // calculations.
 typedef int_range<255> int_range_max;
 
+// This is an "infinite" precision range object for use in temporary
+// calculations for any of the handled types.  The object can be
+// transparently used as a vrange.
+
+class tmp_range
+{
+public:
+  tmp_range ();
+  tmp_range (const vrange &r);
+  tmp_range (tree type);
+  bool init (tree type);
+  vrange& operator= (const vrange &);
+  bool operator== (const tmp_range &r) const;
+  bool operator!= (const tmp_range &r) const;
+  operator vrange &();
+  operator const vrange &() const;
+  void dump (FILE *out = stderr) const;
+
+  // Convenience methods for vrange compatability.
+  void set (tree min, tree max, value_range_kind kind = VR_RANGE)
+    { return m_vrange->set (min, max, kind); }
+  tree type () { return m_vrange->type (); }
+  enum value_range_kind kind () { return m_vrange->kind (); }
+  bool varying_p () const { return m_vrange->varying_p (); }
+  bool undefined_p () const { return m_vrange->undefined_p (); }
+  void set_varying (tree type) { m_vrange->set_varying (type); }
+  void set_undefined () { m_vrange->set_undefined (); }
+  bool union_ (const vrange &r) { return m_vrange->union_ (r); }
+  bool intersect (const vrange &r) { return m_vrange->intersect (r); }
+  bool singleton_p (tree *result = NULL) const
+    { return m_vrange->singleton_p (result); }
+  bool zero_p () const { return m_vrange->zero_p (); }
+  wide_int lower_bound () const; // For irange/prange compatability.
+  wide_int upper_bound () const; // For irange/prange compatability.
+private:
+  static unsupported_range m_unsupported;
+  vrange *m_vrange;
+  int_range_max m_irange;
+  DISABLE_COPY_AND_ASSIGN (tmp_range);
+};
+
+// This default constructor leaves the temporary uninitialized.  Use
+// init() to initialize.
+
+inline
+tmp_range::tmp_range ()
+{
+  m_vrange = nullptr;
+}
+
+// Copy constructor from a vrange.
+
+inline
+tmp_range::tmp_range (const vrange &r)
+{
+  *this = r;
+}
+
+// Copy constructor from a tree TYPE.
+//
+// Note that unlike the similarly named int_range<> constructor which
+// defaults to VARYING, this constructor defaults to UNDEFINED.
+// Defaulting to VARYING had an unfortunate performance penalty.  We
+// could remove the int_range<> (type) constructor if this is
+// confusing.
+
+inline
+tmp_range::tmp_range (tree type)
+{
+  init (type);
+}
+
+// Initialize object so it is possible to store temporaries of TYPE
+// into it.  The range of the temporary is undefined after this call,
+// and must be explicitly set (set_varying, set_undefined, etc).
+
+inline bool
+tmp_range::init (tree type)
+{
+  gcc_checking_assert (TYPE_P (type));
+
+  if (irange::supports_type_p (type))
+    m_vrange = &m_irange;
+  else
+    m_vrange = &m_unsupported;
+  return true;
+}
+
+inline vrange &
+tmp_range::operator= (const vrange &r)
+{
+  if (is_a <irange> (r))
+    {
+      m_irange = as_a <irange> (r);
+      m_vrange = &m_irange;
+      return *m_vrange;
+    }
+  else
+    gcc_unreachable ();
+}
+
+inline bool
+tmp_range::operator== (const tmp_range &r) const
+{
+  return *m_vrange == *r.m_vrange;
+}
+
+inline bool
+tmp_range::operator!= (const tmp_range &r) const
+{
+  return *m_vrange != *r.m_vrange;
+}
+
+inline
+tmp_range::operator vrange &()
+{
+  return *m_vrange;
+}
+
+inline
+tmp_range::operator const vrange &() const
+{
+  return *m_vrange;
+}
+
 // Returns true for an old-school value_range as described above.
 inline bool
 irange::legacy_mode_p () const
@@ -451,9 +577,7 @@ irange::nonzero_p () const
 inline bool
 irange::supports_type_p (tree type)
 {
-  if (type && (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)))
-    return type;
-  return false;
+  return INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type);
 }
 
 inline bool
-- 
2.36.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 3/5] Convert range-op.* to vrange.
  2022-05-30 13:27 [PATCH 1/5] Implement abstract vrange class Aldy Hernandez
  2022-05-30 13:27 ` [PATCH 2/5] Implement generic range temporaries Aldy Hernandez
@ 2022-05-30 13:27 ` Aldy Hernandez
  2022-06-01  9:01   ` Aldy Hernandez
  2022-05-30 13:27 ` [PATCH 4/5] Revamp irange_allocator to handle vranges Aldy Hernandez
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 14+ messages in thread
From: Aldy Hernandez @ 2022-05-30 13:27 UTC (permalink / raw)
  To: GCC patches

This patch provides the infrastructure to make range-ops type agnostic.

First, the range_op_handler function has been replaced with an object
of the same name.  It's coded in such a way to minimize changes to the
code base, and to encapsulate the dispatch code.

Instead of:

	range_operator *op = range_op_handler (code, type);
	if (op)
	  op->fold_range (...);

We now do:
	range_op_handler op (code, type);
	if (op)
	  op->fold_range (...);

I've folded gimple_range_handler into the range_op_handler class,
since it's also a query into the range operators.

Instead of:

	range_operator *handler = gimple_range_handler (stmt);

We now do:

	range_op_handler handler (stmt);

This all has the added benefit of moving all the dispatch code into an
independent class and avoid polluting range_operator (which we'll
further split later when frange and prange come live).

There's this annoying "using" keyword that's been added to each
operator due to hiding rules in C++.  The issue is that we will have
different virtual versions of fold_range() for each combination of
operands.  For example:

	// Traditional binary op on irange's.
	fold_range (irange &lhs, const irange &op1, const irange &op2);
	// For POINTER_DIFF_EXPR:
	fold_range (irange &lhs, const prange &op1, const prange &op2);
	// Cast from irange to prange.
	fold_range (prange &lhs, const irange &op1, const irange &op2);

Overloading virtuals when there are multiple same named methods causes
hidden virtuals warnings from -Woverloaded-virtual, thus the using
keyword.  An alternative would be to have different names:
fold_range_III, fold_range_IPP, fold_range_PII, but that's uglier
still.

Tested on x86-64 & ppc64le Linux.

gcc/ChangeLog:

	* gimple-range-edge.cc (gimple_outgoing_range_stmt_p): Adjust for
	vrange and convert range_op_handler function calls to use the
	identically named object.
	* gimple-range-fold.cc (gimple_range_operand1): Same.
	(gimple_range_operand2): Same.
	(fold_using_range::fold_stmt): Same.
	(fold_using_range::range_of_range_op): Same.
	(fold_using_range::range_of_builtin_ubsan_call): Same.
	(fold_using_range::relation_fold_and_or): Same.
	(fur_source::register_outgoing_edges): Same.
	* gimple-range-fold.h (gimple_range_handler): Remove.
	* gimple-range-gori.cc (gimple_range_calc_op1): Adjust for vrange.
	(gimple_range_calc_op2): Same.
	(range_def_chain::get_def_chain): Same.
	(gori_compute::compute_operand_range): Same.
	(gori_compute::condexpr_adjust): Same.
	* gimple-range.cc (gimple_ranger::prefill_name): Same.
	(gimple_ranger::prefill_stmt_dependencies): Same.
	* range-op.cc (get_bool_state): Same.
	(class operator_equal): Add using clause.
	(class operator_not_equal): Same.
	(class operator_lt): Same.
	(class operator_le): Same.
	(class operator_gt): Same.
	(class operator_ge): Same.
	(class operator_plus): Same.
	(class operator_minus): Same.
	(class operator_mult): Same.
	(class operator_exact_divide): Same.
	(class operator_lshift): Same.
	(class operator_rshift): Same.
	(class operator_cast): Same.
	(class operator_logical_and): Same.
	(class operator_bitwise_and): Same.
	(class operator_logical_or): Same.
	(class operator_bitwise_or): Same.
	(class operator_bitwise_xor): Same.
	(class operator_trunc_mod): Same.
	(class operator_logical_not): Same.
	(class operator_bitwise_not): Same.
	(class operator_cst): Same.
	(class operator_identity): Same.
	(class operator_unknown): Same.
	(class operator_abs): Same.
	(class operator_negate): Same.
	(class operator_addr_expr): Same.
	(class pointer_or_operator): Same.
	(operator_plus::op1_range): Adjust for vrange.
	(operator_minus::op1_range): Same.
	(operator_mult::op1_range): Same.
	(operator_cast::op1_range): Same.
	(operator_bitwise_not::fold_range): Same.
	(operator_negate::fold_range): Same.
	(range_op_handler): Rename to...
	(get_handler): ...this.
	(range_op_handler::range_op_handler): New.
	(range_op_handler::fold_range): New.
	(range_op_handler::op1_range): New.
	(range_op_handler::op2_range): New.
	(range_op_handler::lhs_op1_relation): New.
	(range_op_handler::lhs_op2_relation): New.
	(range_op_handler::op1_op2_relation): New.
	(range_cast): Adjust for vrange.
	* range-op.h (range_op_handler): Remove function.
	(range_cast): Adjust for vrange.
	(class range_op_handler): New.
	(get_bool_state): Adjust for vrange.
	(empty_range_varying): Same.
	(relop_early_resolve): Same.
	* tree-data-ref.cc (compute_distributive_range): Same.
	* tree-vrp.cc (get_range_op_handler): Remove.
	(range_fold_binary_symbolics_p): Use range_op_handler class
	instead of get_range_op_handler.
	(range_fold_unary_symbolics_p): Same.
	(range_fold_binary_expr): Same.
	(range_fold_unary_expr): Same.
	* value-query.cc (range_query::get_tree_range): Adjust for vrange.
---
 gcc/gimple-range-edge.cc |   2 +-
 gcc/gimple-range-fold.cc |  43 ++++----
 gcc/gimple-range-fold.h  |  15 ---
 gcc/gimple-range-gori.cc |  41 ++++----
 gcc/gimple-range.cc      |   6 +-
 gcc/range-op.cc          | 215 ++++++++++++++++++++++++++++++++++-----
 gcc/range-op.h           |  45 ++++++--
 gcc/tree-data-ref.cc     |   8 +-
 gcc/tree-vrp.cc          |  44 ++++----
 gcc/value-query.cc       |   8 +-
 10 files changed, 303 insertions(+), 124 deletions(-)

diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc
index 0bee38ba770..5bbe23ae03d 100644
--- a/gcc/gimple-range-edge.cc
+++ b/gcc/gimple-range-edge.cc
@@ -42,7 +42,7 @@ gimple_outgoing_range_stmt_p (basic_block bb)
   if (!gsi_end_p (gsi))
     {
       gimple *s = gsi_stmt (gsi);
-      if (is_a<gcond *> (s) && gimple_range_handler (s))
+      if (is_a<gcond *> (s) && range_op_handler (s))
 	return gsi_stmt (gsi);
       gswitch *sw = dyn_cast<gswitch *> (s);
       if (sw && irange::supports_type_p (TREE_TYPE (gimple_switch_index (sw))))
diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 0a947c16c58..c53d2863d5e 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -482,7 +482,7 @@ gimple_range_base_of_assignment (const gimple *stmt)
 tree
 gimple_range_operand1 (const gimple *stmt)
 {
-  gcc_checking_assert (gimple_range_handler (stmt));
+  gcc_checking_assert (range_op_handler (stmt));
 
   switch (gimple_code (stmt))
     {
@@ -515,7 +515,7 @@ gimple_range_operand1 (const gimple *stmt)
 tree
 gimple_range_operand2 (const gimple *stmt)
 {
-  gcc_checking_assert (gimple_range_handler (stmt));
+  gcc_checking_assert (range_op_handler (stmt));
 
   switch (gimple_code (stmt))
     {
@@ -551,7 +551,7 @@ fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name)
       && gimple_assign_rhs_code (s) == ADDR_EXPR)
     return range_of_address (r, s, src);
 
-  if (gimple_range_handler (s))
+  if (range_op_handler (s))
     res = range_of_range_op (r, s, src);
   else if (is_a<gphi *>(s))
     res = range_of_phi (r, as_a<gphi *> (s), src);
@@ -593,7 +593,7 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
   tree type = gimple_range_type (s);
   if (!type)
     return false;
-  range_operator *handler = gimple_range_handler (s);
+  range_op_handler handler (s);
   gcc_checking_assert (handler);
 
   tree lhs = gimple_get_lhs (s);
@@ -606,13 +606,13 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
 	{
 	  // Fold range, and register any dependency if available.
 	  int_range<2> r2 (type);
-	  handler->fold_range (r, type, range1, r2);
+	  handler.fold_range (r, type, range1, r2);
 	  if (lhs && gimple_range_ssa_p (op1))
 	    {
 	      if (src.gori ())
 		src.gori ()->register_dependency (lhs, op1);
 	      relation_kind rel;
-	      rel = handler->lhs_op1_relation (r, range1, range1);
+	      rel = handler.lhs_op1_relation (r, range1, range1);
 	      if (rel != VREL_VARYING)
 		src.register_relation (s, rel, lhs, op1);
 	    }
@@ -629,7 +629,7 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
 	      fputc ('\n', dump_file);
 	    }
 	  // Fold range, and register any dependency if available.
-	  handler->fold_range (r, type, range1, range2, rel);
+	  handler.fold_range (r, type, range1, range2, rel);
 	  relation_fold_and_or (r, s, src);
 	  if (lhs)
 	    {
@@ -640,13 +640,13 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
 		}
 	      if (gimple_range_ssa_p (op1))
 		{
-		  rel = handler->lhs_op1_relation (r, range1, range2, rel);
+		  rel = handler.lhs_op1_relation (r, range1, range2, rel);
 		  if (rel != VREL_VARYING)
 		    src.register_relation (s, rel, lhs, op1);
 		}
 	      if (gimple_range_ssa_p (op2))
 		{
-		  rel= handler->lhs_op2_relation (r, range1, range2, rel);
+		  rel= handler.lhs_op2_relation (r, range1, range2, rel);
 		  if (rel != VREL_VARYING)
 		    src.register_relation (s, rel, lhs, op2);
 		}
@@ -921,7 +921,7 @@ fold_using_range::range_of_builtin_ubsan_call (irange &r, gcall *call,
   gcc_checking_assert (code == PLUS_EXPR || code == MINUS_EXPR
 		       || code == MULT_EXPR);
   tree type = gimple_range_type (call);
-  range_operator *op = range_op_handler (code, type);
+  range_op_handler op (code, type);
   gcc_checking_assert (op);
   int_range_max ir0, ir1;
   tree arg0 = gimple_call_arg (call, 0);
@@ -935,7 +935,7 @@ fold_using_range::range_of_builtin_ubsan_call (irange &r, gcall *call,
   // Pretend the arithmetic is wrapping.  If there is any overflow,
   // we'll complain, but will actually do wrapping operation.
   flag_wrapv = 1;
-  op->fold_range (r, type, ir0, ir1, relation);
+  op.fold_range (r, type, ir0, ir1, relation);
   flag_wrapv = saved_flag_wrapv;
 
   // If for both arguments vrp_valueize returned non-NULL, this should
@@ -1391,8 +1391,8 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
   else if (ssa1_dep1 != ssa2_dep2 || ssa1_dep2 != ssa2_dep1)
     return;
 
-  range_operator *handler1 = gimple_range_handler (SSA_NAME_DEF_STMT (ssa1));
-  range_operator *handler2 = gimple_range_handler (SSA_NAME_DEF_STMT (ssa2));
+  range_op_handler handler1 (SSA_NAME_DEF_STMT (ssa1));
+  range_op_handler handler2 (SSA_NAME_DEF_STMT (ssa2));
 
   // If either handler is not present, no relation is found.
   if (!handler1 || !handler2)
@@ -1400,8 +1400,8 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
 
   int_range<2> bool_one (boolean_true_node, boolean_true_node);
 
-  relation_kind relation1 = handler1->op1_op2_relation (bool_one);
-  relation_kind relation2 = handler2->op1_op2_relation (bool_one);
+  relation_kind relation1 = handler1.op1_op2_relation (bool_one);
+  relation_kind relation2 = handler2.op1_op2_relation (bool_one);
   if (relation1 == VREL_VARYING || relation2 == VREL_VARYING)
     return;
 
@@ -1441,7 +1441,6 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
   int_range_max r;
   int_range<2> e0_range, e1_range;
   tree name;
-  range_operator *handler;
   basic_block bb = gimple_bb (s);
 
   if (e0)
@@ -1472,17 +1471,17 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
   tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (s));
   if (ssa1 && ssa2)
     {
-      handler = gimple_range_handler (s);
+      range_op_handler handler (s);
       gcc_checking_assert (handler);
       if (e0)
 	{
-	  relation_kind relation = handler->op1_op2_relation (e0_range);
+	  relation_kind relation = handler.op1_op2_relation (e0_range);
 	  if (relation != VREL_VARYING)
 	    register_relation (e0, relation, ssa1, ssa2);
 	}
       if (e1)
 	{
-	  relation_kind relation = handler->op1_op2_relation (e1_range);
+	  relation_kind relation = handler.op1_op2_relation (e1_range);
 	  if (relation != VREL_VARYING)
 	    register_relation (e1, relation, ssa1, ssa2);
 	}
@@ -1501,7 +1500,7 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
       if (TREE_CODE (TREE_TYPE (name)) != BOOLEAN_TYPE)
 	continue;
       gimple *stmt = SSA_NAME_DEF_STMT (name);
-      handler = gimple_range_handler (stmt);
+      range_op_handler handler (stmt);
       if (!handler)
 	continue;
       tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
@@ -1511,14 +1510,14 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
 	  if (e0 && gori ()->outgoing_edge_range_p (r, e0, name, *m_query)
 	      && r.singleton_p ())
 	    {
-	      relation_kind relation = handler->op1_op2_relation (r);
+	      relation_kind relation = handler.op1_op2_relation (r);
 	      if (relation != VREL_VARYING)
 		register_relation (e0, relation, ssa1, ssa2);
 	    }
 	  if (e1 && gori ()->outgoing_edge_range_p (r, e1, name, *m_query)
 	      && r.singleton_p ())
 	    {
-	      relation_kind relation = handler->op1_op2_relation (r);
+	      relation_kind relation = handler.op1_op2_relation (r);
 	      if (relation != VREL_VARYING)
 		register_relation (e1, relation, ssa1, ssa2);
 	    }
diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h
index 20cb73dabb9..4b5d4b6e0b8 100644
--- a/gcc/gimple-range-fold.h
+++ b/gcc/gimple-range-fold.h
@@ -41,21 +41,6 @@ bool fold_range (irange &r, gimple *s, irange &r1);
 bool fold_range (irange &r, gimple *s, irange &r1, irange &r2);
 bool fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector);
 
-// Return the range_operator pointer for this statement.  This routine
-// can also be used to gate whether a routine is range-ops enabled.
-
-static inline range_operator *
-gimple_range_handler (const gimple *s)
-{
-  if (const gassign *ass = dyn_cast<const gassign *> (s))
-    return range_op_handler (gimple_assign_rhs_code (ass),
-			     TREE_TYPE (gimple_assign_lhs (ass)));
-  if (const gcond *cond = dyn_cast<const gcond *> (s))
-    return range_op_handler (gimple_cond_code (cond),
-			     TREE_TYPE (gimple_cond_lhs (cond)));
-  return NULL;
-}
-
 // Return the type of range which statement S calculates.  If the type is
 // unsupported or no type can be determined, return NULL_TREE.
 
diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index 3e15eb5192d..0e0cf2128e7 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -44,9 +44,9 @@ gimple_range_calc_op1 (irange &r, const gimple *stmt, const irange &lhs_range)
   // Unary operations require the type of the first operand in the
   // second range position.
   tree type = TREE_TYPE (gimple_range_operand1 (stmt));
-  int_range<2> type_range (type);
-  return gimple_range_handler (stmt)->op1_range (r, type, lhs_range,
-						 type_range);
+  tmp_range type_range (type);
+  type_range.set_varying (type);
+  return range_op_handler (stmt).op1_range (r, type, lhs_range, type_range);
 }
 
 // Calculate what we can determine of the range of this statement's
@@ -72,12 +72,12 @@ gimple_range_calc_op1 (irange &r, const gimple *stmt,
       // This is sometimes invoked on single operand stmts.
       if (gimple_num_ops (stmt) < 3)
 	return false;
-      int_range<2> trange (TREE_TYPE (gimple_range_operand2 (stmt)));
-      return gimple_range_handler (stmt)->op1_range (r, type, lhs_range,
-						     trange);
+      tree op2_type = TREE_TYPE (gimple_range_operand2 (stmt));
+      tmp_range trange (op2_type);
+      trange.set_varying (op2_type);
+      return range_op_handler (stmt).op1_range (r, type, lhs_range, trange);
     }
-  return gimple_range_handler (stmt)->op1_range (r, type, lhs_range,
-						 op2_range);
+  return range_op_handler (stmt).op1_range (r, type, lhs_range, op2_range);
 }
 
 // Calculate what we can determine of the range of this statement's
@@ -97,12 +97,13 @@ gimple_range_calc_op2 (irange &r, const gimple *stmt,
   // If op1 is undefined, solve as if it is varying.
   if (op1_range.undefined_p ())
     {
-      int_range<2> trange (TREE_TYPE (gimple_range_operand1 (stmt)));
-      return gimple_range_handler (stmt)->op2_range (r, type, lhs_range,
-						     trange);
+      tree op1_type = TREE_TYPE (gimple_range_operand1 (stmt));
+      tmp_range trange (op1_type);
+      trange.set_varying (op1_type);
+      return range_op_handler (stmt).op2_range (r, type, lhs_range, trange);
     }
-  return gimple_range_handler (stmt)->op2_range (r, type, lhs_range,
-						 op1_range);
+  return range_op_handler (stmt).op2_range (r, type, lhs_range,
+					    op1_range);
 }
 
 // Return TRUE if GS is a logical && or || expression.
@@ -346,7 +347,7 @@ range_def_chain::get_def_chain (tree name)
     }
 
   gimple *stmt = SSA_NAME_DEF_STMT (name);
-  if (gimple_range_handler (stmt))
+  if (range_op_handler (stmt))
     {
       ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
       ssa2 = gimple_range_ssa_p (gimple_range_operand2 (stmt));
@@ -707,7 +708,7 @@ gori_compute::compute_operand_range (irange &r, gimple *stmt,
   if (is_a<gswitch *> (stmt))
     return compute_operand_range_switch (r, as_a<gswitch *> (stmt), lhs, name,
 					 src);
-  if (!gimple_range_handler (stmt))
+  if (!range_op_handler (stmt))
     return false;
 
   tree op1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
@@ -1328,7 +1329,7 @@ gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond,
   tree type = TREE_TYPE (gimple_assign_rhs1 (cond_def));
   if (!range_compatible_p (type, TREE_TYPE (gimple_assign_rhs2 (cond_def))))
     return false;
-  range_operator *hand = range_op_handler (gimple_assign_rhs_code (cond_def), type);
+  range_op_handler hand (gimple_assign_rhs_code (cond_def), type);
   if (!hand)
     return false;
 
@@ -1351,18 +1352,18 @@ gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond,
   // the op1 or op2 routines based on its location.
   if (c1)
     {
-      if (!hand->op1_range (cond_false, type, m_bool_zero, cr))
+      if (!hand.op1_range (cond_false, type, m_bool_zero, cr))
 	return false;
-      if (!hand->op1_range (cond_true, type, m_bool_one, cr))
+      if (!hand.op1_range (cond_true, type, m_bool_one, cr))
 	return false;
       cond_false.intersect (cl);
       cond_true.intersect (cl);
     }
   else
     {
-      if (!hand->op2_range (cond_false, type, m_bool_zero, cl))
+      if (!hand.op2_range (cond_false, type, m_bool_zero, cl))
 	return false;
-      if (!hand->op2_range (cond_true, type, m_bool_one, cl))
+      if (!hand.op2_range (cond_true, type, m_bool_one, cl))
 	return false;
       cond_false.intersect (cr);
       cond_true.intersect (cr);
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index f5e9e77bc71..32d57c9e3db 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -339,7 +339,7 @@ gimple_ranger::prefill_name (irange &r, tree name)
   if (!gimple_range_ssa_p (name))
     return;
   gimple *stmt = SSA_NAME_DEF_STMT (name);
-  if (!gimple_range_handler (stmt) && !is_a<gphi *> (stmt))
+  if (!range_op_handler (stmt) && !is_a<gphi *> (stmt))
     return;
 
   bool current;
@@ -363,7 +363,7 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
   gcc_checking_assert (stmt && gimple_bb (stmt));
 
   // Only pre-process range-ops and phis.
-  if (!gimple_range_handler (stmt) && !is_a<gphi *> (stmt))
+  if (!range_op_handler (stmt) && !is_a<gphi *> (stmt))
     return;
 
   // Mark where on the stack we are starting.
@@ -419,7 +419,7 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
 	}
       else
 	{
-	  gcc_checking_assert (gimple_range_handler (stmt));
+	  gcc_checking_assert (range_op_handler (stmt));
 	  tree op = gimple_range_operand2 (stmt);
 	  if (op)
 	    prefill_name (r, op);
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index c88da8caa6c..6f6d2da573a 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -420,7 +420,7 @@ create_possibly_reversed_range (irange &r, tree type,
 // return the equivalent range for TYPE in R; if FALSE/TRUE, do nothing.
 
 bool_range_state
-get_bool_state (irange &r, const irange &lhs, tree val_type)
+get_bool_state (vrange &r, const vrange &lhs, tree val_type)
 {
   // If there is no result, then this is unexecutable.
   if (lhs.undefined_p ())
@@ -446,6 +446,9 @@ get_bool_state (irange &r, const irange &lhs, tree val_type)
 
 class operator_equal : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -562,6 +565,9 @@ operator_equal::op2_range (irange &r, tree type,
 
 class operator_not_equal : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -738,6 +744,9 @@ build_ge (irange &r, tree type, const wide_int &val)
 
 class operator_lt :  public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -846,6 +855,9 @@ operator_lt::op2_range (irange &r, tree type,
 
 class operator_le :  public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -954,6 +966,9 @@ operator_le::op2_range (irange &r, tree type,
 
 class operator_gt :  public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -1061,6 +1076,9 @@ operator_gt::op2_range (irange &r, tree type,
 
 class operator_ge :  public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -1169,6 +1187,10 @@ operator_ge::op2_range (irange &r, tree type,
 
 class operator_plus : public range_operator
 {
+  using range_operator::op1_range;
+  using range_operator::op2_range;
+  using range_operator::lhs_op1_relation;
+  using range_operator::lhs_op2_relation;
 public:
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
@@ -1286,7 +1308,7 @@ operator_plus::op1_range (irange &r, tree type,
 			  const irange &op2,
 			  relation_kind rel ATTRIBUTE_UNUSED) const
 {
-  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op2);
+  return range_op_handler (MINUS_EXPR, type).fold_range (r, type, lhs, op2);
 }
 
 bool
@@ -1295,12 +1317,15 @@ operator_plus::op2_range (irange &r, tree type,
 			  const irange &op1,
 			  relation_kind rel ATTRIBUTE_UNUSED) const
 {
-  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op1);
+  return range_op_handler (MINUS_EXPR, type).fold_range (r, type, lhs, op1);
 }
 
 
 class operator_minus : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
@@ -1445,7 +1470,7 @@ operator_minus::op1_range (irange &r, tree type,
 			   const irange &op2,
 			   relation_kind rel ATTRIBUTE_UNUSED) const
 {
-  return range_op_handler (PLUS_EXPR, type)->fold_range (r, type, lhs, op2);
+  return range_op_handler (PLUS_EXPR, type).fold_range (r, type, lhs, op2);
 }
 
 bool
@@ -1597,6 +1622,8 @@ cross_product_operator::wi_cross_product (irange &r, tree type,
 
 class operator_mult : public cross_product_operator
 {
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual void wi_fold (irange &r, tree type,
 		        const wide_int &lh_lb,
@@ -1629,8 +1656,8 @@ operator_mult::op1_range (irange &r, tree type,
     return false;
 
   if (op2.singleton_p (&offset) && !integer_zerop (offset))
-    return range_op_handler (TRUNC_DIV_EXPR, type)->fold_range (r, type,
-								lhs, op2);
+    return range_op_handler (TRUNC_DIV_EXPR, type).fold_range (r, type,
+							       lhs, op2);
   return false;
 }
 
@@ -1857,6 +1884,7 @@ operator_div op_ceil_div (CEIL_DIV_EXPR);
 
 class operator_exact_divide : public operator_div
 {
+  using range_operator::op1_range;
 public:
   operator_exact_divide () : operator_div (TRUNC_DIV_EXPR) { }
   virtual bool op1_range (irange &r, tree type,
@@ -1881,13 +1909,15 @@ operator_exact_divide::op1_range (irange &r, tree type,
   // If op2 is a multiple of 2, we would be able to set some non-zero bits.
   if (op2.singleton_p (&offset)
       && !integer_zerop (offset))
-    return range_op_handler (MULT_EXPR, type)->fold_range (r, type, lhs, op2);
+    return range_op_handler (MULT_EXPR, type).fold_range (r, type, lhs, op2);
   return false;
 }
 
 
 class operator_lshift : public cross_product_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
 public:
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
@@ -1909,6 +1939,9 @@ public:
 
 class operator_rshift : public cross_product_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::lhs_op1_relation;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -2248,6 +2281,8 @@ operator_rshift::wi_fold (irange &r, tree type,
 
 class operator_cast: public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -2417,10 +2452,9 @@ operator_cast::op1_range (irange &r, tree type,
 	  // Add this to the unsigned LHS range(s).
 	  int_range_max lim_range (type, lim, lim);
 	  int_range_max lhs_neg;
-	  range_op_handler (PLUS_EXPR, type)->fold_range (lhs_neg,
-							  type,
-							  converted_lhs,
-							  lim_range);
+	  range_op_handler (PLUS_EXPR, type).fold_range (lhs_neg, type,
+							 converted_lhs,
+							 lim_range);
 	  // lhs_neg now has all the negative versions of the LHS.
 	  // Now union in all the values from SIGNED MIN (0x80000) to
 	  // lim-1 in order to fill in all the ranges with the upper
@@ -2469,6 +2503,9 @@ operator_cast::op1_range (irange &r, tree type,
 
 class operator_logical_and : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &lh,
@@ -2542,6 +2579,9 @@ operator_logical_and::op2_range (irange &r, tree type,
 
 class operator_bitwise_and : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &lh,
@@ -2988,6 +3028,9 @@ operator_bitwise_and::op2_range (irange &r, tree type,
 
 class operator_logical_or : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &lh,
@@ -3051,6 +3094,8 @@ operator_logical_or::op2_range (irange &r, tree type,
 
 class operator_bitwise_or : public range_operator
 {
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
@@ -3155,6 +3200,8 @@ operator_bitwise_or::op2_range (irange &r, tree type,
 
 class operator_bitwise_xor : public range_operator
 {
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual void wi_fold (irange &r, tree type,
 		        const wide_int &lh_lb,
@@ -3296,6 +3343,8 @@ operator_bitwise_xor::op2_range (irange &r, tree type,
 
 class operator_trunc_mod : public range_operator
 {
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual void wi_fold (irange &r, tree type,
 		        const wide_int &lh_lb,
@@ -3432,6 +3481,8 @@ operator_trunc_mod::op2_range (irange &r, tree type,
 
 class operator_logical_not : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &lh,
@@ -3487,6 +3538,8 @@ operator_logical_not::op1_range (irange &r,
 
 class operator_bitwise_not : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &lh,
@@ -3513,8 +3566,7 @@ operator_bitwise_not::fold_range (irange &r, tree type,
   // ~X is simply -1 - X.
   int_range<1> minusone (type, wi::minus_one (TYPE_PRECISION (type)),
 			 wi::minus_one (TYPE_PRECISION (type)));
-  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, minusone,
-							  lh);
+  return range_op_handler (MINUS_EXPR, type).fold_range (r, type, minusone, lh);
 }
 
 bool
@@ -3533,6 +3585,7 @@ operator_bitwise_not::op1_range (irange &r, tree type,
 
 class operator_cst : public range_operator
 {
+  using range_operator::fold_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -3553,6 +3606,9 @@ operator_cst::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
 
 class operator_identity : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::lhs_op1_relation;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -3605,6 +3661,7 @@ operator_identity::op1_range (irange &r, tree type ATTRIBUTE_UNUSED,
 
 class operator_unknown : public range_operator
 {
+  using range_operator::fold_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -3625,6 +3682,7 @@ operator_unknown::fold_range (irange &r, tree type,
 
 class operator_abs : public range_operator
 {
+  using range_operator::op1_range;
  public:
   virtual void wi_fold (irange &r, tree type,
 		        const wide_int &lh_lb,
@@ -3790,6 +3848,8 @@ operator_absu::wi_fold (irange &r, tree type,
 
 class operator_negate : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
  public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -3810,9 +3870,8 @@ operator_negate::fold_range (irange &r, tree type,
   if (empty_range_varying (r, type, lh, rh))
     return true;
   // -X is simply 0 - X.
-  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type,
-							  range_zero (type),
-							  lh);
+  return range_op_handler (MINUS_EXPR, type).fold_range (r, type,
+							 range_zero (type), lh);
 }
 
 bool
@@ -3828,6 +3887,8 @@ operator_negate::op1_range (irange &r, tree type,
 
 class operator_addr_expr : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -3978,6 +4039,8 @@ pointer_and_operator::wi_fold (irange &r, tree type,
 
 class pointer_or_operator : public range_operator
 {
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
@@ -4139,8 +4202,8 @@ pointer_table::pointer_table ()
 
 // The tables are hidden and accessed via a simple extern function.
 
-range_operator *
-range_op_handler (enum tree_code code, tree type)
+static inline range_operator *
+get_handler (enum tree_code code, tree type)
 {
   // First check if there is a pointer specialization.
   if (POINTER_TYPE_P (type))
@@ -4150,16 +4213,120 @@ range_op_handler (enum tree_code code, tree type)
   return NULL;
 }
 
+range_op_handler::range_op_handler (tree_code code, tree type)
+{
+  m_op = get_handler (code, type);
+}
+
+range_op_handler::range_op_handler (const gimple *s)
+{
+  if (const gassign *ass = dyn_cast<const gassign *> (s))
+    {
+      enum tree_code code = gimple_assign_rhs_code (ass);
+      // The LHS of a comparison is always an int, so we must look at
+      // the operands.
+      if (TREE_CODE_CLASS (code) == tcc_comparison)
+	m_op = get_handler (code, TREE_TYPE (gimple_assign_rhs1 (ass)));
+      else
+	m_op = get_handler (code, TREE_TYPE (gimple_assign_lhs (ass)));
+    }
+  else if (const gcond *cond = dyn_cast<const gcond *> (s))
+    m_op = get_handler (gimple_cond_code (cond),
+			TREE_TYPE (gimple_cond_lhs (cond)));
+  else
+    m_op = NULL;
+}
+
+bool
+range_op_handler::fold_range (vrange &r, tree type,
+			      const vrange &lh,
+			      const vrange &rh,
+			      relation_kind rel) const
+{
+  if (is_a <irange> (lh))
+    return m_op->fold_range (as_a <irange> (r), type,
+			     as_a <irange> (lh),
+			     as_a <irange> (rh), rel);
+  gcc_unreachable ();
+  return false;
+}
+
+bool
+range_op_handler::op1_range (vrange &r, tree type,
+			     const vrange &lhs,
+			     const vrange &op2,
+			     relation_kind rel) const
+{
+  if (is_a <irange> (r))
+    return m_op->op1_range (as_a <irange> (r), type,
+			    as_a <irange> (lhs),
+			    as_a <irange> (op2), rel);
+  gcc_unreachable ();
+  return false;
+}
+
+bool
+range_op_handler::op2_range (vrange &r, tree type,
+			     const vrange &lhs,
+			     const vrange &op1,
+			     relation_kind rel) const
+{
+  if (is_a <irange> (r))
+    return m_op->op2_range (as_a <irange> (r), type,
+			    as_a <irange> (lhs),
+			    as_a <irange> (op1), rel);
+  gcc_unreachable ();
+  return false;
+}
+
+relation_kind
+range_op_handler::lhs_op1_relation (const vrange &lhs,
+				    const vrange &op1,
+				    const vrange &op2,
+				    relation_kind rel) const
+{
+  if (is_a <irange> (op1))
+    return m_op->lhs_op1_relation (as_a <irange> (lhs),
+				   as_a <irange> (op1), as_a <irange> (op2), rel);
+  gcc_unreachable ();
+  return VREL_VARYING;
+}
+
+relation_kind
+range_op_handler::lhs_op2_relation (const vrange &lhs,
+				    const vrange &op1,
+				    const vrange &op2,
+				    relation_kind rel) const
+{
+  if (is_a <irange> (op1))
+    return m_op->lhs_op2_relation (as_a <irange> (lhs),
+				   as_a <irange> (op1), as_a <irange> (op2), rel);
+  gcc_unreachable ();
+  return VREL_VARYING;
+}
+
+relation_kind
+range_op_handler::op1_op2_relation (const vrange &lhs) const
+{
+  return m_op->op1_op2_relation (as_a <irange> (lhs));
+}
+
 // Cast the range in R to TYPE.
 
-void
-range_cast (irange &r, tree type)
+bool
+range_cast (vrange &r, tree type)
 {
-  int_range_max tmp = r;
-  range_operator *op = range_op_handler (CONVERT_EXPR, type);
+  tmp_range tmp (r);
+  tmp_range varying (type);
+  varying.set_varying (type);
+  range_op_handler op (CONVERT_EXPR, type);
   // Call op_convert, if it fails, the result is varying.
-  if (!op->fold_range (r, type, tmp, int_range<1> (type)))
-    r.set_varying (type);
+  if (!op || !op.fold_range (r, type, tmp, varying))
+    {
+      r.set_varying (type);
+      return false;
+    }
+  return true;
 }
 
 #if CHECKING_P
diff --git a/gcc/range-op.h b/gcc/range-op.h
index 5fdda326d4b..d0f50689897 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -108,8 +108,39 @@ protected:
 			 const wide_int &rh_ub) const;
 };
 
-extern range_operator *range_op_handler (enum tree_code code, tree type);
-extern void range_cast (irange &, tree type);
+class range_op_handler
+{
+public:
+  range_op_handler (enum tree_code code, tree type);
+  range_op_handler (const gimple *s);
+  operator bool () const { return m_op; }
+
+  bool fold_range (vrange &r, tree type,
+		   const vrange &lh,
+		   const vrange &rh,
+		   relation_kind rel = VREL_VARYING) const;
+  bool op1_range (vrange &r, tree type,
+		  const vrange &lhs,
+		  const vrange &op2,
+		  relation_kind rel = VREL_VARYING) const;
+  bool op2_range (vrange &r, tree type,
+		  const vrange &lhs,
+		  const vrange &op1,
+		  relation_kind rel = VREL_VARYING) const;
+  relation_kind lhs_op1_relation (const vrange &lhs,
+				  const vrange &op1,
+				  const vrange &op2,
+				  relation_kind = VREL_VARYING) const;
+  relation_kind lhs_op2_relation (const vrange &lhs,
+				  const vrange &op1,
+				  const vrange &op2,
+				  relation_kind = VREL_VARYING) const;
+  relation_kind op1_op2_relation (const vrange &lhs) const;
+private:
+  range_operator *m_op;
+};
+
+extern bool range_cast (vrange &, tree type);
 extern void wi_set_zero_nonzero_bits (tree type,
 				      const wide_int &, const wide_int &,
 				      wide_int &maybe_nonzero,
@@ -124,7 +155,7 @@ relation_kind gt_op1_op2_relation (const irange &lhs);
 relation_kind ge_op1_op2_relation (const irange &lhs);
 
 enum bool_range_state { BRS_FALSE, BRS_TRUE, BRS_EMPTY, BRS_FULL };
-bool_range_state get_bool_state (irange &r, const irange &lhs, tree val_type);
+bool_range_state get_bool_state (vrange &r, const vrange &lhs, tree val_type);
 
 // If the range of either op1 or op2 is undefined, set the result to
 // varying and return TRUE.  If the caller truely cares about a result,
@@ -132,8 +163,8 @@ bool_range_state get_bool_state (irange &r, const irange &lhs, tree val_type);
 // treated as a varying.
 
 inline bool
-empty_range_varying (irange &r, tree type,
-		     const irange &op1, const irange & op2)
+empty_range_varying (vrange &r, tree type,
+		     const vrange &op1, const vrange & op2)
 {
   if (op1.undefined_p () || op2.undefined_p ())
     {
@@ -150,8 +181,8 @@ empty_range_varying (irange &r, tree type,
 // return false.
 
 inline bool
-relop_early_resolve (irange &r, tree type, const irange &op1,
-		     const irange &op2, relation_kind rel,
+relop_early_resolve (irange &r, tree type, const vrange &op1,
+		     const vrange &op2, relation_kind rel,
 		     relation_kind my_rel)
 {
   // If known relation is a complete subset of this relation, always true.
diff --git a/gcc/tree-data-ref.cc b/gcc/tree-data-ref.cc
index 397792c3584..ae05fe74b95 100644
--- a/gcc/tree-data-ref.cc
+++ b/gcc/tree-data-ref.cc
@@ -593,8 +593,8 @@ compute_distributive_range (tree type, value_range &op0_range,
   gcc_assert (INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_TRAPS (type));
   if (result_range)
     {
-      range_operator *op = range_op_handler (code, type);
-      op->fold_range (*result_range, type, op0_range, op1_range);
+      range_op_handler op (code, type);
+      op.fold_range (*result_range, type, op0_range, op1_range);
     }
 
   /* The distributive property guarantees that if TYPE is no narrower
@@ -639,10 +639,10 @@ compute_distributive_range (tree type, value_range &op0_range,
   range_cast (op0_range, ssizetype);
   range_cast (op1_range, ssizetype);
   value_range wide_range;
-  range_operator *op = range_op_handler (code, ssizetype);
+  range_op_handler op (code, ssizetype);
   bool saved_flag_wrapv = flag_wrapv;
   flag_wrapv = 1;
-  op->fold_range (wide_range, ssizetype, op0_range, op1_range);
+  op.fold_range (wide_range, ssizetype, op0_range, op1_range);
   flag_wrapv = saved_flag_wrapv;
   if (wide_range.num_pairs () != 1 || !range_int_cst_p (&wide_range))
     return false;
diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
index 0784d658567..3c7b5af4737 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -924,20 +924,6 @@ extract_range_from_plus_minus_expr (value_range *vr,
     vr->set (min, max, kind);
 }
 
-/* Return the range-ops handler for CODE and EXPR_TYPE.  If no
-   suitable operator is found, return NULL and set VR to VARYING.  */
-
-static const range_operator *
-get_range_op_handler (value_range *vr,
-		      enum tree_code code,
-		      tree expr_type)
-{
-  const range_operator *op = range_op_handler (code, expr_type);
-  if (!op)
-    vr->set_varying (expr_type);
-  return op;
-}
-
 /* If the types passed are supported, return TRUE, otherwise set VR to
    VARYING and return FALSE.  */
 
@@ -1005,10 +991,12 @@ range_fold_binary_symbolics_p (value_range *vr,
 						&vr0, &vr1);
 	  return true;
 	}
-      const range_operator *op = get_range_op_handler (vr, code, expr_type);
+      range_op_handler op (code, expr_type);
+      if (!op)
+	vr->set_varying (expr_type);
       vr0.normalize_symbolics ();
       vr1.normalize_symbolics ();
-      return op->fold_range (*vr, expr_type, vr0, vr1);
+      return op.fold_range (*vr, expr_type, vr0, vr1);
     }
   return false;
 }
@@ -1040,10 +1028,12 @@ range_fold_unary_symbolics_p (value_range *vr,
 	  range_fold_binary_expr (vr, MINUS_EXPR, expr_type, &minusone, vr0);
 	  return true;
 	}
-      const range_operator *op = get_range_op_handler (vr, code, expr_type);
+      range_op_handler op (code, expr_type);
+      if (!op)
+	vr->set_varying (expr_type);
       value_range vr0_cst (*vr0);
       vr0_cst.normalize_symbolics ();
-      return op->fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
+      return op.fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
     }
   return false;
 }
@@ -1060,9 +1050,12 @@ range_fold_binary_expr (value_range *vr,
   if (!supported_types_p (vr, expr_type)
       || !defined_ranges_p (vr, vr0_, vr1_))
     return;
-  const range_operator *op = get_range_op_handler (vr, code, expr_type);
+  range_op_handler op (code, expr_type);
   if (!op)
-    return;
+    {
+      vr->set_varying (expr_type);
+      return;
+    }
 
   if (range_fold_binary_symbolics_p (vr, code, expr_type, vr0_, vr1_))
     return;
@@ -1075,7 +1068,7 @@ range_fold_binary_expr (value_range *vr,
     vr1.set_varying (expr_type);
   vr0.normalize_addresses ();
   vr1.normalize_addresses ();
-  op->fold_range (*vr, expr_type, vr0, vr1);
+  op.fold_range (*vr, expr_type, vr0, vr1);
 }
 
 /* Perform a unary operation on a range.  */
@@ -1089,16 +1082,19 @@ range_fold_unary_expr (value_range *vr,
   if (!supported_types_p (vr, expr_type, vr0_type)
       || !defined_ranges_p (vr, vr0))
     return;
-  const range_operator *op = get_range_op_handler (vr, code, expr_type);
+  range_op_handler op (code, expr_type);
   if (!op)
-    return;
+    {
+      vr->set_varying (expr_type);
+      return;
+    }
 
   if (range_fold_unary_symbolics_p (vr, code, expr_type, vr0))
     return;
 
   value_range vr0_cst (*vr0);
   vr0_cst.normalize_addresses ();
-  op->fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
+  op.fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
 }
 
 /* If the range of values taken by OP can be inferred after STMT executes,
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 26e3858103b..31e56eeae53 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -234,13 +234,13 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
     }
   if (BINARY_CLASS_P (expr))
     {
-      range_operator *op = range_op_handler (TREE_CODE (expr), type);
+      range_op_handler op (TREE_CODE (expr), type);
       if (op)
 	{
 	  int_range_max r0, r1;
 	  range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
 	  range_of_expr (r1, TREE_OPERAND (expr, 1), stmt);
-	  op->fold_range (r, type, r0, r1);
+	  op.fold_range (r, type, r0, r1);
 	}
       else
 	r.set_varying (type);
@@ -248,13 +248,13 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
     }
   if (UNARY_CLASS_P (expr))
     {
-      range_operator *op = range_op_handler (TREE_CODE (expr), type);
+      range_op_handler op (TREE_CODE (expr), type);
       tree op0_type = TREE_TYPE (TREE_OPERAND (expr, 0));
       if (op && irange::supports_type_p (op0_type))
 	{
 	  int_range_max r0;
 	  range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
-	  op->fold_range (r, type, r0, int_range<1> (type));
+	  op.fold_range (r, type, r0, int_range<1> (type));
 	}
       else
 	r.set_varying (type);
-- 
2.36.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 4/5] Revamp irange_allocator to handle vranges.
  2022-05-30 13:27 [PATCH 1/5] Implement abstract vrange class Aldy Hernandez
  2022-05-30 13:27 ` [PATCH 2/5] Implement generic range temporaries Aldy Hernandez
  2022-05-30 13:27 ` [PATCH 3/5] Convert range-op.* to vrange Aldy Hernandez
@ 2022-05-30 13:27 ` Aldy Hernandez
  2022-06-01  9:02   ` Aldy Hernandez
  2022-05-30 13:27 ` [PATCH 5/5] Convert ranger and clients to vrange Aldy Hernandez
  2022-06-01  8:57 ` [PATCH 1/5] Implement abstract vrange class Aldy Hernandez
  4 siblings, 1 reply; 14+ messages in thread
From: Aldy Hernandez @ 2022-05-30 13:27 UTC (permalink / raw)
  To: GCC patches

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 <typename T> 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 <irange> (some_irange);
      frange *f = allocator.clone <frange> (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-side-effect.cc (side_effect_manager::get_nonzero):
	Same.
	(side_effect_manager::add_range): Same.
	* gimple-range-side-effect.h (class side_effect_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/gimple-range-cache.cc       | 55 +++++++++++-----------
 gcc/gimple-range-cache.h        |  4 +-
 gcc/gimple-range-edge.cc        |  4 +-
 gcc/gimple-range-edge.h         |  2 +-
 gcc/gimple-range-side-effect.cc | 13 ++++--
 gcc/gimple-range-side-effect.h  |  2 +-
 gcc/value-range.h               | 82 +++++++++++++++++++++------------
 7 files changed, 96 insertions(+), 66 deletions(-)

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index c726393b380..9c541993fb6 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -75,7 +75,7 @@ ssa_block_ranges::dump (FILE *f)
 class sbr_vector : public ssa_block_ranges
 {
 public:
-  sbr_vector (tree t, irange_allocator *allocator);
+  sbr_vector (tree t, vrange_allocator *allocator);
 
   virtual bool set_bb_range (const_basic_block bb, const irange &r) override;
   virtual bool get_bb_range (irange &r, const_basic_block bb) override;
@@ -86,20 +86,21 @@ protected:
   int_range<2> m_varying;
   int_range<2> m_undefined;
   tree m_type;
-  irange_allocator *m_irange_allocator;
+  vrange_allocator *m_range_allocator;
   void grow ();
 };
 
 
 // Initialize a block cache for an ssa_name of type T.
 
-sbr_vector::sbr_vector (tree t, irange_allocator *allocator)
+sbr_vector::sbr_vector (tree t, vrange_allocator *allocator)
 {
   gcc_checking_assert (TYPE_P (t));
   m_type = t;
-  m_irange_allocator = allocator;
+  m_range_allocator = allocator;
   m_tab_size = last_basic_block_for_fn (cfun) + 1;
-  m_tab = (irange **)allocator->get_memory (m_tab_size * sizeof (irange *));
+  m_tab = static_cast <irange **>
+    (allocator->alloc (m_tab_size * sizeof (irange *)));
   memset (m_tab, 0, m_tab_size * sizeof (irange *));
 
   // Create the cached type range.
@@ -121,8 +122,8 @@ sbr_vector::grow ()
   int new_size = inc + curr_bb_size;
 
   // Allocate new memory, copy the old vector and clear the new space.
-  irange **t = (irange **)m_irange_allocator->get_memory (new_size
-							  * sizeof (irange *));
+  irange **t = static_cast <irange **>
+    (m_range_allocator->alloc (new_size * sizeof (irange *)));
   memcpy (t, m_tab, m_tab_size * sizeof (irange *));
   memset (t + m_tab_size, 0, (new_size - m_tab_size) * sizeof (irange *));
 
@@ -143,7 +144,7 @@ sbr_vector::set_bb_range (const_basic_block bb, const irange &r)
   else if (r.undefined_p ())
     m = &m_undefined;
   else
-    m = m_irange_allocator->allocate (r);
+    m = m_range_allocator->clone (r);
   m_tab[bb->index] = m;
   return true;
 }
@@ -191,14 +192,14 @@ sbr_vector::bb_range_p (const_basic_block bb)
 class sbr_sparse_bitmap : public ssa_block_ranges
 {
 public:
-  sbr_sparse_bitmap (tree t, irange_allocator *allocator, bitmap_obstack *bm);
+  sbr_sparse_bitmap (tree t, vrange_allocator *allocator, bitmap_obstack *bm);
   virtual bool set_bb_range (const_basic_block bb, const irange &r) override;
   virtual bool get_bb_range (irange &r, const_basic_block bb) override;
   virtual bool bb_range_p (const_basic_block bb) override;
 private:
   void bitmap_set_quad (bitmap head, int quad, int quad_value);
   int bitmap_get_quad (const_bitmap head, int quad);
-  irange_allocator *m_irange_allocator;
+  vrange_allocator *m_range_allocator;
   irange *m_range[SBR_NUM];
   bitmap_head bitvec;
   tree m_type;
@@ -206,23 +207,25 @@ private:
 
 // Initialize a block cache for an ssa_name of type T.
 
-sbr_sparse_bitmap::sbr_sparse_bitmap (tree t, irange_allocator *allocator,
-				bitmap_obstack *bm)
+sbr_sparse_bitmap::sbr_sparse_bitmap (tree t, vrange_allocator *allocator,
+				      bitmap_obstack *bm)
 {
   gcc_checking_assert (TYPE_P (t));
   m_type = t;
   bitmap_initialize (&bitvec, bm);
   bitmap_tree_view (&bitvec);
-  m_irange_allocator = allocator;
+  m_range_allocator = allocator;
   // Pre-cache varying.
-  m_range[0] = m_irange_allocator->allocate (2);
+  m_range[0] = static_cast <irange *> (m_range_allocator->alloc_vrange (t));
   m_range[0]->set_varying (t);
   // Pre-cache zero and non-zero values for pointers.
   if (POINTER_TYPE_P (t))
     {
-      m_range[1] = m_irange_allocator->allocate (2);
+      m_range[1]
+	= static_cast <irange *> (m_range_allocator->alloc_vrange (t));
       m_range[1]->set_nonzero (t);
-      m_range[2] = m_irange_allocator->allocate (2);
+      m_range[2]
+	= static_cast <irange *> (m_range_allocator->alloc_vrange (t));
       m_range[2]->set_zero (t);
     }
   else
@@ -267,7 +270,7 @@ sbr_sparse_bitmap::set_bb_range (const_basic_block bb, const irange &r)
     if (!m_range[x] || r == *(m_range[x]))
       {
 	if (!m_range[x])
-	  m_range[x] = m_irange_allocator->allocate (r);
+	  m_range[x] = m_range_allocator->clone (r);
 	bitmap_set_quad (&bitvec, bb->index, x + 1);
 	return true;
       }
@@ -312,14 +315,14 @@ block_range_cache::block_range_cache ()
   bitmap_obstack_initialize (&m_bitmaps);
   m_ssa_ranges.create (0);
   m_ssa_ranges.safe_grow_cleared (num_ssa_names);
-  m_irange_allocator = new irange_allocator;
+  m_range_allocator = new vrange_allocator;
 }
 
 // Remove any m_block_caches which have been created.
 
 block_range_cache::~block_range_cache ()
 {
-  delete m_irange_allocator;
+  delete m_range_allocator;
   // Release the vector itself.
   m_ssa_ranges.release ();
   bitmap_obstack_release (&m_bitmaps);
@@ -341,17 +344,17 @@ block_range_cache::set_bb_range (tree name, const_basic_block bb,
       // Use sparse representation if there are too many basic blocks.
       if (last_basic_block_for_fn (cfun) > param_evrp_sparse_threshold)
 	{
-	  void *r = m_irange_allocator->get_memory (sizeof (sbr_sparse_bitmap));
+	  void *r = m_range_allocator->alloc (sizeof (sbr_sparse_bitmap));
 	  m_ssa_ranges[v] = new (r) sbr_sparse_bitmap (TREE_TYPE (name),
-						       m_irange_allocator,
+						       m_range_allocator,
 						       &m_bitmaps);
 	}
       else
 	{
 	  // Otherwise use the default vector implemntation.
-	  void *r = m_irange_allocator->get_memory (sizeof (sbr_vector));
+	  void *r = m_range_allocator->alloc (sizeof (sbr_vector));
 	  m_ssa_ranges[v] = new (r) sbr_vector (TREE_TYPE (name),
-						m_irange_allocator);
+						m_range_allocator);
 	}
     }
   return m_ssa_ranges[v]->set_bb_range (bb, r);
@@ -467,7 +470,7 @@ block_range_cache::dump (FILE *f, basic_block bb, bool print_varying)
 ssa_global_cache::ssa_global_cache ()
 {
   m_tab.create (0);
-  m_irange_allocator = new irange_allocator;
+  m_range_allocator = new vrange_allocator;
 }
 
 // Deconstruct a global cache.
@@ -475,7 +478,7 @@ ssa_global_cache::ssa_global_cache ()
 ssa_global_cache::~ssa_global_cache ()
 {
   m_tab.release ();
-  delete m_irange_allocator;
+  delete m_range_allocator;
 }
 
 // Retrieve the global range of NAME from cache memory if it exists. 
@@ -509,7 +512,7 @@ ssa_global_cache::set_global_range (tree name, const irange &r)
   if (m && m->fits_p (r))
     *m = r;
   else
-    m_tab[v] = m_irange_allocator->allocate (r);
+    m_tab[v] = m_range_allocator->clone (r);
   return m != NULL;
 }
 
diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h
index 555fe32513f..2472cd04f47 100644
--- a/gcc/gimple-range-cache.h
+++ b/gcc/gimple-range-cache.h
@@ -44,7 +44,7 @@ private:
   vec<class ssa_block_ranges *> m_ssa_ranges;
   ssa_block_ranges &get_block_ranges (tree name);
   ssa_block_ranges *query_block_ranges (tree name);
-  irange_allocator *m_irange_allocator;
+  vrange_allocator *m_range_allocator;
   bitmap_obstack m_bitmaps;
 };
 
@@ -64,7 +64,7 @@ public:
   void dump (FILE *f = stderr);
 private:
   vec<irange *> m_tab;
-  class irange_allocator *m_irange_allocator;
+  vrange_allocator *m_range_allocator;
 };
 
 // This class provides all the caches a global ranger may need, and makes 
diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc
index 5bbe23ae03d..5264e627c9a 100644
--- a/gcc/gimple-range-edge.cc
+++ b/gcc/gimple-range-edge.cc
@@ -166,13 +166,13 @@ gimple_outgoing_range::calc_switch_ranges (gswitch *sw)
       // If there was an existing range and it doesn't fit, we lose the memory.
       // It'll get reclaimed when the obstack is freed.  This seems less
       // intrusive than allocating max ranges for each case.
-      slot = m_range_allocator.allocate (case_range);
+      slot = m_range_allocator.clone <irange> (case_range);
     }
 
   irange *&slot = m_edge_table->get_or_insert (default_edge, &existed);
   // This should be the first call into this switch.
   gcc_checking_assert (!existed);
-  irange *dr = m_range_allocator.allocate (default_range);
+  irange *dr = m_range_allocator.clone <irange> (default_range);
   slot = dr;
 }
 
diff --git a/gcc/gimple-range-edge.h b/gcc/gimple-range-edge.h
index c131b3309cc..ce383b0aa6f 100644
--- a/gcc/gimple-range-edge.h
+++ b/gcc/gimple-range-edge.h
@@ -47,7 +47,7 @@ private:
 
   int m_max_edges;
   hash_map<edge, irange *> *m_edge_table;
-  irange_allocator m_range_allocator;
+  vrange_allocator m_range_allocator;
 };
 
 // If there is a range control statement at the end of block BB, return it.
diff --git a/gcc/gimple-range-side-effect.cc b/gcc/gimple-range-side-effect.cc
index 2c8c77dc569..8d2ac35bc8d 100644
--- a/gcc/gimple-range-side-effect.cc
+++ b/gcc/gimple-range-side-effect.cc
@@ -189,8 +189,10 @@ side_effect_manager::get_nonzero (tree name)
     m_nonzero.safe_grow_cleared (num_ssa_names + 20);
   if (!m_nonzero[v])
     {
-      m_nonzero[v] = m_range_allocator.allocate (2);
-      m_nonzero[v]->set_nonzero (TREE_TYPE (name));
+      tree type = TREE_TYPE (name);
+      m_nonzero[v]
+	= static_cast <irange *> (m_range_allocator.alloc_vrange (type));
+      m_nonzero[v]->set_nonzero (type);
     }
   return *(m_nonzero[v]);
 }
@@ -259,14 +261,17 @@ side_effect_manager::add_range (tree name, basic_block bb, const irange &r)
       if (ptr->range->fits_p (cur))
 	*(ptr->range) = cur;
       else
-	ptr->range = m_range_allocator.allocate (cur);
+	{
+	  vrange &v = cur;
+	  ptr->range = static_cast <irange *> (m_range_allocator.clone (v));
+	}
       return;
     }
 
   // Otherwise create a record.
   bitmap_set_bit (m_on_exit[bb->index].m_names, SSA_NAME_VERSION (name));
   ptr = (exit_range *)obstack_alloc (&m_list_obstack, sizeof (exit_range));
-  ptr->range = m_range_allocator.allocate (r);
+  ptr->range = m_range_allocator.clone (r);
   ptr->name = name;
   ptr->next = m_on_exit[bb->index].head;
   m_on_exit[bb->index].head = ptr;
diff --git a/gcc/gimple-range-side-effect.h b/gcc/gimple-range-side-effect.h
index 848d94ba6d7..d76d6eb34f2 100644
--- a/gcc/gimple-range-side-effect.h
+++ b/gcc/gimple-range-side-effect.h
@@ -76,7 +76,7 @@ private:
   bitmap m_seen;
   bitmap_obstack m_bitmaps;
   struct obstack m_list_obstack;
-  irange_allocator m_range_allocator;
+  vrange_allocator m_range_allocator;
 };
 
 #endif // GCC_GIMPLE_RANGE_SIDE_H
diff --git a/gcc/value-range.h b/gcc/value-range.h
index d51998145da..a5da53f595e 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;
@@ -892,56 +892,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 <typename T> 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.
@@ -951,17 +958,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 <tree *> (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 <irange> (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 <vrange> (const vrange &src)
+{
+  if (is_a <irange> (src))
+    return clone <irange> (as_a <irange> (src));
+
+  gcc_unreachable ();
+}
+
 #endif // GCC_VALUE_RANGE_H
-- 
2.36.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 5/5] Convert ranger and clients to vrange.
  2022-05-30 13:27 [PATCH 1/5] Implement abstract vrange class Aldy Hernandez
                   ` (2 preceding siblings ...)
  2022-05-30 13:27 ` [PATCH 4/5] Revamp irange_allocator to handle vranges Aldy Hernandez
@ 2022-05-30 13:27 ` Aldy Hernandez
  2022-06-01  9:04   ` Aldy Hernandez
  2022-06-01  8:57 ` [PATCH 1/5] Implement abstract vrange class Aldy Hernandez
  4 siblings, 1 reply; 14+ messages in thread
From: Aldy Hernandez @ 2022-05-30 13:27 UTC (permalink / raw)
  To: GCC patches

Finally, the meat of the work.  Convert ranger and associated clients
to vrange.

Everything's relatively mechanical given the previous patches.  I did
include a minor cleanup in the edge code.  There's no need to check
that the type of the switch is an integer as non-integer switches are
invalid.  I verified this with an appropriately coded assert.

Tested on x86-64 & ppc64le Linux.

gcc/ChangeLog:

	* gimple-range-cache.cc (ssa_block_ranges::dump): Convert to vrange.
	(sbr_vector::sbr_vector): Same.
	(sbr_vector::grow): Same.
	(sbr_vector::set_bb_range): Same.
	(sbr_vector::get_bb_range): Same.
	(sbr_sparse_bitmap::sbr_sparse_bitmap): Same.
	(sbr_sparse_bitmap::set_bb_range): Same.
	(sbr_sparse_bitmap::get_bb_range): Same.
	(block_range_cache::set_bb_range): Same.
	(block_range_cache::get_bb_range): Same.
	(block_range_cache::dump): Same.
	(ssa_global_cache::get_global_range): Same.
	(ssa_global_cache::set_global_range): Same.
	(ssa_global_cache::clear): Same.
	(ssa_global_cache::dump): Same.
	(ranger_cache::get_global_range): Same.
	(ranger_cache::set_global_range): Same.
	(ranger_cache::range_of_def): Same.
	(ranger_cache::entry_range): Same.
	(ranger_cache::exit_range): Same.
	(ranger_cache::edge_range): Same.
	(ranger_cache::range_of_expr): Same.
	(ranger_cache::range_on_edge): Same.
	(ranger_cache::block_range): Same.
	(ranger_cache::propagate_cache): Same.
	(ranger_cache::fill_block_cache): Same.
	(ranger_cache::range_from_dom): Same.
	* gimple-range-cache.h: Same.
	* gimple-range-edge.cc (gimple_outgoing_range::get_edge_range):
	Same.
	(gimple_outgoing_range::switch_edge_range): Same.
	(gimple_outgoing_range::edge_range_p): Same.
	* gimple-range-edge.h: Same.
	* gimple-range-fold.cc (fur_source::get_operand): Same.
	(fur_source::get_phi_operand): Same.
	(fur_edge::get_operand): Same.
	(fur_edge::get_phi_operand): Same.
	(fur_stmt::get_operand): Same.
	(fur_stmt::get_phi_operand): Same.
	(fur_list::fur_list): Same.
	(fur_list::get_operand): Same.
	(fur_list::get_phi_operand): Same.
	(fold_range): Same.
	(adjust_imagpart_expr): Same.
	(adjust_realpart_expr): Same.
	(gimple_range_adjustment): Same.
	(fold_using_range::fold_stmt): Same.
	(fold_using_range::range_of_range_op): Same.
	(fold_using_range::range_of_address): Same.
	(fold_using_range::range_of_phi): Same.
	(fold_using_range::range_of_call): Same.
	(fold_using_range::range_of_builtin_call): Same.
	(fold_using_range::range_of_builtin_int_call): Same.
	(fold_using_range::range_of_cond_expr): Same.
	(fur_source::register_outgoing_edges): Same.
	* gimple-range-fold.h (fold_range): Same.
	(gimple_range_type): Same.
	(gimple_range_ssa_p): Same.
	* gimple-range-gori.cc (gimple_range_calc_op1): Same.
	(gimple_range_calc_op2): Same.
	(gori_compute::compute_operand_range_switch): Same.
	(gori_compute::compute_operand_range): Same.
	(gori_compute::logical_combine): Same.
	(gori_compute::compute_logical_operands): Same.
	(gori_compute::compute_operand1_range): Same.
	(gori_compute::compute_operand2_range): Same.
	(gori_compute::compute_operand1_and_operand2_range): Same.
	(gori_compute::outgoing_edge_range_p): Same.
	(gori_compute::condexpr_adjust): Same.
	* gimple-range-gori.h (gimple_range_calc_op1): Same.
	(gimple_range_calc_op2): Same.
	* gimple-range-path.cc (path_range_query::get_cache): Same.
	(path_range_query::set_cache): Same.
	(path_range_query::range_on_path_entry): Same.
	(path_range_query::internal_range_of_expr): Same.
	(path_range_query::range_of_expr): Same.
	(path_range_query::ssa_range_in_phi): Same.
	(path_range_query::range_defined_in_block): Same.
	(path_range_query::compute_ranges_in_phis): Same.
	(path_range_query::compute_ranges_in_block): Same.
	(path_range_query::add_to_imports): Same.
	(path_range_query::range_of_stmt): Same.
	* gimple-range-path.h: Same.
	* gimple-range-side-effect.cc (stmt_side_effects::add_range): Same.
	(side_effect_manager::~side_effect_manager): Same.
	(side_effect_manager::get_nonzero): Same.
	(side_effect_manager::maybe_adjust_range): Same.
	(side_effect_manager::add_range): Same.
	* gimple-range-side-effect.h: Same.
	* gimple-range-tests.cc: Same.
	* gimple-range-trace.cc (range_tracer::trailer): Same.
	(debug_seed_ranger): Same.
	* gimple-range-trace.h: Same.
	* gimple-range.cc (gimple_ranger::range_of_expr): Same.
	(gimple_ranger::range_on_entry): Same.
	(gimple_ranger::range_on_exit): Same.
	(gimple_ranger::range_on_edge): Same.
	(gimple_ranger::fold_range_internal): Same.
	(gimple_ranger::range_of_stmt): Same.
	(gimple_ranger::prefill_name): Same.
	(gimple_ranger::prefill_stmt_dependencies): Same.
	(gimple_ranger::export_global_ranges): Same.
	(gimple_ranger::dump_bb): Same.
	* gimple-range.h: Same.
	* gimple-ssa-warn-access.cc (check_nul_terminated_array): Same.
	(memmodel_to_uhwi): Same.
	* tree-ssa-loop-niter.cc (refine_value_range_using_guard): Same.
	(determine_value_range): Same.
	(record_nonwrapping_iv): Same.
	(infer_loop_bounds_from_signedness): Same.
	(scev_var_range_cant_overflow): Same.
	* tree-ssa-threadedge.cc (hybrid_jt_simplifier::simplify): Same.
	* value-query.cc (range_query::range_on_edge): Same.
	(range_query::range_of_stmt): Same.
	(range_query::value_of_expr): Same.
	(range_query::value_on_edge): Same.
	(range_query::value_of_stmt): Same.
	(range_query::get_tree_range): Same.
	(update_global_range): Same.
	(get_range_global): Same.
	(gimple_range_global): Same.
	(global_range_query::range_of_expr): Same.
	(range_query::query_relation): Same.
	* value-query.h (gimple_range_global): Same.
	(update_global_range): Same.
	* vr-values.cc (vr_values::range_of_expr): Same.
	(bounds_of_var_in_loop): Same.
	(simplify_using_ranges::vrp_visit_cond_stmt): Same.
	* vr-values.h (class vr_values): Same.
---
 gcc/gimple-range-cache.cc       | 136 ++++++++++++++++--------------
 gcc/gimple-range-cache.h        |  32 +++----
 gcc/gimple-range-edge.cc        |  12 +--
 gcc/gimple-range-edge.h         |   2 +-
 gcc/gimple-range-fold.cc        | 144 +++++++++++++++++++-------------
 gcc/gimple-range-fold.h         |  37 ++++----
 gcc/gimple-range-gori.cc        | 116 ++++++++++++++-----------
 gcc/gimple-range-gori.h         |  42 +++++-----
 gcc/gimple-range-path.cc        |  47 ++++++-----
 gcc/gimple-range-path.h         |  16 ++--
 gcc/gimple-range-side-effect.cc |  20 ++---
 gcc/gimple-range-side-effect.h  |  14 ++--
 gcc/gimple-range-tests.cc       |   3 +-
 gcc/gimple-range-trace.cc       |   9 +-
 gcc/gimple-range-trace.h        |   2 +-
 gcc/gimple-range.cc             |  44 ++++++----
 gcc/gimple-range.h              |  14 ++--
 gcc/gimple-ssa-warn-access.cc   |   7 +-
 gcc/tree-ssa-loop-niter.cc      |  16 ++--
 gcc/tree-ssa-threadedge.cc      |   4 +-
 gcc/value-query.cc              |  73 ++++++++--------
 gcc/value-query.h               |  16 ++--
 gcc/vr-values.cc                |  29 ++++---
 gcc/vr-values.h                 |   2 +-
 24 files changed, 457 insertions(+), 380 deletions(-)

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 9c541993fb6..4983e4d3aa7 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -44,11 +44,14 @@ along with GCC; see the file COPYING3.  If not see
 class ssa_block_ranges
 {
 public:
-  virtual bool set_bb_range (const_basic_block bb, const irange &r) = 0;
-  virtual bool get_bb_range (irange &r, const_basic_block bb) = 0;
+  ssa_block_ranges (tree t) : m_type (t) { }
+  virtual bool set_bb_range (const_basic_block bb, const vrange &r) = 0;
+  virtual bool get_bb_range (vrange &r, const_basic_block bb) = 0;
   virtual bool bb_range_p (const_basic_block bb) = 0;
 
   void dump(FILE *f);
+private:
+  tree m_type;
 };
 
 // Print the list of known ranges for file F in a nice format.
@@ -57,7 +60,7 @@ void
 ssa_block_ranges::dump (FILE *f)
 {
   basic_block bb;
-  int_range_max r;
+  tmp_range r (m_type);
 
   FOR_EACH_BB_FN (bb, cfun)
     if (get_bb_range (r, bb))
@@ -77,14 +80,14 @@ class sbr_vector : public ssa_block_ranges
 public:
   sbr_vector (tree t, vrange_allocator *allocator);
 
-  virtual bool set_bb_range (const_basic_block bb, const irange &r) override;
-  virtual bool get_bb_range (irange &r, const_basic_block bb) override;
+  virtual bool set_bb_range (const_basic_block bb, const vrange &r) override;
+  virtual bool get_bb_range (vrange &r, const_basic_block bb) override;
   virtual bool bb_range_p (const_basic_block bb) override;
 protected:
-  irange **m_tab;	// Non growing vector.
+  vrange **m_tab;	// Non growing vector.
   int m_tab_size;
-  int_range<2> m_varying;
-  int_range<2> m_undefined;
+  vrange *m_varying;
+  vrange *m_undefined;
   tree m_type;
   vrange_allocator *m_range_allocator;
   void grow ();
@@ -94,18 +97,21 @@ protected:
 // Initialize a block cache for an ssa_name of type T.
 
 sbr_vector::sbr_vector (tree t, vrange_allocator *allocator)
+  : ssa_block_ranges (t)
 {
   gcc_checking_assert (TYPE_P (t));
   m_type = t;
   m_range_allocator = allocator;
   m_tab_size = last_basic_block_for_fn (cfun) + 1;
-  m_tab = static_cast <irange **>
-    (allocator->alloc (m_tab_size * sizeof (irange *)));
-  memset (m_tab, 0, m_tab_size * sizeof (irange *));
+  m_tab = static_cast <vrange **>
+    (allocator->alloc (m_tab_size * sizeof (vrange *)));
+  memset (m_tab, 0, m_tab_size * sizeof (vrange *));
 
   // Create the cached type range.
-  m_varying.set_varying (t);
-  m_undefined.set_undefined ();
+  m_varying = m_range_allocator->alloc_vrange (t);
+  m_undefined = m_range_allocator->alloc_vrange (t);
+  m_varying->set_varying (t);
+  m_undefined->set_undefined ();
 }
 
 // Grow the vector when the CFG has increased in size.
@@ -122,10 +128,10 @@ sbr_vector::grow ()
   int new_size = inc + curr_bb_size;
 
   // Allocate new memory, copy the old vector and clear the new space.
-  irange **t = static_cast <irange **>
-    (m_range_allocator->alloc (new_size * sizeof (irange *)));
-  memcpy (t, m_tab, m_tab_size * sizeof (irange *));
-  memset (t + m_tab_size, 0, (new_size - m_tab_size) * sizeof (irange *));
+  vrange **t = static_cast <vrange **>
+    (m_range_allocator->alloc (new_size * sizeof (vrange *)));
+  memcpy (t, m_tab, m_tab_size * sizeof (vrange *));
+  memset (t + m_tab_size, 0, (new_size - m_tab_size) * sizeof (vrange *));
 
   m_tab = t;
   m_tab_size = new_size;
@@ -134,15 +140,15 @@ sbr_vector::grow ()
 // Set the range for block BB to be R.
 
 bool
-sbr_vector::set_bb_range (const_basic_block bb, const irange &r)
+sbr_vector::set_bb_range (const_basic_block bb, const vrange &r)
 {
-  irange *m;
+  vrange *m;
   if (bb->index >= m_tab_size)
     grow ();
   if (r.varying_p ())
-    m = &m_varying;
+    m = m_varying;
   else if (r.undefined_p ())
-    m = &m_undefined;
+    m = m_undefined;
   else
     m = m_range_allocator->clone (r);
   m_tab[bb->index] = m;
@@ -153,11 +159,11 @@ sbr_vector::set_bb_range (const_basic_block bb, const irange &r)
 // there is no range.
 
 bool
-sbr_vector::get_bb_range (irange &r, const_basic_block bb)
+sbr_vector::get_bb_range (vrange &r, const_basic_block bb)
 {
   if (bb->index >= m_tab_size)
     return false;
-  irange *m = m_tab[bb->index];
+  vrange *m = m_tab[bb->index];
   if (m)
     {
       r = *m;
@@ -193,14 +199,14 @@ class sbr_sparse_bitmap : public ssa_block_ranges
 {
 public:
   sbr_sparse_bitmap (tree t, vrange_allocator *allocator, bitmap_obstack *bm);
-  virtual bool set_bb_range (const_basic_block bb, const irange &r) override;
-  virtual bool get_bb_range (irange &r, const_basic_block bb) override;
+  virtual bool set_bb_range (const_basic_block bb, const vrange &r) override;
+  virtual bool get_bb_range (vrange &r, const_basic_block bb) override;
   virtual bool bb_range_p (const_basic_block bb) override;
 private:
   void bitmap_set_quad (bitmap head, int quad, int quad_value);
   int bitmap_get_quad (const_bitmap head, int quad);
   vrange_allocator *m_range_allocator;
-  irange *m_range[SBR_NUM];
+  vrange *m_range[SBR_NUM];
   bitmap_head bitvec;
   tree m_type;
 };
@@ -209,6 +215,7 @@ private:
 
 sbr_sparse_bitmap::sbr_sparse_bitmap (tree t, vrange_allocator *allocator,
 				      bitmap_obstack *bm)
+  : ssa_block_ranges (t)
 {
   gcc_checking_assert (TYPE_P (t));
   m_type = t;
@@ -216,16 +223,14 @@ sbr_sparse_bitmap::sbr_sparse_bitmap (tree t, vrange_allocator *allocator,
   bitmap_tree_view (&bitvec);
   m_range_allocator = allocator;
   // Pre-cache varying.
-  m_range[0] = static_cast <irange *> (m_range_allocator->alloc_vrange (t));
+  m_range[0] = m_range_allocator->alloc_vrange (t);
   m_range[0]->set_varying (t);
   // Pre-cache zero and non-zero values for pointers.
   if (POINTER_TYPE_P (t))
     {
-      m_range[1]
-	= static_cast <irange *> (m_range_allocator->alloc_vrange (t));
+      m_range[1] = m_range_allocator->alloc_vrange (t);
       m_range[1]->set_nonzero (t);
-      m_range[2]
-	= static_cast <irange *> (m_range_allocator->alloc_vrange (t));
+      m_range[2] = m_range_allocator->alloc_vrange (t);
       m_range[2]->set_zero (t);
     }
   else
@@ -257,7 +262,7 @@ sbr_sparse_bitmap::bitmap_get_quad (const_bitmap head, int quad)
 // Set the range on entry to basic block BB to R.
 
 bool
-sbr_sparse_bitmap::set_bb_range (const_basic_block bb, const irange &r)
+sbr_sparse_bitmap::set_bb_range (const_basic_block bb, const vrange &r)
 {
   if (r.undefined_p ())
     {
@@ -283,7 +288,7 @@ sbr_sparse_bitmap::set_bb_range (const_basic_block bb, const irange &r)
 // there is no range.
 
 bool
-sbr_sparse_bitmap::get_bb_range (irange &r, const_basic_block bb)
+sbr_sparse_bitmap::get_bb_range (vrange &r, const_basic_block bb)
 {
   int value = bitmap_get_quad (&bitvec, bb->index);
 
@@ -333,7 +338,7 @@ block_range_cache::~block_range_cache ()
 
 bool
 block_range_cache::set_bb_range (tree name, const_basic_block bb,
-				 const irange &r)
+				 const vrange &r)
 {
   unsigned v = SSA_NAME_VERSION (name);
   if (v >= m_ssa_ranges.length ())
@@ -379,7 +384,7 @@ block_range_cache::query_block_ranges (tree name)
 // is one.
 
 bool
-block_range_cache::get_bb_range (irange &r, tree name, const_basic_block bb)
+block_range_cache::get_bb_range (vrange &r, tree name, const_basic_block bb)
 {
   ssa_block_ranges *ptr = query_block_ranges (name);
   if (ptr)
@@ -423,12 +428,13 @@ void
 block_range_cache::dump (FILE *f, basic_block bb, bool print_varying)
 {
   unsigned x;
-  int_range_max r;
   bool summarize_varying = false;
   for (x = 1; x < m_ssa_ranges.length (); ++x)
     {
       if (!gimple_range_ssa_p (ssa_name (x)))
 	continue;
+
+      tmp_range r (TREE_TYPE (ssa_name (x)));
       if (m_ssa_ranges[x] && m_ssa_ranges[x]->get_bb_range (r, bb))
 	{
 	  if (!print_varying && r.varying_p ())
@@ -450,6 +456,8 @@ block_range_cache::dump (FILE *f, basic_block bb, bool print_varying)
 	{
 	  if (!gimple_range_ssa_p (ssa_name (x)))
 	    continue;
+
+	  tmp_range r (TREE_TYPE (ssa_name (x)));
 	  if (m_ssa_ranges[x] && m_ssa_ranges[x]->get_bb_range (r, bb))
 	    {
 	      if (r.varying_p ())
@@ -485,13 +493,13 @@ ssa_global_cache::~ssa_global_cache ()
 // Return the value in R.
 
 bool
-ssa_global_cache::get_global_range (irange &r, tree name) const
+ssa_global_cache::get_global_range (vrange &r, tree name) const
 {
   unsigned v = SSA_NAME_VERSION (name);
   if (v >= m_tab.length ())
     return false;
 
-  irange *stow = m_tab[v];
+  vrange *stow = m_tab[v];
   if (!stow)
     return false;
   r = *stow;
@@ -502,13 +510,13 @@ ssa_global_cache::get_global_range (irange &r, tree name) const
 // Return TRUE if there was already a range set, otherwise false.
 
 bool
-ssa_global_cache::set_global_range (tree name, const irange &r)
+ssa_global_cache::set_global_range (tree name, const vrange &r)
 {
   unsigned v = SSA_NAME_VERSION (name);
   if (v >= m_tab.length ())
     m_tab.safe_grow_cleared (num_ssa_names + 1);
 
-  irange *m = m_tab[v];
+  vrange *m = m_tab[v];
   if (m && m->fits_p (r))
     *m = r;
   else
@@ -533,7 +541,7 @@ void
 ssa_global_cache::clear ()
 {
   if (m_tab.address ())
-    memset (m_tab.address(), 0, m_tab.length () * sizeof (irange *));
+    memset (m_tab.address(), 0, m_tab.length () * sizeof (vrange *));
 }
 
 // Dump the contents of the global cache to F.
@@ -545,8 +553,9 @@ ssa_global_cache::dump (FILE *f)
   bool print_header = true;
   for (unsigned x = 1; x < num_ssa_names; x++)
     {
-      int_range_max r;
+      tmp_range r;
       if (gimple_range_ssa_p (ssa_name (x)) &&
+	  r.init (TREE_TYPE (ssa_name (x))) &&
 	  get_global_range (r, ssa_name (x))  && !r.varying_p ())
 	{
 	  if (print_header)
@@ -809,11 +818,11 @@ ranger_cache::dump_bb (FILE *f, basic_block bb)
 // global range is not set, and return the legacy global value in R.
 
 bool
-ranger_cache::get_global_range (irange &r, tree name) const
+ranger_cache::get_global_range (vrange &r, tree name) const
 {
   if (m_globals.get_global_range (r, name))
     return true;
-  r = gimple_range_global (name);
+  gimple_range_global (r, name);
   return false;
 }
 
@@ -825,7 +834,7 @@ ranger_cache::get_global_range (irange &r, tree name) const
 // After this call, the global cache will have a value.
 
 bool
-ranger_cache::get_global_range (irange &r, tree name, bool &current_p)
+ranger_cache::get_global_range (vrange &r, tree name, bool &current_p)
 {
   bool had_global = get_global_range (r, name);
 
@@ -847,7 +856,7 @@ ranger_cache::get_global_range (irange &r, tree name, bool &current_p)
 //  Set the global range of NAME to R and give it a timestamp.
 
 void
-ranger_cache::set_global_range (tree name, const irange &r)
+ranger_cache::set_global_range (tree name, const vrange &r)
 {
   if (m_globals.set_global_range (name, r))
     {
@@ -882,7 +891,7 @@ ranger_cache::set_global_range (tree name, const irange &r)
 // get the best global value available.
 
 void
-ranger_cache::range_of_def (irange &r, tree name, basic_block bb)
+ranger_cache::range_of_def (vrange &r, tree name, basic_block bb)
 {
   gcc_checking_assert (gimple_range_ssa_p (name));
   gcc_checking_assert (!bb || bb == gimple_bb (SSA_NAME_DEF_STMT (name)));
@@ -895,7 +904,7 @@ ranger_cache::range_of_def (irange &r, tree name, basic_block bb)
       if (gimple_get_lhs (s) == name)
 	fold_range (r, s, get_global_range_query ());
       else
-	r = gimple_range_global (name);
+	gimple_range_global (r, name);
     }
 }
 
@@ -903,12 +912,12 @@ ranger_cache::range_of_def (irange &r, tree name, basic_block bb)
 // lookups.
 
 void
-ranger_cache::entry_range (irange &r, tree name, basic_block bb,
+ranger_cache::entry_range (vrange &r, tree name, basic_block bb,
 			   enum rfd_mode mode)
 {
   if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun))
     {
-      r = gimple_range_global (name);
+      gimple_range_global (r, name);
       return;
     }
 
@@ -923,12 +932,12 @@ ranger_cache::entry_range (irange &r, tree name, basic_block bb,
 // lookups.
 
 void
-ranger_cache::exit_range (irange &r, tree name, basic_block bb,
+ranger_cache::exit_range (vrange &r, tree name, basic_block bb,
 			  enum rfd_mode mode)
 {
   if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun))
     {
-      r = gimple_range_global (name);
+      gimple_range_global (r, name);
       return;
     }
 
@@ -944,7 +953,7 @@ ranger_cache::exit_range (irange &r, tree name, basic_block bb,
 // Always returns a range and true.
 
 bool
-ranger_cache::edge_range (irange &r, edge e, tree name, enum rfd_mode mode)
+ranger_cache::edge_range (vrange &r, edge e, tree name, enum rfd_mode mode)
 {
   exit_range (r, name, e->src, mode);
   // If this is not an abnormal edge, check for side effects on exit.
@@ -961,7 +970,7 @@ ranger_cache::edge_range (irange &r, edge e, tree name, enum rfd_mode mode)
 // Implement range_of_expr.
 
 bool
-ranger_cache::range_of_expr (irange &r, tree name, gimple *stmt)
+ranger_cache::range_of_expr (vrange &r, tree name, gimple *stmt)
 {
   if (!gimple_range_ssa_p (name))
     {
@@ -985,7 +994,7 @@ ranger_cache::range_of_expr (irange &r, tree name, gimple *stmt)
 // the current cache values.
 
 bool
-ranger_cache::range_on_edge (irange &r, edge e, tree expr)
+ranger_cache::range_on_edge (vrange &r, edge e, tree expr)
 {
   if (gimple_range_ssa_p (expr))
     return edge_range (r, e, expr, RFD_NONE);
@@ -997,7 +1006,7 @@ ranger_cache::range_on_edge (irange &r, edge e, tree expr)
 // def block for NAME.  Otherwise, return false if the cache is empty.
 
 bool
-ranger_cache::block_range (irange &r, basic_block bb, tree name, bool calc)
+ranger_cache::block_range (vrange &r, basic_block bb, tree name, bool calc)
 {
   gcc_checking_assert (gimple_range_ssa_p (name));
 
@@ -1041,9 +1050,10 @@ ranger_cache::propagate_cache (tree name)
   basic_block bb;
   edge_iterator ei;
   edge e;
-  int_range_max new_range;
-  int_range_max current_range;
-  int_range_max e_range;
+  tree type = TREE_TYPE (name);
+  tmp_range new_range (type);
+  tmp_range current_range (type);
+  tmp_range e_range (type);
 
   // Process each block by seeing if its calculated range on entry is
   // the same as its cached value. If there is a difference, update
@@ -1178,8 +1188,8 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
 {
   edge_iterator ei;
   edge e;
-  int_range_max block_result;
-  int_range_max undefined;
+  tmp_range block_result (TREE_TYPE (name));
+  tmp_range undefined (TREE_TYPE (name));
 
   // At this point we shouldn't be looking at the def, entry or exit block.
   gcc_checking_assert (bb != def_bb && bb != ENTRY_BLOCK_PTR_FOR_FN (cfun) &&
@@ -1232,7 +1242,7 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
       FOR_EACH_EDGE (e, ei, node->preds)
 	{
 	  basic_block pred = e->src;
-	  int_range_max r;
+	  tmp_range r (TREE_TYPE (name));
 
 	  if (DEBUG_RANGE_CACHE)
 	    fprintf (dump_file, "  %d->%d ",e->src->index, e->dest->index);
@@ -1306,7 +1316,7 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
 // dominator tree based on MODE.
 
 bool
-ranger_cache::range_from_dom (irange &r, tree name, basic_block start_bb,
+ranger_cache::range_from_dom (vrange &r, tree name, basic_block start_bb,
 			      enum rfd_mode mode)
 {
   if (mode == RFD_NONE || !dom_info_available_p (CDI_DOMINATORS))
diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h
index 2472cd04f47..d17950c7154 100644
--- a/gcc/gimple-range-cache.h
+++ b/gcc/gimple-range-cache.h
@@ -34,8 +34,8 @@ public:
   block_range_cache ();
   ~block_range_cache ();
 
-  bool set_bb_range (tree name, const_basic_block bb, const irange &r);
-  bool get_bb_range (irange &r, tree name, const_basic_block bb);
+  bool set_bb_range (tree name, const_basic_block bb, const vrange &v);
+  bool get_bb_range (vrange &v, tree name, const_basic_block bb);
   bool bb_range_p (tree name, const_basic_block bb);
 
   void dump (FILE *f);
@@ -57,13 +57,13 @@ class ssa_global_cache
 public:
   ssa_global_cache ();
   ~ssa_global_cache ();
-  bool get_global_range (irange &r, tree name) const;
-  bool set_global_range (tree name, const irange &r);
+  bool get_global_range (vrange &r, tree name) const;
+  bool set_global_range (tree name, const vrange &r);
   void clear_global_range (tree name);
   void clear ();
   void dump (FILE *f = stderr);
 private:
-  vec<irange *> m_tab;
+  vec<vrange *> m_tab;
   vrange_allocator *m_range_allocator;
 };
 
@@ -77,13 +77,13 @@ public:
   ranger_cache (int not_executable_flag, bool use_imm_uses);
   ~ranger_cache ();
 
-  virtual bool range_of_expr (irange &r, tree name, gimple *stmt);
-  virtual bool range_on_edge (irange &r, edge e, tree expr);
-  bool block_range (irange &r, basic_block bb, tree name, bool calc = true);
+  virtual bool range_of_expr (vrange &r, tree name, gimple *stmt);
+  virtual bool range_on_edge (vrange &r, edge e, tree expr);
+  bool block_range (vrange &r, basic_block bb, tree name, bool calc = true);
 
-  bool get_global_range (irange &r, tree name) const;
-  bool get_global_range (irange &r, tree name, bool &current_p);
-  void set_global_range (tree name, const irange &r);
+  bool get_global_range (vrange &r, tree name) const;
+  bool get_global_range (vrange &r, tree name, bool &current_p);
+  void set_global_range (tree name, const vrange &r);
 
   void propagate_updated_value (tree name, basic_block bb);
 
@@ -106,11 +106,11 @@ private:
       RFD_READ_ONLY,	// Scan DOM tree, do not write to cache.
       RFD_FILL		// Scan DOM tree, updating important nodes.
     };
-  bool range_from_dom (irange &r, tree name, basic_block bb, enum rfd_mode);
-  void range_of_def (irange &r, tree name, basic_block bb = NULL);
-  void entry_range (irange &r, tree expr, basic_block bb, enum rfd_mode);
-  void exit_range (irange &r, tree expr, basic_block bb, enum rfd_mode);
-  bool edge_range (irange &r, edge e, tree name, enum rfd_mode);
+  bool range_from_dom (vrange &r, tree name, basic_block bb, enum rfd_mode);
+  void range_of_def (vrange &r, tree name, basic_block bb = NULL);
+  void entry_range (vrange &r, tree expr, basic_block bb, enum rfd_mode);
+  void exit_range (vrange &r, tree expr, basic_block bb, enum rfd_mode);
+  bool edge_range (vrange &r, edge e, tree name, enum rfd_mode);
 
   vec<basic_block> m_workback;
   class update_list *m_update;
diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc
index 5264e627c9a..6fe33408f7e 100644
--- a/gcc/gimple-range-edge.cc
+++ b/gcc/gimple-range-edge.cc
@@ -83,11 +83,8 @@ gimple_outgoing_range::~gimple_outgoing_range ()
 // Use a cached value if it exists, or calculate it if not.
 
 bool
-gimple_outgoing_range::get_edge_range (irange &r, gimple *s, edge e)
+gimple_outgoing_range::switch_edge_range (irange &r, gswitch *sw, edge e)
 {
-  gcc_checking_assert (is_a<gswitch *> (s));
-  gswitch *sw = as_a<gswitch *> (s);
-
   // ADA currently has cases where the index is 64 bits and the case
   // arguments are 32 bit, causing a trap when we create a case_range.
   // Until this is resolved (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87798)
@@ -204,12 +201,9 @@ gimple_outgoing_range::edge_range_p (irange &r, edge e)
 
   gcc_checking_assert (is_a<gswitch *> (s));
   gswitch *sw = as_a<gswitch *> (s);
-  tree type = TREE_TYPE (gimple_switch_index (sw));
-
-  if (!irange::supports_type_p (type))
-    return NULL;
 
-  if (get_edge_range (r, sw, e))
+  // Switches can only be integers.
+  if (switch_edge_range (as_a <irange> (r), sw, e))
     return s;
 
   return NULL;
diff --git a/gcc/gimple-range-edge.h b/gcc/gimple-range-edge.h
index ce383b0aa6f..a9c4af8715b 100644
--- a/gcc/gimple-range-edge.h
+++ b/gcc/gimple-range-edge.h
@@ -43,7 +43,7 @@ public:
   gimple *edge_range_p (irange &r, edge e);
 private:
   void calc_switch_ranges (gswitch *sw);
-  bool get_edge_range (irange &r, gimple *s, edge e);
+  bool switch_edge_range (irange &r, gswitch *sw, edge e);
 
   int m_max_edges;
   hash_map<edge, irange *> *m_edge_table;
diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index c53d2863d5e..7fed5a99513 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -60,7 +60,7 @@ fur_source::fur_source (range_query *q)
 // Invoke range_of_expr on EXPR.
 
 bool
-fur_source::get_operand (irange &r, tree expr)
+fur_source::get_operand (vrange &r, tree expr)
 {
   return m_query->range_of_expr (r, expr);
 }
@@ -69,7 +69,7 @@ fur_source::get_operand (irange &r, tree expr)
 // range_query to get the range on the edge.
 
 bool
-fur_source::get_phi_operand (irange &r, tree expr, edge e)
+fur_source::get_phi_operand (vrange &r, tree expr, edge e)
 {
   return m_query->range_on_edge (r, e, expr);
 }
@@ -109,8 +109,8 @@ class fur_edge : public fur_source
 {
 public:
   fur_edge (edge e, range_query *q = NULL);
-  virtual bool get_operand (irange &r, tree expr) override;
-  virtual bool get_phi_operand (irange &r, tree expr, edge e) override;
+  virtual bool get_operand (vrange &r, tree expr) override;
+  virtual bool get_phi_operand (vrange &r, tree expr, edge e) override;
 private:
   edge m_edge;
 };
@@ -126,7 +126,7 @@ fur_edge::fur_edge (edge e, range_query *q) : fur_source (q)
 // Get the value of EXPR on edge m_edge.
 
 bool
-fur_edge::get_operand (irange &r, tree expr)
+fur_edge::get_operand (vrange &r, tree expr)
 {
   return m_query->range_on_edge (r, m_edge, expr);
 }
@@ -135,7 +135,7 @@ fur_edge::get_operand (irange &r, tree expr)
 // range_query to get the range on the edge.
 
 bool
-fur_edge::get_phi_operand (irange &r, tree expr, edge e)
+fur_edge::get_phi_operand (vrange &r, tree expr, edge e)
 {
   // Edge to edge recalculations not supoprted yet, until we sort it out.
   gcc_checking_assert (e == m_edge);
@@ -152,7 +152,7 @@ fur_stmt::fur_stmt (gimple *s, range_query *q) : fur_source (q)
 // Retreive range of EXPR as it occurs as a use on stmt M_STMT.
 
 bool
-fur_stmt::get_operand (irange &r, tree expr)
+fur_stmt::get_operand (vrange &r, tree expr)
 {
   return m_query->range_of_expr (r, expr, m_stmt);
 }
@@ -161,7 +161,7 @@ fur_stmt::get_operand (irange &r, tree expr)
 // range_query to get the range on the edge.
 
 bool
-fur_stmt::get_phi_operand (irange &r, tree expr, edge e)
+fur_stmt::get_phi_operand (vrange &r, tree expr, edge e)
 {
   // Pick up the range of expr from edge E.
   fur_edge e_src (e, m_query);
@@ -214,42 +214,42 @@ fur_depend::register_relation (edge e, relation_kind k, tree op1, tree op2)
 class fur_list : public fur_source
 {
 public:
-  fur_list (irange &r1);
-  fur_list (irange &r1, irange &r2);
-  fur_list (unsigned num, irange *list);
-  virtual bool get_operand (irange &r, tree expr) override;
-  virtual bool get_phi_operand (irange &r, tree expr, edge e) override;
+  fur_list (vrange &r1);
+  fur_list (vrange &r1, vrange &r2);
+  fur_list (unsigned num, vrange **list);
+  virtual bool get_operand (vrange &r, tree expr) override;
+  virtual bool get_phi_operand (vrange &r, tree expr, edge e) override;
 private:
-  int_range_max m_local[2];
-  irange *m_list;
+  vrange *m_local[2];
+  vrange **m_list;
   unsigned m_index;
   unsigned m_limit;
 };
 
 // One range supplied for unary operations.
 
-fur_list::fur_list (irange &r1) : fur_source (NULL)
+fur_list::fur_list (vrange &r1) : fur_source (NULL)
 {
   m_list = m_local;
   m_index = 0;
   m_limit = 1;
-  m_local[0] = r1;
+  m_local[0] = &r1;
 }
 
 // Two ranges supplied for binary operations.
 
-fur_list::fur_list (irange &r1, irange &r2) : fur_source (NULL)
+fur_list::fur_list (vrange &r1, vrange &r2) : fur_source (NULL)
 {
   m_list = m_local;
   m_index = 0;
   m_limit = 2;
-  m_local[0] = r1;
-  m_local[1] = r2;
+  m_local[0] = &r1;
+  m_local[1] = &r2;
 }
 
 // Arbitrary number of ranges in a vector.
 
-fur_list::fur_list (unsigned num, irange *list) : fur_source (NULL)
+fur_list::fur_list (unsigned num, vrange **list) : fur_source (NULL)
 {
   m_list = list;
   m_index = 0;
@@ -259,18 +259,18 @@ fur_list::fur_list (unsigned num, irange *list) : fur_source (NULL)
 // Get the next operand from the vector, ensure types are compatible.
 
 bool
-fur_list::get_operand (irange &r, tree expr)
+fur_list::get_operand (vrange &r, tree expr)
 {
   if (m_index >= m_limit)
     return m_query->range_of_expr (r, expr);
-  r = m_list[m_index++];
+  r = *m_list[m_index++];
   gcc_checking_assert (range_compatible_p (TREE_TYPE (expr), r.type ()));
   return true;
 }
 
 // This will simply pick the next operand from the vector.
 bool
-fur_list::get_phi_operand (irange &r, tree expr, edge e ATTRIBUTE_UNUSED)
+fur_list::get_phi_operand (vrange &r, tree expr, edge e ATTRIBUTE_UNUSED)
 {
   return get_operand (r, expr);
 }
@@ -278,7 +278,7 @@ fur_list::get_phi_operand (irange &r, tree expr, edge e ATTRIBUTE_UNUSED)
 // Fold stmt S into range R using R1 as the first operand.
 
 bool
-fold_range (irange &r, gimple *s, irange &r1)
+fold_range (vrange &r, gimple *s, vrange &r1)
 {
   fold_using_range f;
   fur_list src (r1);
@@ -288,7 +288,7 @@ fold_range (irange &r, gimple *s, irange &r1)
 // Fold stmt S into range R using R1  and R2 as the first two operands.
 
 bool
-fold_range (irange &r, gimple *s, irange &r1, irange &r2)
+fold_range (vrange &r, gimple *s, vrange &r1, vrange &r2)
 {
   fold_using_range f;
   fur_list src (r1, r2);
@@ -299,7 +299,7 @@ fold_range (irange &r, gimple *s, irange &r1, irange &r2)
 // operands encountered.
 
 bool
-fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector)
+fold_range (vrange &r, gimple *s, unsigned num_elements, vrange **vector)
 {
   fold_using_range f;
   fur_list src (num_elements, vector);
@@ -309,7 +309,7 @@ fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector)
 // Fold stmt S into range R using range query Q.
 
 bool
-fold_range (irange &r, gimple *s, range_query *q)
+fold_range (vrange &r, gimple *s, range_query *q)
 {
   fold_using_range f;
   fur_stmt src (s, q);
@@ -319,7 +319,7 @@ fold_range (irange &r, gimple *s, range_query *q)
 // Recalculate stmt S into R using range query Q as if it were on edge ON_EDGE.
 
 bool
-fold_range (irange &r, gimple *s, edge on_edge, range_query *q)
+fold_range (vrange &r, gimple *s, edge on_edge, range_query *q)
 {
   fold_using_range f;
   fur_edge src (on_edge, q);
@@ -370,7 +370,7 @@ adjust_pointer_diff_expr (irange &res, const gimple *diff_stmt)
 // Adjust the range for an IMAGPART_EXPR.
 
 static void
-adjust_imagpart_expr (irange &res, const gimple *stmt)
+adjust_imagpart_expr (vrange &res, const gimple *stmt)
 {
   tree name = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
 
@@ -413,7 +413,7 @@ adjust_imagpart_expr (irange &res, const gimple *stmt)
 // Adjust the range for a REALPART_EXPR.
 
 static void
-adjust_realpart_expr (irange &res, const gimple *stmt)
+adjust_realpart_expr (vrange &res, const gimple *stmt)
 {
   tree name = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
 
@@ -442,12 +442,12 @@ adjust_realpart_expr (irange &res, const gimple *stmt)
 // this statement.
 
 static void
-gimple_range_adjustment (irange &res, const gimple *stmt)
+gimple_range_adjustment (vrange &res, const gimple *stmt)
 {
   switch (gimple_expr_code (stmt))
     {
     case POINTER_DIFF_EXPR:
-      adjust_pointer_diff_expr (res, stmt);
+      adjust_pointer_diff_expr (as_a <irange> (res), stmt);
       return;
 
     case IMAGPART_EXPR:
@@ -536,7 +536,7 @@ gimple_range_operand2 (const gimple *stmt)
 // be calculated, return false.
 
 bool
-fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name)
+fold_using_range::fold_stmt (vrange &r, gimple *s, fur_source &src, tree name)
 {
   bool res = false;
   // If name and S are specified, make sure it is an LHS of S.
@@ -549,7 +549,7 @@ fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name)
   // Process addresses.
   if (gimple_code (s) == GIMPLE_ASSIGN
       && gimple_assign_rhs_code (s) == ADDR_EXPR)
-    return range_of_address (r, s, src);
+    return range_of_address (as_a <irange> (r), s, src);
 
   if (range_op_handler (s))
     res = range_of_range_op (r, s, src);
@@ -566,7 +566,7 @@ fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name)
       if (!name || !gimple_range_ssa_p (name))
 	return false;
       // We don't understand the stmt, so return the global range.
-      r = gimple_range_global (name);
+      gimple_range_global (r, name);
       return true;
     }
 
@@ -587,9 +587,8 @@ fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name)
 // If a range cannot be calculated, return false.
 
 bool
-fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
+fold_using_range::range_of_range_op (vrange &r, gimple *s, fur_source &src)
 {
-  int_range_max range1, range2;
   tree type = gimple_range_type (s);
   if (!type)
     return false;
@@ -599,13 +598,16 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
   tree lhs = gimple_get_lhs (s);
   tree op1 = gimple_range_operand1 (s);
   tree op2 = gimple_range_operand2 (s);
+  tmp_range range1 (TREE_TYPE (op1));
+  tmp_range range2;
 
   if (src.get_operand (range1, op1))
     {
       if (!op2)
 	{
 	  // Fold range, and register any dependency if available.
-	  int_range<2> r2 (type);
+	  tmp_range r2 (type);
+	  r2.set_varying (type);
 	  handler.fold_range (r, type, range1, r2);
 	  if (lhs && gimple_range_ssa_p (op1))
 	    {
@@ -617,7 +619,8 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
 		src.register_relation (s, rel, lhs, op1);
 	    }
 	}
-      else if (src.get_operand (range2, op2))
+      else if (range2.init (TREE_TYPE (op2))
+	       && src.get_operand (range2, op2))
 	{
 	  relation_kind rel = src.query_relation (op1, op2);
 	  if (dump_file && (dump_flags & TDF_DETAILS) && rel != VREL_VARYING)
@@ -630,7 +633,8 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
 	    }
 	  // Fold range, and register any dependency if available.
 	  handler.fold_range (r, type, range1, range2, rel);
-	  relation_fold_and_or (r, s, src);
+	  if (irange::supports_type_p (type))
+	    relation_fold_and_or (as_a <irange> (r), s, src);
 	  if (lhs)
 	    {
 	      if (src.gori ())
@@ -663,7 +667,8 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
 		e0 = NULL;
 	      if (!single_pred_p (e1->dest))
 		e1 = NULL;
-	      src.register_outgoing_edges (as_a<gcond *> (s), r, e0, e1);
+	      src.register_outgoing_edges (as_a<gcond *> (s),
+					   as_a <irange> (r), e0, e1);
 	    }
 	}
       else
@@ -729,12 +734,12 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src)
 	{
 	  /* For -fdelete-null-pointer-checks -fno-wrapv-pointer we don't
 	     allow going from non-NULL pointer to NULL.  */
-	  if (!range_includes_zero_p (&r))
+	  if (r.undefined_p () || !r.contains_p (build_zero_cst (r.type ())))
 	    {
 	      /* We could here instead adjust r by off >> LOG2_BITS_PER_UNIT
 		 using POINTER_PLUS_EXPR if off_cst and just fall back to
 		 this.  */
-	      r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
+	      r.set_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
 	      return true;
 	    }
 	}
@@ -746,22 +751,22 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src)
 	  && known_ne (off, 0)
 	  && (flag_delete_null_pointer_checks || known_gt (off, 0)))
 	{
-	  r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
+	  r.set_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
 	  return true;
 	}
-      r = int_range<2> (TREE_TYPE (gimple_assign_rhs1 (stmt)));
+      r.set_varying (TREE_TYPE (gimple_assign_rhs1 (stmt)));
       return true;
     }
 
   // Handle "= &a".
   if (tree_single_nonzero_warnv_p (expr, &strict_overflow_p))
     {
-      r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
+      r.set_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
       return true;
     }
 
   // Otherwise return varying.
-  r = int_range<2> (TREE_TYPE (gimple_assign_rhs1 (stmt)));
+  r.set_varying (TREE_TYPE (gimple_assign_rhs1 (stmt)));
   return true;
 }
 
@@ -769,12 +774,12 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src)
 // If a range cannot be calculated, return false.
 
 bool
-fold_using_range::range_of_phi (irange &r, gphi *phi, fur_source &src)
+fold_using_range::range_of_phi (vrange &r, gphi *phi, fur_source &src)
 {
   tree phi_def = gimple_phi_result (phi);
   tree type = gimple_range_type (phi);
-  int_range_max arg_range;
-  int_range_max equiv_range;
+  tmp_range arg_range (type);
+  tmp_range equiv_range (type);
   unsigned x;
 
   if (!type)
@@ -881,7 +886,7 @@ fold_using_range::range_of_phi (irange &r, gphi *phi, fur_source &src)
 // If a range cannot be calculated, return false.
 
 bool
-fold_using_range::range_of_call (irange &r, gcall *call, fur_source &src)
+fold_using_range::range_of_call (vrange &r, gcall *call, fur_source &src)
 {
   tree type = gimple_range_type (call);
   if (!type)
@@ -893,18 +898,18 @@ fold_using_range::range_of_call (irange &r, gcall *call, fur_source &src)
   if (range_of_builtin_call (r, call, src))
     ;
   else if (gimple_stmt_nonnegative_warnv_p (call, &strict_overflow_p))
-    r.set (build_int_cst (type, 0), TYPE_MAX_VALUE (type));
+    r.set_nonnegative (type);
   else if (gimple_call_nonnull_result_p (call)
 	   || gimple_call_nonnull_arg (call))
-    r = range_nonzero (type);
+    r.set_nonzero (type);
   else
     r.set_varying (type);
 
   // If there is an LHS, intersect that with what is known.
   if (lhs)
     {
-      value_range def;
-      def = gimple_range_global (lhs);
+      tmp_range def (TREE_TYPE (lhs));
+      gimple_range_global (def, lhs);
       r.intersect (def);
     }
   return true;
@@ -971,13 +976,30 @@ get_letter_range (tree type, irange &lowers, irange &uppers)
 // TRUE.  Otherwise return FALSE.
 
 bool
-fold_using_range::range_of_builtin_call (irange &r, gcall *call,
+fold_using_range::range_of_builtin_call (vrange &r, gcall *call,
 					 fur_source &src)
 {
   combined_fn func = gimple_call_combined_fn (call);
   if (func == CFN_LAST)
     return false;
 
+  tree type = gimple_range_type (call);
+  gcc_checking_assert (type);
+
+  if (irange::supports_type_p (type))
+    return range_of_builtin_int_call (as_a <irange> (r), call, src);
+
+  return false;
+}
+
+bool
+fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
+					     fur_source &src)
+{
+  combined_fn func = gimple_call_combined_fn (call);
+  if (func == CFN_LAST)
+    return false;
+
   tree type = gimple_range_type (call);
   tree arg;
   int mini, maxi, zerov = 0, prec;
@@ -1256,9 +1278,8 @@ fold_using_range::range_of_builtin_call (irange &r, gcall *call,
 // If a range cannot be calculated, return false.
 
 bool
-fold_using_range::range_of_cond_expr  (irange &r, gassign *s, fur_source &src)
+fold_using_range::range_of_cond_expr  (vrange &r, gassign *s, fur_source &src)
 {
-  int_range_max cond_range, range1, range2;
   tree cond = gimple_assign_rhs1 (s);
   tree op1 = gimple_assign_rhs2 (s);
   tree op2 = gimple_assign_rhs3 (s);
@@ -1267,6 +1288,9 @@ fold_using_range::range_of_cond_expr  (irange &r, gassign *s, fur_source &src)
   if (!type)
     return false;
 
+  tmp_range range1 (TREE_TYPE (op1));
+  tmp_range range2 (TREE_TYPE (op2));
+  tmp_range cond_range (TREE_TYPE (cond));
   gcc_checking_assert (gimple_assign_rhs_code (s) == COND_EXPR);
   gcc_checking_assert (range_compatible_p (TREE_TYPE (op1), TREE_TYPE (op2)));
   src.get_operand (cond_range, cond);
@@ -1438,7 +1462,6 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
 void
 fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge e1)
 {
-  int_range_max r;
   int_range<2> e0_range, e1_range;
   tree name;
   basic_block bb = gimple_bb (s);
@@ -1505,6 +1528,7 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
 	continue;
       tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
       tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (stmt));
+      tmp_range r (TREE_TYPE (name));
       if (ssa1 && ssa2)
 	{
 	  if (e0 && gori ()->outgoing_edge_range_p (r, e0, name, *m_query)
diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h
index 4b5d4b6e0b8..df24280ee40 100644
--- a/gcc/gimple-range-fold.h
+++ b/gcc/gimple-range-fold.h
@@ -23,7 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 #define GCC_GIMPLE_RANGE_FOLD_H
 
 // This file is the main include point for gimple range folding.
-// These routines will fold stmt S into the result irange R.
+// These routines will fold stmt S into the result range R.
 // Any ssa_names on the stmt will be calculated using the range_query
 // parameter via a call to range_of_expr.
 // If no range_query is provided, current global range info will be used.
@@ -31,15 +31,15 @@ along with GCC; see the file COPYING3.  If not see
 // it appeared on that edge.
 
 // Fold stmt S into range R using range query Q.
-bool fold_range (irange &r, gimple *s, range_query *q = NULL);
+bool fold_range (vrange &r, gimple *s, range_query *q = NULL);
 // Recalculate stmt S into R using range query Q as if it were on edge ON_EDGE.
-bool fold_range (irange &r, gimple *s, edge on_edge, range_query *q = NULL);
+bool fold_range (vrange &v, gimple *s, edge on_edge, range_query *q = NULL);
 
 // These routines the operands to be specified when manually folding.
 // Any excess queries will be drawn from the current range_query.
-bool fold_range (irange &r, gimple *s, irange &r1);
-bool fold_range (irange &r, gimple *s, irange &r1, irange &r2);
-bool fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector);
+bool fold_range (vrange &r, gimple *s, vrange &r1);
+bool fold_range (vrange &r, gimple *s, vrange &r1, vrange &r2);
+bool fold_range (vrange &r, gimple *s, unsigned num_elements, vrange **vector);
 
 // Return the type of range which statement S calculates.  If the type is
 // unsupported or no type can be determined, return NULL_TREE.
@@ -66,7 +66,7 @@ gimple_range_type (const gimple *s)
 	    type = TREE_TYPE (type);
 	}
     }
-  if (type && irange::supports_type_p (type))
+  if (type && vrange::supports_type_p (type))
     return type;
   return NULL_TREE;
 }
@@ -79,7 +79,7 @@ gimple_range_ssa_p (tree exp)
   if (exp && TREE_CODE (exp) == SSA_NAME &&
       !SSA_NAME_IS_VIRTUAL_OPERAND (exp) &&
       !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp) &&
-      irange::supports_type_p (TREE_TYPE (exp)))
+      vrange::supports_type_p (TREE_TYPE (exp)))
     return exp;
   return NULL_TREE;
 }
@@ -108,8 +108,8 @@ public:
   fur_source (range_query *q = NULL);
   inline range_query *query () { return m_query; }
   inline class gori_compute *gori () { return m_gori; };
-  virtual bool get_operand (irange &r, tree expr);
-  virtual bool get_phi_operand (irange &r, tree expr, edge e);
+  virtual bool get_operand (vrange &r, tree expr);
+  virtual bool get_phi_operand (vrange &r, tree expr, edge e);
   virtual relation_kind query_relation (tree op1, tree op2);
   virtual void register_relation (gimple *stmt, relation_kind k, tree op1,
 				  tree op2);
@@ -128,8 +128,8 @@ class fur_stmt : public fur_source
 {
 public:
   fur_stmt (gimple *s, range_query *q = NULL);
-  virtual bool get_operand (irange &r, tree expr) override;
-  virtual bool get_phi_operand (irange &r, tree expr, edge e) override;
+  virtual bool get_operand (vrange &r, tree expr) override;
+  virtual bool get_phi_operand (vrange &r, tree expr, edge e) override;
   virtual relation_kind query_relation (tree op1, tree op2) override;
 private:
   gimple *m_stmt;
@@ -161,17 +161,18 @@ extern tree gimple_range_operand2 (const gimple *s);
 class fold_using_range
 {
 public:
-  bool fold_stmt (irange &r, gimple *s, class fur_source &src,
+  bool fold_stmt (vrange &r, gimple *s, class fur_source &src,
 		  tree name = NULL_TREE);
 protected:
-  bool range_of_range_op (irange &r, gimple *s, fur_source &src);
-  bool range_of_call (irange &r, gcall *call, fur_source &src);
-  bool range_of_cond_expr (irange &r, gassign* cond, fur_source &src);
+  bool range_of_range_op (vrange &r, gimple *s, fur_source &src);
+  bool range_of_call (vrange &r, gcall *call, fur_source &src);
+  bool range_of_cond_expr (vrange &r, gassign* cond, fur_source &src);
   bool range_of_address (irange &r, gimple *s, fur_source &src);
-  bool range_of_builtin_call (irange &r, gcall *call, fur_source &src);
+  bool range_of_builtin_call (vrange &r, gcall *call, fur_source &src);
+  bool range_of_builtin_int_call (irange &r, gcall *call, fur_source &src);
   void range_of_builtin_ubsan_call (irange &r, gcall *call, tree_code code,
 				    fur_source &src);
-  bool range_of_phi (irange &r, gphi *phi, fur_source &src);
+  bool range_of_phi (vrange &r, gphi *phi, fur_source &src);
   void range_of_ssa_name_with_loop_info (irange &, tree, class loop *, gphi *,
 					 fur_source &src);
   void relation_fold_and_or (irange& lhs_range, gimple *s, fur_source &src);
diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index 0e0cf2128e7..47d0dab8cb9 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -34,7 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 // LHS_RANGE.  Return false if nothing can be determined.
 
 bool
-gimple_range_calc_op1 (irange &r, const gimple *stmt, const irange &lhs_range)
+gimple_range_calc_op1 (vrange &r, const gimple *stmt, const vrange &lhs_range)
 {
   gcc_checking_assert (gimple_num_ops (stmt) < 3);
   // Give up on empty ranges.
@@ -55,8 +55,8 @@ gimple_range_calc_op1 (irange &r, const gimple *stmt, const irange &lhs_range)
 // nothing can be determined.
 
 bool
-gimple_range_calc_op1 (irange &r, const gimple *stmt,
-		       const irange &lhs_range, const irange &op2_range)
+gimple_range_calc_op1 (vrange &r, const gimple *stmt,
+		       const vrange &lhs_range, const vrange &op2_range)
 {
   // Give up on empty ranges.
   if (lhs_range.undefined_p ())
@@ -86,8 +86,8 @@ gimple_range_calc_op1 (irange &r, const gimple *stmt,
 // nothing can be determined.
 
 bool
-gimple_range_calc_op2 (irange &r, const gimple *stmt,
-		       const irange &lhs_range, const irange &op1_range)
+gimple_range_calc_op2 (vrange &r, const gimple *stmt,
+		       const vrange &lhs_range, const vrange &op1_range)
 {
   // Give up on empty ranges.
   if (lhs_range.undefined_p ())
@@ -663,8 +663,8 @@ gori_compute::gori_compute (int not_executable_flag)
 // was not resolvable.
 
 bool
-gori_compute::compute_operand_range_switch (irange &r, gswitch *s,
-					    const irange &lhs,
+gori_compute::compute_operand_range_switch (vrange &r, gswitch *s,
+					    const vrange &lhs,
 					    tree name, fur_source &src)
 {
   tree op1 = gimple_switch_index (s);
@@ -691,8 +691,8 @@ gori_compute::compute_operand_range_switch (irange &r, gswitch *s,
 // store the evaluation in R, otherwise return FALSE.
 
 bool
-gori_compute::compute_operand_range (irange &r, gimple *stmt,
-				     const irange &lhs, tree name,
+gori_compute::compute_operand_range (vrange &r, gimple *stmt,
+				     const vrange &lhs, tree name,
 				     fur_source &src)
 {
   // If the lhs doesn't tell us anything, neither will unwinding further.
@@ -743,13 +743,18 @@ gori_compute::compute_operand_range (irange &r, gimple *stmt,
 	  print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
 	}
 
-      int_range_max op1_trange, op1_frange;
-      int_range_max op2_trange, op2_frange;
-      compute_logical_operands (op1_trange, op1_frange, stmt, lhs,
+      tree type = TREE_TYPE (name);
+      tmp_range op1_trange (type), op1_frange (type);
+      tmp_range op2_trange (type), op2_frange (type);
+      compute_logical_operands (op1_trange, op1_frange, stmt,
+				as_a <irange> (lhs),
 				name, src, op1, op1_in_chain);
-      compute_logical_operands (op2_trange, op2_frange, stmt, lhs,
+      compute_logical_operands (op2_trange, op2_frange, stmt,
+				as_a <irange> (lhs),
 				name, src, op2, op2_in_chain);
-      res = logical_combine (r, gimple_expr_code (stmt), lhs,
+      res = logical_combine (r,
+			     gimple_expr_code (stmt),
+			     as_a <irange> (lhs),
 			     op1_trange, op1_frange, op2_trange, op2_frange);
       if (idx)
 	tracer.trailer (idx, "compute_operand", res, name, r);
@@ -789,10 +794,10 @@ range_is_either_true_or_false (const irange &r)
 // the LHS.
 
 bool
-gori_compute::logical_combine (irange &r, enum tree_code code,
+gori_compute::logical_combine (vrange &r, enum tree_code code,
 			       const irange &lhs,
-			       const irange &op1_true, const irange &op1_false,
-			       const irange &op2_true, const irange &op2_false)
+			       const vrange &op1_true, const vrange &op1_false,
+			       const vrange &op2_true, const vrange &op2_false)
 {
   if (op1_true.varying_p () && op1_false.varying_p ()
       && op2_true.varying_p () && op2_false.varying_p ())
@@ -868,7 +873,7 @@ gori_compute::logical_combine (irange &r, enum tree_code code,
   if (!range_is_either_true_or_false (lhs))
     {
       bool res;
-      int_range_max r1;
+      tmp_range r1 (r);
       if (logical_combine (r1, code, m_bool_zero, op1_true, op1_false,
 			   op2_true, op2_false)
 	  && logical_combine (r, code, m_bool_one, op1_true, op1_false,
@@ -898,11 +903,11 @@ gori_compute::logical_combine (irange &r, enum tree_code code,
 	else
 	  {
 	    // The FALSE side is the union of the other 3 cases.
-	    int_range_max ff (op1_false);
+	    tmp_range ff (op1_false);
 	    ff.intersect (op2_false);
-	    int_range_max tf (op1_true);
+	    tmp_range tf (op1_true);
 	    tf.intersect (op2_false);
-	    int_range_max ft (op1_false);
+	    tmp_range ft (op1_false);
 	    ft.intersect (op2_true);
 	    r = ff;
 	    r.union_ (tf);
@@ -925,11 +930,11 @@ gori_compute::logical_combine (irange &r, enum tree_code code,
 	  {
 	    // The TRUE side of an OR operation will be the union of
 	    // the other three combinations.
-	    int_range_max tt (op1_true);
+	    tmp_range tt (op1_true);
 	    tt.intersect (op2_true);
-	    int_range_max tf (op1_true);
+	    tmp_range tf (op1_true);
 	    tf.intersect (op2_false);
-	    int_range_max ft (op1_false);
+	    tmp_range ft (op1_false);
 	    ft.intersect (op2_true);
 	    r = tt;
 	    r.union_ (tf);
@@ -951,7 +956,7 @@ gori_compute::logical_combine (irange &r, enum tree_code code,
 // OP_IN_CHAIN is true.
 
 void
-gori_compute::compute_logical_operands (irange &true_range, irange &false_range,
+gori_compute::compute_logical_operands (vrange &true_range, vrange &false_range,
 					gimple *stmt,
 					const irange &lhs,
 					tree name, fur_source &src,
@@ -1007,13 +1012,15 @@ gori_compute::compute_logical_operands (irange &true_range, irange &false_range,
 // R, or false if no range could be calculated.
 
 bool
-gori_compute::compute_operand1_range (irange &r, gimple *stmt,
-				      const irange &lhs, tree name,
+gori_compute::compute_operand1_range (vrange &r, gimple *stmt,
+				      const vrange &lhs, tree name,
 				      fur_source &src)
 {
-  int_range_max op1_range, op2_range;
   tree op1 = gimple_range_operand1 (stmt);
   tree op2 = gimple_range_operand2 (stmt);
+  tmp_range op1_range (TREE_TYPE (op1));
+  tmp_range tmp (TREE_TYPE (op1));
+  tmp_range op2_range;
 
   // Fetch the known range for op1 in this block.
   src.get_operand (op1_range, op1);
@@ -1021,8 +1028,9 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt,
   // Now range-op calcuate and put that result in r.
   if (op2)
     {
+      op2_range.init (TREE_TYPE (op2));
       src.get_operand (op2_range, op2);
-      if (!gimple_range_calc_op1 (r, stmt, lhs, op2_range))
+      if (!gimple_range_calc_op1 (tmp, stmt, lhs, op2_range))
 	return false;
     }
   else
@@ -1030,7 +1038,7 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt,
       // We pass op1_range to the unary operation.  Nomally it's a
       // hidden range_for_type parameter, but sometimes having the
       // actual range can result in better information.
-      if (!gimple_range_calc_op1 (r, stmt, lhs, op1_range))
+      if (!gimple_range_calc_op1 (tmp, stmt, lhs, op1_range))
 	return false;
     }
 
@@ -1053,7 +1061,7 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt,
       tracer.print (idx, "Computes ");
       print_generic_expr (dump_file, op1, TDF_SLIM);
       fprintf (dump_file, " = ");
-      r.dump (dump_file);
+      tmp.dump (dump_file);
       fprintf (dump_file, " intersect Known range : ");
       op1_range.dump (dump_file);
       fputc ('\n', dump_file);
@@ -1061,13 +1069,14 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt,
   // Intersect the calculated result with the known result and return if done.
   if (op1 == name)
     {
-      r.intersect (op1_range);
+      tmp.intersect (op1_range);
+      r = tmp;
       if (idx)
 	tracer.trailer (idx, "produces ", true, name, r);
       return true;
     }
   // If the calculation continues, we're using op1_range as the new LHS.
-  op1_range.intersect (r);
+  op1_range.intersect (tmp);
 
   if (idx)
     tracer.trailer (idx, "produces ", true, op1, op1_range);
@@ -1084,19 +1093,21 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt,
 // R, or false if no range could be calculated.
 
 bool
-gori_compute::compute_operand2_range (irange &r, gimple *stmt,
-				      const irange &lhs, tree name,
+gori_compute::compute_operand2_range (vrange &r, gimple *stmt,
+				      const vrange &lhs, tree name,
 				      fur_source &src)
 {
-  int_range_max op1_range, op2_range;
   tree op1 = gimple_range_operand1 (stmt);
   tree op2 = gimple_range_operand2 (stmt);
+  tmp_range op1_range (TREE_TYPE (op1));
+  tmp_range op2_range (TREE_TYPE (op2));
+  tmp_range tmp (TREE_TYPE (op2));
 
   src.get_operand (op1_range, op1);
   src.get_operand (op2_range, op2);
 
   // Intersect with range for op2 based on lhs and op1.
-  if (!gimple_range_calc_op2 (r, stmt, lhs, op1_range))
+  if (!gimple_range_calc_op2 (tmp, stmt, lhs, op1_range))
     return false;
 
   unsigned idx;
@@ -1118,7 +1129,7 @@ gori_compute::compute_operand2_range (irange &r, gimple *stmt,
       tracer.print (idx, "Computes ");
       print_generic_expr (dump_file, op2, TDF_SLIM);
       fprintf (dump_file, " = ");
-      r.dump (dump_file);
+      tmp.dump (dump_file);
       fprintf (dump_file, " intersect Known range : ");
       op2_range.dump (dump_file);
       fputc ('\n', dump_file);
@@ -1126,13 +1137,14 @@ gori_compute::compute_operand2_range (irange &r, gimple *stmt,
   // Intersect the calculated result with the known result and return if done.
   if (op2 == name)
     {
-      r.intersect (op2_range);
+      tmp.intersect (op2_range);
+      r = tmp;
       if (idx)
 	tracer.trailer (idx, " produces ", true, NULL_TREE, r);
       return true;
     }
   // If the calculation continues, we're using op2_range as the new LHS.
-  op2_range.intersect (r);
+  op2_range.intersect (tmp);
 
   if (idx)
     tracer.trailer (idx, " produces ", true, op2, op2_range);
@@ -1149,13 +1161,13 @@ gori_compute::compute_operand2_range (irange &r, gimple *stmt,
 // R, or false if no range could be calculated.
 
 bool
-gori_compute::compute_operand1_and_operand2_range (irange &r,
+gori_compute::compute_operand1_and_operand2_range (vrange &r,
 						   gimple *stmt,
-						   const irange &lhs,
+						   const vrange &lhs,
 						   tree name,
 						   fur_source &src)
 {
-  int_range_max op_range;
+  tmp_range op_range (TREE_TYPE (name));
 
   // Calculate a good a range for op2.  Since op1 == op2, this will
   // have already included whatever the actual range of name is.
@@ -1236,10 +1248,9 @@ gori_compute::has_edge_range_p (tree name, edge e)
 // control edge or NAME is not defined by this edge.
 
 bool
-gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name,
+gori_compute::outgoing_edge_range_p (vrange &r, edge e, tree name,
 				     range_query &q)
 {
-  int_range_max lhs;
   unsigned idx;
 
   if ((e->flags & m_not_executable_flag))
@@ -1252,6 +1263,7 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name,
     }
 
   gcc_checking_assert (gimple_range_ssa_p (name));
+  int_range_max lhs;
   // Determine if there is an outgoing edge.
   gimple *stmt = outgoing.edge_range_p (lhs, e);
   if (!stmt)
@@ -1312,10 +1324,9 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name,
 // edge and OP2 on the false edge.
 
 bool
-gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond,
+gori_compute::condexpr_adjust (vrange &r1, vrange &r2, gimple *, tree cond,
 			       tree op1, tree op2, fur_source &src)
 {
-  int_range_max tmp, cond_true, cond_false;
   tree ssa1 = gimple_range_ssa_p (op1);
   tree ssa2 = gimple_range_ssa_p (op2);
   if (!ssa1 && !ssa2)
@@ -1341,15 +1352,19 @@ gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond,
     return false;
 
   // Pick up the current values of each part of the condition.
-  int_range_max cl, cr;
-  src.get_operand (cl, gimple_assign_rhs1 (cond_def));
-  src.get_operand (cr, gimple_assign_rhs2 (cond_def));
+  tree rhs1 = gimple_assign_rhs1 (cond_def);
+  tree rhs2 = gimple_assign_rhs2 (cond_def);
+  tmp_range cl (TREE_TYPE (rhs1));
+  tmp_range cr (TREE_TYPE (rhs2));
+  src.get_operand (cl, rhs1);
+  src.get_operand (cr, rhs2);
 
   tree cond_name = c1 ? c1 : c2;
   gimple *def_stmt = SSA_NAME_DEF_STMT (cond_name);
 
   // Evaluate the value of COND_NAME on the true and false edges, using either
   // the op1 or op2 routines based on its location.
+  tmp_range cond_true (type), cond_false (type);
   if (c1)
     {
       if (!hand.op1_range (cond_false, type, m_bool_zero, cr))
@@ -1380,6 +1395,7 @@ gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond,
     }
 
    // Now solve for SSA1 or SSA2 if they are in the dependency chain.
+  tmp_range tmp (type);
    if (ssa1 && in_chain_p (ssa1, cond_name))
     {
       if (compute_operand_range (tmp, def_stmt, cond_true, ssa1, src))
diff --git a/gcc/gimple-range-gori.h b/gcc/gimple-range-gori.h
index 605884e2e53..f5f691fe424 100644
--- a/gcc/gimple-range-gori.h
+++ b/gcc/gimple-range-gori.h
@@ -121,7 +121,7 @@ private:
 //   on *ANY* edge that has been seen.  FALSE indicates that the global value
 //   is applicable everywhere that has been processed.
 //
-// outgoing_edge_range_p (irange &range, edge e, tree name)
+// outgoing_edge_range_p (vrange &range, edge e, tree name)
 //   Actually does the calculation of RANGE for name on E
 //   This represents application of whatever static range effect edge E
 //   may have on NAME, not any cumulative effect.
@@ -157,8 +157,8 @@ class gori_compute : public gori_map
 {
 public:
   gori_compute (int not_executable_flag = 0);
-  bool outgoing_edge_range_p (irange &r, edge e, tree name, range_query &q);
-  bool condexpr_adjust (irange &r1, irange &r2, gimple *s, tree cond, tree op1,
+  bool outgoing_edge_range_p (vrange &r, edge e, tree name, range_query &q);
+  bool condexpr_adjust (vrange &r1, vrange &r2, gimple *s, tree cond, tree op1,
 			tree op2, fur_source &src);
   bool has_edge_range_p (tree name, basic_block bb = NULL);
   bool has_edge_range_p (tree name, edge e);
@@ -166,24 +166,24 @@ public:
 private:
   bool may_recompute_p (tree name, edge e);
   bool may_recompute_p (tree name, basic_block bb = NULL);
-  bool compute_operand_range (irange &r, gimple *stmt, const irange &lhs,
+  bool compute_operand_range (vrange &r, gimple *stmt, const vrange &lhs,
 			      tree name, class fur_source &src);
-  bool compute_operand_range_switch (irange &r, gswitch *s, const irange &lhs,
+  bool compute_operand_range_switch (vrange &r, gswitch *s, const vrange &lhs,
 				     tree name, fur_source &src);
-  bool compute_operand1_range (irange &r, gimple *stmt, const irange &lhs,
+  bool compute_operand1_range (vrange &r, gimple *stmt, const vrange &lhs,
 			       tree name, fur_source &src);
-  bool compute_operand2_range (irange &r, gimple *stmt, const irange &lhs,
+  bool compute_operand2_range (vrange &r, gimple *stmt, const vrange &lhs,
 			       tree name, fur_source &src);
-  bool compute_operand1_and_operand2_range (irange &r, gimple *stmt,
-					    const irange &lhs, tree name,
+  bool compute_operand1_and_operand2_range (vrange &r, gimple *stmt,
+					    const vrange &lhs, tree name,
 					    fur_source &src);
-  void compute_logical_operands (irange &true_range, irange &false_range,
+  void compute_logical_operands (vrange &true_range, vrange &false_range,
 				 gimple *stmt, const irange &lhs,
 				 tree name, fur_source &src, tree op,
 				 bool op_in_chain);
-  bool logical_combine (irange &r, enum tree_code code, const irange &lhs,
-			const irange &op1_true, const irange &op1_false,
-			const irange &op2_true, const irange &op2_false);
+  bool logical_combine (vrange &r, enum tree_code code, const irange &lhs,
+			const vrange &op1_true, const vrange &op1_false,
+			const vrange &op2_true, const vrange &op2_false);
   int_range<2> m_bool_zero;	// Boolean false cached.
   int_range<2> m_bool_one;	// Boolean true cached.
 
@@ -193,14 +193,14 @@ private:
 };
 
 // These routines provide a GIMPLE interface to the range-ops code.
-extern bool gimple_range_calc_op1 (irange &r, const gimple *s,
-				   const irange &lhs_range);
-extern bool gimple_range_calc_op1 (irange &r, const gimple *s,
-				   const irange &lhs_range,
-				   const irange &op2_range);
-extern bool gimple_range_calc_op2 (irange &r, const gimple *s,
-				   const irange &lhs_range,
-				   const irange &op1_range);
+extern bool gimple_range_calc_op1 (vrange &r, const gimple *s,
+				   const vrange &lhs_range);
+extern bool gimple_range_calc_op1 (vrange &r, const gimple *s,
+				   const vrange &lhs_range,
+				   const vrange &op2_range);
+extern bool gimple_range_calc_op2 (vrange &r, const gimple *s,
+				   const vrange &lhs_range,
+				   const vrange &op1_range);
 
 // For each name that is an import into BB's exports..
 #define FOR_EACH_GORI_IMPORT_NAME(gori, bb, name)			\
diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc
index 66f433dd1d5..4819332f358 100644
--- a/gcc/gimple-range-path.cc
+++ b/gcc/gimple-range-path.cc
@@ -83,7 +83,7 @@ path_range_query::clear_cache (tree name)
 // If NAME has a cache entry, return it in R, and return TRUE.
 
 inline bool
-path_range_query::get_cache (irange &r, tree name)
+path_range_query::get_cache (vrange &r, tree name)
 {
   if (!gimple_range_ssa_p (name))
     return get_global_range_query ()->range_of_expr (r, name);
@@ -98,7 +98,7 @@ path_range_query::get_cache (irange &r, tree name)
 // Set the cache entry for NAME to R.
 
 void
-path_range_query::set_cache (const irange &r, tree name)
+path_range_query::set_cache (const vrange &r, tree name)
 {
   unsigned v = SSA_NAME_VERSION (name);
   bitmap_set_bit (m_has_cache_entry, v);
@@ -149,7 +149,7 @@ path_range_query::defined_outside_path (tree name)
 // Return the range of NAME on entry to the path.
 
 void
-path_range_query::range_on_path_entry (irange &r, tree name)
+path_range_query::range_on_path_entry (vrange &r, tree name)
 {
   gcc_checking_assert (defined_outside_path (name));
   basic_block entry = entry_bb ();
@@ -168,7 +168,7 @@ path_range_query::range_on_path_entry (irange &r, tree name)
   // block.  This can happen when we're querying a block with only an
   // outgoing edge (no statement but the fall through edge), but for
   // which we can determine a range on entry to the block.
-  int_range_max tmp;
+  tmp_range tmp (TREE_TYPE (name));
   bool changed = false;
   r.set_undefined ();
   for (unsigned i = 0; i < EDGE_COUNT (entry->preds); ++i)
@@ -190,9 +190,9 @@ path_range_query::range_on_path_entry (irange &r, tree name)
 // Return the range of NAME at the end of the path being analyzed.
 
 bool
-path_range_query::internal_range_of_expr (irange &r, tree name, gimple *stmt)
+path_range_query::internal_range_of_expr (vrange &r, tree name, gimple *stmt)
 {
-  if (!irange::supports_type_p (TREE_TYPE (name)))
+  if (!vrange::supports_type_p (TREE_TYPE (name)))
     return false;
 
   if (get_cache (r, name))
@@ -209,18 +209,22 @@ path_range_query::internal_range_of_expr (irange &r, tree name, gimple *stmt)
       && range_defined_in_block (r, name, gimple_bb (stmt)))
     {
       if (TREE_CODE (name) == SSA_NAME)
-	r.intersect (gimple_range_global (name));
+	{
+	  tmp_range glob (TREE_TYPE (name));
+	  gimple_range_global (glob, name);
+	  r.intersect (glob);
+	}
 
       set_cache (r, name);
       return true;
     }
 
-  r = gimple_range_global (name);
+  gimple_range_global (r, name);
   return true;
 }
 
 bool
-path_range_query::range_of_expr (irange &r, tree name, gimple *stmt)
+path_range_query::range_of_expr (vrange &r, tree name, gimple *stmt)
 {
   if (internal_range_of_expr (r, name, stmt))
     {
@@ -269,7 +273,7 @@ path_range_query::ssa_defined_in_bb (tree name, basic_block bb)
 // calculating the PHI's range must not trigger additional lookups.
 
 void
-path_range_query::ssa_range_in_phi (irange &r, gphi *phi)
+path_range_query::ssa_range_in_phi (vrange &r, gphi *phi)
 {
   tree name = gimple_phi_result (phi);
   basic_block bb = gimple_bb (phi);
@@ -283,7 +287,7 @@ path_range_query::ssa_range_in_phi (irange &r, gphi *phi)
       // Try to fold the phi exclusively with global or cached values.
       // This will get things like PHI <5(99), 6(88)>.  We do this by
       // calling range_of_expr with no context.
-      int_range_max arg_range;
+      tmp_range arg_range (TREE_TYPE (name));
       r.set_undefined ();
       for (size_t i = 0; i < nargs; ++i)
 	{
@@ -312,7 +316,7 @@ path_range_query::ssa_range_in_phi (irange &r, gphi *phi)
 	  {
 	    if (m_resolve)
 	      {
-		int_range_max tmp;
+		tmp_range tmp (TREE_TYPE (name));
 		// Using both the range on entry to the path, and the
 		// range on this edge yields significantly better
 		// results.
@@ -335,7 +339,7 @@ path_range_query::ssa_range_in_phi (irange &r, gphi *phi)
 // TRUE.  Otherwise, return FALSE.
 
 bool
-path_range_query::range_defined_in_block (irange &r, tree name, basic_block bb)
+path_range_query::range_defined_in_block (vrange &r, tree name, basic_block bb)
 {
   gimple *def_stmt = SSA_NAME_DEF_STMT (name);
   basic_block def_bb = gimple_bb (def_stmt);
@@ -377,7 +381,6 @@ path_range_query::range_defined_in_block (irange &r, tree name, basic_block bb)
 void
 path_range_query::compute_ranges_in_phis (basic_block bb)
 {
-  int_range_max r;
   auto_bitmap phi_set;
 
   // PHIs must be resolved simultaneously on entry to the block
@@ -390,7 +393,11 @@ path_range_query::compute_ranges_in_phis (basic_block bb)
       gphi *phi = iter.phi ();
       tree name = gimple_phi_result (phi);
 
-      if (import_p (name) && range_defined_in_block (r, name, bb))
+      if (!import_p (name))
+	continue;
+
+      tmp_range r (TREE_TYPE (name));
+      if (range_defined_in_block (r, name, bb))
 	{
 	  unsigned v = SSA_NAME_VERSION (name);
 	  set_cache (r, name);
@@ -423,7 +430,6 @@ void
 path_range_query::compute_ranges_in_block (basic_block bb)
 {
   bitmap_iterator bi;
-  int_range_max r, cached_range;
   unsigned i;
 
   if (m_resolve && !at_entry ())
@@ -444,6 +450,7 @@ path_range_query::compute_ranges_in_block (basic_block bb)
   EXECUTE_IF_SET_IN_BITMAP (m_imports, 0, i, bi)
     {
       tree name = ssa_name (i);
+      tmp_range r (TREE_TYPE (name));
 
       if (gimple_code (SSA_NAME_DEF_STMT (name)) != GIMPLE_PHI
 	  && range_defined_in_block (r, name, bb))
@@ -480,8 +487,10 @@ path_range_query::compute_ranges_in_block (basic_block bb)
 
       if (bitmap_bit_p (exports, i))
 	{
+	  tmp_range r (TREE_TYPE (name));
 	  if (g.outgoing_edge_range_p (r, e, name, *this))
 	    {
+	      tmp_range cached_range (TREE_TYPE (name));
 	      if (get_cache (cached_range, name))
 		r.intersect (cached_range);
 
@@ -539,7 +548,7 @@ bool
 path_range_query::add_to_imports (tree name, bitmap imports)
 {
   if (TREE_CODE (name) == SSA_NAME
-      && irange::supports_type_p (TREE_TYPE (name)))
+      && vrange::supports_type_p (TREE_TYPE (name)))
     return bitmap_set_bit (imports, SSA_NAME_VERSION (name));
   return false;
 }
@@ -751,11 +760,11 @@ jt_fur_source::query_relation (tree op1, tree op2)
 // Return the range of STMT at the end of the path being analyzed.
 
 bool
-path_range_query::range_of_stmt (irange &r, gimple *stmt, tree)
+path_range_query::range_of_stmt (vrange &r, gimple *stmt, tree)
 {
   tree type = gimple_range_type (stmt);
 
-  if (!type || !irange::supports_type_p (type))
+  if (!type || !vrange::supports_type_p (type))
     return false;
 
   // If resolving unknowns, fold the statement making use of any
diff --git a/gcc/gimple-range-path.h b/gcc/gimple-range-path.h
index 914983bb0aa..2c4624e4cef 100644
--- a/gcc/gimple-range-path.h
+++ b/gcc/gimple-range-path.h
@@ -38,29 +38,29 @@ public:
 		       const bitmap_head *imports = NULL);
   void compute_ranges (edge e);
   void compute_imports (bitmap imports, basic_block exit);
-  bool range_of_expr (irange &r, tree name, gimple * = NULL) override;
-  bool range_of_stmt (irange &r, gimple *, tree name = NULL) override;
+  bool range_of_expr (vrange &r, tree name, gimple * = NULL) override;
+  bool range_of_stmt (vrange &r, gimple *, tree name = NULL) override;
   bool unreachable_path_p ();
   void dump (FILE *) override;
   void debug ();
 
 private:
-  bool internal_range_of_expr (irange &r, tree name, gimple *);
+  bool internal_range_of_expr (vrange &r, tree name, gimple *);
   bool defined_outside_path (tree name);
-  void range_on_path_entry (irange &r, tree name);
+  void range_on_path_entry (vrange &r, tree name);
   path_oracle *get_path_oracle () { return (path_oracle *)m_oracle; }
 
   // Cache manipulation.
-  void set_cache (const irange &r, tree name);
-  bool get_cache (irange &r, tree name);
+  void set_cache (const vrange &r, tree name);
+  bool get_cache (vrange &r, tree name);
   void clear_cache (tree name);
 
   // Methods to compute ranges for the given path.
-  bool range_defined_in_block (irange &, tree name, basic_block bb);
+  bool range_defined_in_block (vrange &, tree name, basic_block bb);
   void compute_ranges_in_block (basic_block bb);
   void compute_ranges_in_phis (basic_block bb);
   void adjust_for_non_null_uses (basic_block bb);
-  void ssa_range_in_phi (irange &r, gphi *phi);
+  void ssa_range_in_phi (vrange &r, gphi *phi);
   void compute_outgoing_relations (basic_block bb, basic_block next);
   void compute_phi_relations (basic_block bb, basic_block prev);
   void maybe_register_phi_relation (gphi *, edge e);
diff --git a/gcc/gimple-range-side-effect.cc b/gcc/gimple-range-side-effect.cc
index 8d2ac35bc8d..aae087b7227 100644
--- a/gcc/gimple-range-side-effect.cc
+++ b/gcc/gimple-range-side-effect.cc
@@ -58,7 +58,7 @@ non_null_loadstore (gimple *, tree op, tree, void *data)
 // Add NAME and RANGE to the the side effect summary.
 
 void
-stmt_side_effects::add_range (tree name, irange &range)
+stmt_side_effects::add_range (tree name, vrange &range)
 {
   m_names[num_args] = name;
   m_ranges[num_args] = range;
@@ -126,7 +126,7 @@ class exit_range
 {
 public:
   tree name;
-  irange *range;
+  vrange *range;
   exit_range *next;
 };
 
@@ -181,7 +181,7 @@ side_effect_manager::~side_effect_manager ()
 // Return a non-zero range value of the appropriate type for NAME from
 // the cache, creating it if necessary.
 
-const irange&
+const vrange&
 side_effect_manager::get_nonzero (tree name)
 {
   unsigned v = SSA_NAME_VERSION (name);
@@ -189,10 +189,8 @@ side_effect_manager::get_nonzero (tree name)
     m_nonzero.safe_grow_cleared (num_ssa_names + 20);
   if (!m_nonzero[v])
     {
-      tree type = TREE_TYPE (name);
-      m_nonzero[v]
-	= static_cast <irange *> (m_range_allocator.alloc_vrange (type));
-      m_nonzero[v]->set_nonzero (type);
+      m_nonzero[v] = m_range_allocator.alloc_vrange (TREE_TYPE (name));
+      m_nonzero[v]->set_nonzero (TREE_TYPE (name));
     }
   return *(m_nonzero[v]);
 }
@@ -219,7 +217,7 @@ side_effect_manager::has_range_p (tree name, basic_block bb)
 // to include it.
 
 bool
-side_effect_manager::maybe_adjust_range (irange &r, tree name, basic_block bb)
+side_effect_manager::maybe_adjust_range (vrange &r, tree name, basic_block bb)
 {
   if (!has_range_p (name, bb))
     return false;
@@ -232,7 +230,7 @@ side_effect_manager::maybe_adjust_range (irange &r, tree name, basic_block bb)
 // Add range R as a side effect for NAME in block BB.
 
 void
-side_effect_manager::add_range (tree name, basic_block bb, const irange &r)
+side_effect_manager::add_range (tree name, basic_block bb, const vrange &r)
 {
   if (bb->index >= (int)m_on_exit.length ())
     m_on_exit.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1);
@@ -254,7 +252,7 @@ side_effect_manager::add_range (tree name, basic_block bb, const irange &r)
   exit_range *ptr = m_on_exit[bb->index].find_ptr (name);
   if (ptr)
     {
-      int_range_max cur = r;
+      tmp_range cur (r);
       // If no new info is added, just return.
       if (!cur.intersect (*(ptr->range)))
 	return;
@@ -263,7 +261,7 @@ side_effect_manager::add_range (tree name, basic_block bb, const irange &r)
       else
 	{
 	  vrange &v = cur;
-	  ptr->range = static_cast <irange *> (m_range_allocator.clone (v));
+	  ptr->range = m_range_allocator.clone (v);
 	}
       return;
     }
diff --git a/gcc/gimple-range-side-effect.h b/gcc/gimple-range-side-effect.h
index d76d6eb34f2..a7625646ed1 100644
--- a/gcc/gimple-range-side-effect.h
+++ b/gcc/gimple-range-side-effect.h
@@ -33,15 +33,15 @@ public:
   inline unsigned num () const { return num_args; }
   inline tree name (unsigned index) const
     { gcc_checking_assert (index < num_args); return m_names[index]; }
-  inline const irange& range (unsigned index) const
+  inline const vrange& range (unsigned index) const
     { gcc_checking_assert (index < num_args); return m_ranges[index]; }
-  void add_range (tree name, irange &range);
+  void add_range (tree name, vrange &range);
   void add_nonzero (tree name);
 private:
   unsigned num_args;
   static const int size_limit = 10;
   tree m_names[size_limit];
-  int_range<3> m_ranges[size_limit];
+  tmp_range m_ranges[size_limit];
   inline void bump_index () { if (num_args < size_limit - 1) num_args++; }
 };
 
@@ -56,10 +56,10 @@ class side_effect_manager
 public:
   side_effect_manager (bool do_search);
   ~side_effect_manager ();
-  void add_range (tree name, basic_block bb, const irange &r);
+  void add_range (tree name, basic_block bb, const vrange &r);
   void add_nonzero (tree name, basic_block bb);
   bool has_range_p (tree name, basic_block bb);
-  bool maybe_adjust_range (irange &r, tree name, basic_block bb);
+  bool maybe_adjust_range (vrange &r, tree name, basic_block bb);
 private:
   class exit_range_head
   {
@@ -71,8 +71,8 @@ private:
   };
   void register_all_uses (tree name);
   vec <exit_range_head> m_on_exit;
-  const irange &get_nonzero (tree name);
-  vec <irange *> m_nonzero;
+  const vrange &get_nonzero (tree name);
+  vec <vrange *> m_nonzero;
   bitmap m_seen;
   bitmap_obstack m_bitmaps;
   struct obstack m_list_obstack;
diff --git a/gcc/gimple-range-tests.cc b/gcc/gimple-range-tests.cc
index 572acd33d7f..84ecc486889 100644
--- a/gcc/gimple-range-tests.cc
+++ b/gcc/gimple-range-tests.cc
@@ -42,8 +42,9 @@ public:
     ASSERT_TRUE (r == expect);
   }
 
-  virtual bool range_of_expr (irange &r, tree expr, gimple * = NULL) override
+  virtual bool range_of_expr (vrange &v, tree expr, gimple * = NULL) override
   {
+    irange &r = as_a <irange> (v);
     if (expr == op0)
       {
 	r.set (build_int_cst (type, 5), build_int_cst (type, 10));
diff --git a/gcc/gimple-range-trace.cc b/gcc/gimple-range-trace.cc
index 39971093e6d..37cf37ca885 100644
--- a/gcc/gimple-range-trace.cc
+++ b/gcc/gimple-range-trace.cc
@@ -102,7 +102,7 @@ range_tracer::print (unsigned counter, const char *str)
 
 void
 range_tracer::trailer (unsigned counter, const char *caller, bool result,
-		      tree name, const irange &r)
+		      tree name, const vrange &r)
 {
   gcc_checking_assert (tracing && counter != 0);
 
@@ -141,7 +141,6 @@ debug_seed_ranger (gimple_ranger &ranger)
     }
 
   basic_block bb;
-  int_range_max r;
   gimple_stmt_iterator gsi;
   FOR_EACH_BB_FN (bb, cfun)
     for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
@@ -151,7 +150,11 @@ debug_seed_ranger (gimple_ranger &ranger)
 	if (is_gimple_debug (stmt))
 	  continue;
 
-	ranger.range_of_stmt (r, stmt);
+	if (tree type = gimple_range_type (stmt))
+	  {
+	    tmp_range r (type);
+	    ranger.range_of_stmt (r, stmt);
+	  }
       }
 }
 
diff --git a/gcc/gimple-range-trace.h b/gcc/gimple-range-trace.h
index 302afda3104..3f92e51803b 100644
--- a/gcc/gimple-range-trace.h
+++ b/gcc/gimple-range-trace.h
@@ -32,7 +32,7 @@ public:
   range_tracer (const char *name = "");
   unsigned header (const char *str);
   void trailer (unsigned counter, const char *caller, bool result, tree name,
-		const irange &r);
+		const vrange &r);
   void print (unsigned counter, const char *str);
   inline void enable_trace () { tracing = true; }
   inline void disable_trace () { tracing = false; }
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 32d57c9e3db..1118feb41a5 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -71,7 +71,7 @@ gimple_ranger::~gimple_ranger ()
 }
 
 bool
-gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt)
+gimple_ranger::range_of_expr (vrange &r, tree expr, gimple *stmt)
 {
   unsigned idx;
   if (!gimple_range_ssa_p (expr))
@@ -93,7 +93,7 @@ gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt)
   // If there is no statement, just get the global value.
   if (!stmt)
     {
-      int_range_max tmp;
+      tmp_range tmp (TREE_TYPE (expr));
       m_cache.get_global_range (r, expr);
       // Pick up implied context information from the on-entry cache
       // if current_bb is set.  Do not attempt any new calculations.
@@ -137,9 +137,9 @@ gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt)
 // Return the range of NAME on entry to block BB in R.
 
 void
-gimple_ranger::range_on_entry (irange &r, basic_block bb, tree name)
+gimple_ranger::range_on_entry (vrange &r, basic_block bb, tree name)
 {
-  int_range_max entry_range;
+  tmp_range entry_range (TREE_TYPE (name));
   gcc_checking_assert (gimple_range_ssa_p (name));
 
   unsigned idx;
@@ -164,7 +164,7 @@ gimple_ranger::range_on_entry (irange &r, basic_block bb, tree name)
 // Return false if no range can be calculated.
 
 void
-gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name)
+gimple_ranger::range_on_exit (vrange &r, basic_block bb, tree name)
 {
   // on-exit from the exit block?
   gcc_checking_assert (bb != EXIT_BLOCK_PTR_FOR_FN (cfun));
@@ -198,10 +198,10 @@ gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name)
 // Calculate a range for NAME on edge E and return it in R.
 
 bool
-gimple_ranger::range_on_edge (irange &r, edge e, tree name)
+gimple_ranger::range_on_edge (vrange &r, edge e, tree name)
 {
-  int_range_max edge_range;
-  gcc_checking_assert (irange::supports_type_p (TREE_TYPE (name)));
+  tmp_range edge_range (TREE_TYPE (name));
+  gcc_checking_assert (vrange::supports_type_p (TREE_TYPE (name)));
 
   // Do not process values along abnormal edges.
   if (e->flags & EDGE_ABNORMAL)
@@ -249,7 +249,7 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name)
 // fold_range wrapper for range_of_stmt to use as an internal client.
 
 bool
-gimple_ranger::fold_range_internal (irange &r, gimple *s, tree name)
+gimple_ranger::fold_range_internal (vrange &r, gimple *s, tree name)
 {
   fold_using_range f;
   fur_depend src (s, &(gori ()), this);
@@ -263,7 +263,7 @@ gimple_ranger::fold_range_internal (irange &r, gimple *s, tree name)
 // avoided.  If a range cannot be calculated, return false and UNDEFINED.
 
 bool
-gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name)
+gimple_ranger::range_of_stmt (vrange &r, gimple *s, tree name)
 {
   bool res;
   r.set_undefined ();
@@ -313,7 +313,7 @@ gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name)
 	prefill_stmt_dependencies (name);
 
       // Calculate a new value.
-      int_range_max tmp;
+      tmp_range tmp (TREE_TYPE (name));
       fold_range_internal (tmp, s, name);
 
       // Combine the new value with the old value.  This is required because
@@ -334,7 +334,7 @@ gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name)
 // stack if so.  R is a scratch range.
 
 inline void
-gimple_ranger::prefill_name (irange &r, tree name)
+gimple_ranger::prefill_name (tmp_range &r, tree name)
 {
   if (!gimple_range_ssa_p (name))
     return;
@@ -343,6 +343,7 @@ gimple_ranger::prefill_name (irange &r, tree name)
     return;
 
   bool current;
+  r.init (TREE_TYPE (name));
   // If this op has not been processed yet, then push it on the stack
   if (!m_cache.get_global_range (r, name, current))
     m_stmt_list.safe_push (name);
@@ -357,7 +358,7 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
   if (SSA_NAME_IS_DEFAULT_DEF (ssa))
     return;
 
-  int_range_max r;
+  tmp_range r;
   unsigned idx;
   gimple *stmt = SSA_NAME_DEF_STMT (ssa);
   gcc_checking_assert (stmt && gimple_bb (stmt));
@@ -388,6 +389,7 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
 	    {
 	      // Fold and save the value for NAME.
 	      stmt = SSA_NAME_DEF_STMT (name);
+	      r.init (TREE_TYPE (name));
 	      fold_range_internal (r, stmt, name);
 	      // Make sure we don't lose any current global info.
 	      int_range_max tmp;
@@ -488,10 +490,11 @@ gimple_ranger::export_global_ranges ()
   bool print_header = true;
   for (unsigned x = 1; x < num_ssa_names; x++)
     {
-      int_range_max r;
+      tmp_range r;
       tree name = ssa_name (x);
       if (name && !SSA_NAME_IN_FREE_LIST (name)
 	  && gimple_range_ssa_p (name)
+	  && r.init (TREE_TYPE (name))
 	  && m_cache.get_global_range (r, name)
 	  && !r.varying_p())
 	{
@@ -508,13 +511,17 @@ gimple_ranger::export_global_ranges ()
 	      print_header = false;
 	    }
 
-	  value_range vr = r;
+	  if (!irange::supports_type_p (TREE_TYPE (name)))
+	    continue;
+
+	  vrange &v = r;
+	  value_range vr = as_a <irange> (v);
 	  print_generic_expr (dump_file, name , TDF_SLIM);
 	  fprintf (dump_file, "  : ");
 	  vr.dump (dump_file);
 	  fprintf (dump_file, "\n");
 	  int_range_max same = vr;
-	  if (same != r)
+	  if (same != as_a <irange> (v))
 	    {
 	      fprintf (dump_file, "         irange : ");
 	      r.dump (dump_file);
@@ -532,7 +539,7 @@ gimple_ranger::dump_bb (FILE *f, basic_block bb)
   unsigned x;
   edge_iterator ei;
   edge e;
-  int_range_max range, tmp_range;
+  tmp_range range, tmp_range;
   fprintf (f, "\n=========== BB %d ============\n", bb->index);
   m_cache.dump_bb (f, bb);
 
@@ -543,6 +550,7 @@ gimple_ranger::dump_bb (FILE *f, basic_block bb)
     {
       tree name = ssa_name (x);
       if (gimple_range_ssa_p (name) && SSA_NAME_DEF_STMT (name) &&
+	  range.init (TREE_TYPE (name)) &&
 	  gimple_bb (SSA_NAME_DEF_STMT (name)) == bb &&
 	  m_cache.get_global_range (range, name))
 	{
@@ -564,9 +572,11 @@ gimple_ranger::dump_bb (FILE *f, basic_block bb)
 	{
 	  tree name = gimple_range_ssa_p (ssa_name (x));
 	  if (name && gori ().has_edge_range_p (name, e)
+	      && range.init (TREE_TYPE (name))
 	      && m_cache.range_on_edge (range, e, name))
 	    {
 	      gimple *s = SSA_NAME_DEF_STMT (name);
+	      tmp_range.init (TREE_TYPE (name));
 	      // Only print the range if this is the def block, or
 	      // the on entry cache for either end of the edge is
 	      // set.
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index 13d4c77883e..ca5a33e65c6 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -48,11 +48,11 @@ class gimple_ranger : public range_query
 public:
   gimple_ranger (bool use_imm_uses = true);
   ~gimple_ranger ();
-  virtual bool range_of_stmt (irange &r, gimple *, tree name = NULL) override;
-  virtual bool range_of_expr (irange &r, tree name, gimple * = NULL) override;
-  virtual bool range_on_edge (irange &r, edge e, tree name) override;
-  void range_on_entry (irange &r, basic_block bb, tree name);
-  void range_on_exit (irange &r, basic_block bb, tree name);
+  virtual bool range_of_stmt (vrange &r, gimple *, tree name = NULL) override;
+  virtual bool range_of_expr (vrange &r, tree name, gimple * = NULL) override;
+  virtual bool range_on_edge (vrange &r, edge e, tree name) override;
+  void range_on_entry (vrange &r, basic_block bb, tree name);
+  void range_on_exit (vrange &r, basic_block bb, tree name);
   void export_global_ranges ();
   inline gori_compute &gori ()  { return m_cache.m_gori; }
   virtual void dump (FILE *f) override;
@@ -62,8 +62,8 @@ public:
   bool fold_stmt (gimple_stmt_iterator *gsi, tree (*) (tree));
   void register_side_effects (gimple *s);
 protected:
-  bool fold_range_internal (irange &r, gimple *s, tree name);
-  void prefill_name (irange &r, tree name);
+  bool fold_range_internal (vrange &r, gimple *s, tree name);
+  void prefill_name (tmp_range &r, tree name);
   void prefill_stmt_dependencies (tree ssa);
   ranger_cache m_cache;
   range_tracer tracer;
diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index 9357a4e576a..132d82a5240 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -328,11 +328,11 @@ check_nul_terminated_array (GimpleOrTree expr, tree src, tree bound)
   wide_int bndrng[2];
   if (bound)
     {
-      value_range r;
+      tmp_range r (TREE_TYPE (bound));
 
       get_global_range_query ()->range_of_expr (r, bound);
 
-      if (r.kind () != VR_RANGE)
+      if (r.undefined_p () || r.varying_p ())
 	return true;
 
       bndrng[0] = r.lower_bound ();
@@ -2790,9 +2790,8 @@ memmodel_to_uhwi (tree ord, gimple *stmt, unsigned HOST_WIDE_INT *cstval)
     {
       /* Use the range query to determine constant values in the absence
 	 of constant propagation (such as at -O0).  */
-      value_range rng;
+      tmp_range rng (TREE_TYPE (ord));
       if (!get_range_query (cfun)->range_of_expr (rng, ord, stmt)
-	  || !rng.constant_p ()
 	  || !rng.singleton_p (&ord))
 	return false;
 
diff --git a/gcc/tree-ssa-loop-niter.cc b/gcc/tree-ssa-loop-niter.cc
index afa51064953..8907e310c19 100644
--- a/gcc/tree-ssa-loop-niter.cc
+++ b/gcc/tree-ssa-loop-niter.cc
@@ -221,7 +221,7 @@ refine_value_range_using_guard (tree type, tree var,
   get_type_static_bounds (type, mint, maxt);
   mpz_init (minc1);
   mpz_init (maxc1);
-  value_range r;
+  tmp_range r (TREE_TYPE (varc1));
   /* Setup range information for varc1.  */
   if (integer_zerop (varc1))
     {
@@ -374,7 +374,7 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off,
       gphi_iterator gsi;
 
       /* Either for VAR itself...  */
-      value_range var_range;
+      tmp_range var_range (TREE_TYPE (var));
       get_range_query (cfun)->range_of_expr (var_range, var);
       rtype = var_range.kind ();
       if (!var_range.undefined_p ())
@@ -385,10 +385,10 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off,
 
       /* Or for PHI results in loop->header where VAR is used as
 	 PHI argument from the loop preheader edge.  */
+      tmp_range phi_range (TREE_TYPE (var));
       for (gsi = gsi_start_phis (loop->header); !gsi_end_p (gsi); gsi_next (&gsi))
 	{
 	  gphi *phi = gsi.phi ();
-	  value_range phi_range;
 	  if (PHI_ARG_DEF_FROM_EDGE (phi, e) == var
 	      && get_range_query (cfun)->range_of_expr (phi_range,
 						    gimple_phi_result (phi))
@@ -410,7 +410,7 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off,
 		     involved.  */
 		  if (wi::gt_p (minv, maxv, sgn))
 		    {
-		      value_range vr;
+		      tmp_range vr (TREE_TYPE (var));
 		      get_range_query (cfun)->range_of_expr (vr, var);
 		      rtype = vr.kind ();
 		      if (!vr.undefined_p ())
@@ -3650,7 +3650,7 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt,
   if (tree_int_cst_sign_bit (step))
     {
       wide_int max;
-      value_range base_range;
+      tmp_range base_range (TREE_TYPE (orig_base));
       if (get_range_query (cfun)->range_of_expr (base_range, orig_base)
 	  && !base_range.undefined_p ())
 	max = base_range.upper_bound ();
@@ -3672,7 +3672,7 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt,
   else
     {
       wide_int min;
-      value_range base_range;
+      tmp_range base_range (TREE_TYPE (orig_base));
       if (get_range_query (cfun)->range_of_expr (base_range, orig_base)
 	  && !base_range.undefined_p ())
 	min = base_range.lower_bound ();
@@ -3947,7 +3947,7 @@ infer_loop_bounds_from_signedness (class loop *loop, gimple *stmt)
 
   low = lower_bound_in_type (type, type);
   high = upper_bound_in_type (type, type);
-  value_range r;
+  tmp_range r (TREE_TYPE (def));
   get_range_query (cfun)->range_of_expr (r, def);
   if (r.kind () == VR_RANGE)
     {
@@ -4997,7 +4997,7 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop)
   if (!def_bb || !dominated_by_p (CDI_DOMINATORS, loop->latch, def_bb))
     return false;
 
-  value_range r;
+  tmp_range r (TREE_TYPE (var));
   get_range_query (cfun)->range_of_expr (r, var);
   if (r.kind () != VR_RANGE)
     return false;
diff --git a/gcc/tree-ssa-threadedge.cc b/gcc/tree-ssa-threadedge.cc
index 4eb65ca7cac..d5e285d5d4d 100644
--- a/gcc/tree-ssa-threadedge.cc
+++ b/gcc/tree-ssa-threadedge.cc
@@ -1409,19 +1409,19 @@ tree
 hybrid_jt_simplifier::simplify (gimple *stmt, gimple *, basic_block,
 				jt_state *state)
 {
-  int_range_max r;
-
   compute_ranges_from_state (stmt, state);
 
   if (gimple_code (stmt) == GIMPLE_COND
       || gimple_code (stmt) == GIMPLE_ASSIGN)
     {
+      tmp_range r (gimple_range_type (stmt));
       tree ret;
       if (m_query->range_of_stmt (r, stmt) && r.singleton_p (&ret))
 	return ret;
     }
   else if (gimple_code (stmt) == GIMPLE_SWITCH)
     {
+      int_range_max r;
       gswitch *switch_stmt = dyn_cast <gswitch *> (stmt);
       tree index = gimple_switch_index (switch_stmt);
       if (m_query->range_of_expr (r, index, stmt))
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 31e56eeae53..463ac179a00 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -57,13 +57,13 @@ value_query::value_of_stmt (gimple *stmt, tree name)
 // range_query default methods.
 
 bool
-range_query::range_on_edge (irange &r, edge, tree expr)
+range_query::range_on_edge (vrange &r, edge, tree expr)
 {
   return range_of_expr (r, expr);
 }
 
 bool
-range_query::range_of_stmt (irange &r, gimple *stmt, tree name)
+range_query::range_of_stmt (vrange &r, gimple *stmt, tree name)
 {
   if (!name)
     name = gimple_get_lhs (stmt);
@@ -79,11 +79,12 @@ tree
 range_query::value_of_expr (tree expr, gimple *stmt)
 {
   tree t;
-  int_range_max r;
 
-  if (!irange::supports_type_p (TREE_TYPE (expr)))
+  if (!vrange::supports_type_p (TREE_TYPE (expr)))
     return NULL_TREE;
 
+  tmp_range r (TREE_TYPE (expr));
+
   if (range_of_expr (r, expr, stmt))
     {
       // A constant used in an unreachable block oftens returns as UNDEFINED.
@@ -100,10 +101,10 @@ tree
 range_query::value_on_edge (edge e, tree expr)
 {
   tree t;
-  int_range_max r;
 
-  if (!irange::supports_type_p (TREE_TYPE (expr)))
+  if (!vrange::supports_type_p (TREE_TYPE (expr)))
     return NULL_TREE;
+  tmp_range r (TREE_TYPE (expr));
   if (range_on_edge (r, e, expr))
     {
       // A constant used in an unreachable block oftens returns as UNDEFINED.
@@ -121,15 +122,15 @@ tree
 range_query::value_of_stmt (gimple *stmt, tree name)
 {
   tree t;
-  int_range_max r;
 
   if (!name)
     name = gimple_get_lhs (stmt);
 
   gcc_checking_assert (!name || name == gimple_get_lhs (stmt));
 
-  if (!name || !irange::supports_type_p (TREE_TYPE (name)))
+  if (!name || !vrange::supports_type_p (TREE_TYPE (name)))
     return NULL_TREE;
+  tmp_range r (TREE_TYPE (name));
   if (range_of_stmt (r, stmt, name) && r.singleton_p (&t))
     return t;
   return NULL_TREE;
@@ -187,7 +188,7 @@ range_query::~range_query ()
 // representable, and UNDEFINED/false if not.
 
 bool
-range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
+range_query::get_tree_range (vrange &r, tree expr, gimple *stmt)
 {
   tree type;
   if (TYPE_P (expr))
@@ -195,7 +196,7 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
   else
     type = TREE_TYPE (expr);
 
-  if (!irange::supports_type_p (type))
+  if (!vrange::supports_type_p (type))
     {
       r.set_undefined ();
       return false;
@@ -214,7 +215,7 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
       return true;
 
     case SSA_NAME:
-      r = gimple_range_global (expr);
+      gimple_range_global (r, expr);
       return true;
 
     case ADDR_EXPR:
@@ -223,7 +224,7 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
 	bool ov;
 	if (tree_single_nonzero_warnv_p (expr, &ov))
 	  {
-	    r = range_nonzero (type);
+	    r.set_nonzero (type);
 	    return true;
 	  }
 	break;
@@ -237,7 +238,8 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
       range_op_handler op (TREE_CODE (expr), type);
       if (op)
 	{
-	  int_range_max r0, r1;
+	  tmp_range r0 (TREE_TYPE (TREE_OPERAND (expr, 0)));
+	  tmp_range r1 (TREE_TYPE (TREE_OPERAND (expr, 1)));
 	  range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
 	  range_of_expr (r1, TREE_OPERAND (expr, 1), stmt);
 	  op.fold_range (r, type, r0, r1);
@@ -250,11 +252,13 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
     {
       range_op_handler op (TREE_CODE (expr), type);
       tree op0_type = TREE_TYPE (TREE_OPERAND (expr, 0));
-      if (op && irange::supports_type_p (op0_type))
+      if (op && vrange::supports_type_p (op0_type))
 	{
-	  int_range_max r0;
+	  tmp_range r0 (TREE_TYPE (TREE_OPERAND (expr, 0)));
+	  tmp_range r1 (type);
+	  r1.set_varying (type);
 	  range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
-	  op.fold_range (r, type, r0, int_range<1> (type));
+	  op.fold_range (r, type, r0, r1);
 	}
       else
 	r.set_varying (type);
@@ -311,7 +315,7 @@ get_ssa_name_ptr_info_nonnull (const_tree name)
 // updated.
 
 bool
-update_global_range (irange &r, tree name)
+update_global_range (vrange &r, tree name)
 {
   tree type = TREE_TYPE (name);
 
@@ -330,8 +334,7 @@ update_global_range (irange &r, tree name)
       if (r.undefined_p ())
 	return false;
 
-      value_range vr = r;
-      set_range_info (name, vr);
+      set_range_info (name, as_a <irange> (r));
       return true;
     }
   else if (POINTER_TYPE_P (type))
@@ -349,7 +352,7 @@ update_global_range (irange &r, tree name)
 // return VARYING.
 
 static void
-get_range_global (irange &r, tree name)
+get_range_global (vrange &r, tree name)
 {
   tree type = TREE_TYPE (name);
 
@@ -369,7 +372,7 @@ get_range_global (irange &r, tree name)
 	    r.set_nonzero (type);
 	  else if (INTEGRAL_TYPE_P (type))
 	    {
-	      get_ssa_name_range_info (r, name);
+	      get_ssa_name_range_info (as_a <irange> (r), name);
 	      if (r.undefined_p ())
 		r.set_varying (type);
 	    }
@@ -384,7 +387,8 @@ get_range_global (irange &r, tree name)
    }
   else if (!POINTER_TYPE_P (type) && SSA_NAME_RANGE_INFO (name))
     {
-      get_ssa_name_range_info (r, name);
+      gcc_checking_assert (irange::supports_type_p (TREE_TYPE (name)));
+      get_ssa_name_range_info (as_a <irange> (r), name);
       if (r.undefined_p ())
 	r.set_varying (type);
     }
@@ -414,21 +418,19 @@ get_range_global (irange &r, tree name)
 // See discussion here:
 // https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571709.html
 
-value_range
-gimple_range_global (tree name)
+void
+gimple_range_global (vrange &r, tree name)
 {
   tree type = TREE_TYPE (name);
-  gcc_checking_assert (TREE_CODE (name) == SSA_NAME
-		       && irange::supports_type_p (type));
+  gcc_checking_assert (TREE_CODE (name) == SSA_NAME);
 
   if (SSA_NAME_IS_DEFAULT_DEF (name) || (cfun && cfun->after_inlining)
       || is_a<gphi *> (SSA_NAME_DEF_STMT (name)))
     {
-      value_range vr;
-      get_range_global (vr, name);
-      return vr;
+      get_range_global (r, name);
+      return;
     }
-  return value_range (type);
+  r.set_varying (type);
 }
 
 // ----------------------------------------------
@@ -437,7 +439,7 @@ gimple_range_global (tree name)
 global_range_query global_ranges;
 
 bool
-global_range_query::range_of_expr (irange &r, tree expr, gimple *stmt)
+global_range_query::range_of_expr (vrange &r, tree expr, gimple *stmt)
 {
   tree type = TREE_TYPE (expr);
 
@@ -456,15 +458,16 @@ global_range_query::range_of_expr (irange &r, tree expr, gimple *stmt)
 relation_kind
 range_query::query_relation (gimple *s, tree ssa1, tree ssa2, bool get_range)
 {
-  int_range_max tmp;
   if (!m_oracle || TREE_CODE (ssa1) != SSA_NAME || TREE_CODE (ssa2) != SSA_NAME)
     return VREL_VARYING;
 
   // Ensure ssa1 and ssa2 have both been evaluated.
   if (get_range)
     {
-      range_of_expr (tmp, ssa1, s);
-      range_of_expr (tmp, ssa2, s);
+      tmp_range tmp1 (TREE_TYPE (ssa1));
+      tmp_range tmp2 (TREE_TYPE (ssa2));
+      range_of_expr (tmp1, ssa1, s);
+      range_of_expr (tmp2, ssa2, s);
     }
   return m_oracle->query_relation (gimple_bb (s), ssa1, ssa2);
 }
@@ -477,7 +480,6 @@ relation_kind
 range_query::query_relation (edge e, tree ssa1, tree ssa2, bool get_range)
 {
   basic_block bb;
-  int_range_max tmp;
   if (!m_oracle || TREE_CODE (ssa1) != SSA_NAME || TREE_CODE (ssa2) != SSA_NAME)
     return VREL_VARYING;
 
@@ -492,6 +494,7 @@ range_query::query_relation (edge e, tree ssa1, tree ssa2, bool get_range)
   // Ensure ssa1 and ssa2 have both been evaluated.
   if (get_range)
     {
+      tmp_range tmp (TREE_TYPE (ssa1));
       range_on_edge (tmp, e, ssa1);
       range_on_edge (tmp, e, ssa2);
     }
diff --git a/gcc/value-query.h b/gcc/value-query.h
index cf1a1d74de3..280e47e3f6b 100644
--- a/gcc/value-query.h
+++ b/gcc/value-query.h
@@ -89,9 +89,9 @@ public:
   //
   // Note that range_of_expr must always return TRUE unless ranges are
   // unsupported for EXPR's type (supports_type_p is false).
-  virtual bool range_of_expr (irange &r, tree expr, gimple * = NULL) = 0;
-  virtual bool range_on_edge (irange &r, edge, tree expr);
-  virtual bool range_of_stmt (irange &r, gimple *, tree name = NULL);
+  virtual bool range_of_expr (vrange &r, tree expr, gimple * = NULL) = 0;
+  virtual bool range_on_edge (vrange &r, edge, tree expr);
+  virtual bool range_of_stmt (vrange &r, gimple *, tree name = NULL);
 
   // Query if there is any relation between SSA1 and SSA2.
   relation_kind query_relation (gimple *s, tree ssa1, tree ssa2,
@@ -110,8 +110,8 @@ public:
 protected:
   class value_range_equiv *allocate_value_range_equiv ();
   void free_value_range_equiv (class value_range_equiv *);
-  bool get_tree_range (irange &r, tree expr, gimple *stmt);
-  bool get_arith_expr_range (irange &r, tree expr, gimple *stmt);
+  bool get_tree_range (vrange &v, tree expr, gimple *stmt);
+  bool get_arith_expr_range (vrange &r, tree expr, gimple *stmt);
   relation_oracle *m_oracle;
 
 private:
@@ -123,7 +123,7 @@ private:
 class global_range_query : public range_query
 {
 public:
-  bool range_of_expr (irange &r, tree expr, gimple * = NULL) override;
+  bool range_of_expr (vrange &r, tree expr, gimple * = NULL) override;
 };
 
 extern global_range_query global_ranges;
@@ -143,7 +143,7 @@ get_range_query (const struct function *fun)
   return fun->x_range_query ? fun->x_range_query : &global_ranges;
 }
 
-extern value_range gimple_range_global (tree name);
-extern bool update_global_range (irange &r, tree name);
+extern void gimple_range_global (vrange &v, tree name);
+extern bool update_global_range (vrange &v, tree name);
 
 #endif // GCC_QUERY_H
diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc
index 6f8583c8d01..9b681a46905 100644
--- a/gcc/vr-values.cc
+++ b/gcc/vr-values.cc
@@ -177,7 +177,7 @@ vr_values::get_value_range (const_tree var,
 }
 
 bool
-vr_values::range_of_expr (irange &r, tree expr, gimple *stmt)
+vr_values::range_of_expr (vrange &r, tree expr, gimple *stmt)
 {
   if (!gimple_range_ssa_p (expr))
     return get_tree_range (r, expr, stmt);
@@ -1640,6 +1640,8 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
 {
   tree init, step, chrec, tmin, tmax, type = TREE_TYPE (var);
   enum ev_direction dir;
+  tmp_range trange;
+  int_range<2> r;
 
   chrec = instantiate_parameters (loop, analyze_scalar_evolution (loop, var));
 
@@ -1661,11 +1663,15 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
 
   /* If INIT is an SSA with a singleton range, set INIT to said
      singleton, otherwise leave INIT alone.  */
-  if (TREE_CODE (init) == SSA_NAME)
-    query->get_value_range (init, stmt)->singleton_p (&init);
+  if (TREE_CODE (init) == SSA_NAME
+      && trange.init (TREE_TYPE (init))
+      && query->range_of_expr (trange, init, stmt))
+    trange.singleton_p (&init);
   /* Likewise for step.  */
-  if (TREE_CODE (step) == SSA_NAME)
-    query->get_value_range (step, stmt)->singleton_p (&step);
+  if (TREE_CODE (step) == SSA_NAME
+      && trange.init (TREE_TYPE (step))
+      && query->range_of_expr (trange, step, stmt))
+    trange.singleton_p (&step);
 
   /* If STEP is symbolic, we can't know whether INIT will be the
      minimum or maximum value in the range.  Also, unless INIT is
@@ -1699,7 +1705,8 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
   if (TREE_CODE (step) == INTEGER_CST
       && is_gimple_val (init)
       && (TREE_CODE (init) != SSA_NAME
-	  || query->get_value_range (init, stmt)->kind () == VR_RANGE))
+	  || (query->range_of_expr (r, init, stmt)
+	      && r.kind () == VR_RANGE)))
     {
       widest_int nit;
 
@@ -1724,7 +1731,7 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
 	    {
 	      value_range maxvr, vr0, vr1;
 	      if (TREE_CODE (init) == SSA_NAME)
-		vr0 = *(query->get_value_range (init, stmt));
+		query->range_of_expr (vr0, init, stmt);
 	      else if (is_gimple_min_invariant (init))
 		vr0.set (init);
 	      else
@@ -1737,10 +1744,10 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
 	      /* Likewise if the addition did.  */
 	      if (maxvr.kind () == VR_RANGE)
 		{
-		  value_range initvr;
+		  int_range<2> initvr;
 
 		  if (TREE_CODE (init) == SSA_NAME)
-		    initvr = *(query->get_value_range (init, stmt));
+		    query->range_of_expr (initvr, init, stmt);
 		  else if (is_gimple_min_invariant (init))
 		    initvr.set (init);
 		  else
@@ -2446,7 +2453,9 @@ simplify_using_ranges::vrp_visit_cond_stmt (gcond *stmt, edge *taken_edge_p)
 	  fprintf (dump_file, "\t");
 	  print_generic_expr (dump_file, use);
 	  fprintf (dump_file, ": ");
-	  dump_value_range (dump_file, query->get_value_range (use, stmt));
+	  tmp_range r (TREE_TYPE (use));
+	  query->range_of_expr (r, use, stmt);
+	  r.dump (dump_file);
 	}
 
       fprintf (dump_file, "\n");
diff --git a/gcc/vr-values.h b/gcc/vr-values.h
index 7a377cebd01..f018d0dfc4b 100644
--- a/gcc/vr-values.h
+++ b/gcc/vr-values.h
@@ -109,7 +109,7 @@ class vr_values : public range_query
   vr_values (void);
   ~vr_values (void);
 
-  virtual bool range_of_expr (irange &r, tree expr, gimple *stmt) override;
+  virtual bool range_of_expr (vrange &r, tree expr, gimple *stmt) override;
   virtual tree value_of_expr (tree, gimple * = NULL) override;
   virtual tree value_on_edge (edge, tree) override;
   virtual tree value_of_stmt (gimple *, tree = NULL_TREE) override;
-- 
2.36.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/5] Implement generic range temporaries.
  2022-05-30 13:27 ` [PATCH 2/5] Implement generic range temporaries Aldy Hernandez
@ 2022-05-30 14:56   ` Andrew MacLeod
  2022-05-31  6:21     ` Aldy Hernandez
  0 siblings, 1 reply; 14+ messages in thread
From: Andrew MacLeod @ 2022-05-30 14:56 UTC (permalink / raw)
  To: Aldy Hernandez, GCC patches

On 5/30/22 09:27, Aldy Hernandez wrote:
> Now that we have generic ranges, we need a way to define generic local
> temporaries on the stack for intermediate calculations in the ranger
> and elsewhere.  We need temporaries analogous to int_range_max, but
> for any of the supported types (currently just integers, but soon
> integers, pointers, and floats).
>
> The tmp_range object is such a temporary.  It is designed to be
> transparently used as a vrange.  It shares vrange's abstract API, and
> implicitly casts itself to a vrange when passed around.
>
> The ultimate name will be value_range, but we need to remove legacy
> first for that to happen.  Until then, tmp_range will do.
>
I was going to suggest maybe renaming value_range to legacy_range or 
something, and then start using value_range for ranges of any time.  
Then it occurred to me that numerous places which use value_range 
will/can continue to use value_range going forward.. ie

value_range vr;
  if (!rvals->range_of_expr (vr, name, stmt))
    return -1;

would be unaffected, to it would be pointless turmoil to rename that and 
then rename it back to value_range.

I also notice there are already a few instance of local variable named 
tmp_range, which make name renames annoying.   Perhaps we should use 
Value_Range or something like that in the interim for the multi-type 
ranges?   Then the rename is trivial down the road, formatting will be 
unaffected, and then we're kinda sorta using the end_goal name?

Andrew


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/5] Implement generic range temporaries.
  2022-05-30 14:56   ` Andrew MacLeod
@ 2022-05-31  6:21     ` Aldy Hernandez
  2022-05-31 16:40       ` Andrew MacLeod
  2022-06-01  9:01       ` Aldy Hernandez
  0 siblings, 2 replies; 14+ messages in thread
From: Aldy Hernandez @ 2022-05-31  6:21 UTC (permalink / raw)
  To: Andrew MacLeod; +Cc: GCC patches

On Mon, May 30, 2022 at 4:56 PM Andrew MacLeod <amacleod@redhat.com> wrote:
>
> On 5/30/22 09:27, Aldy Hernandez wrote:
> > Now that we have generic ranges, we need a way to define generic local
> > temporaries on the stack for intermediate calculations in the ranger
> > and elsewhere.  We need temporaries analogous to int_range_max, but
> > for any of the supported types (currently just integers, but soon
> > integers, pointers, and floats).
> >
> > The tmp_range object is such a temporary.  It is designed to be
> > transparently used as a vrange.  It shares vrange's abstract API, and
> > implicitly casts itself to a vrange when passed around.
> >
> > The ultimate name will be value_range, but we need to remove legacy
> > first for that to happen.  Until then, tmp_range will do.
> >
> I was going to suggest maybe renaming value_range to legacy_range or
> something, and then start using value_range for ranges of any time.
> Then it occurred to me that numerous places which use value_range
> will/can continue to use value_range going forward.. ie
>
> value_range vr;
>   if (!rvals->range_of_expr (vr, name, stmt))
>     return -1;
>
> would be unaffected, to it would be pointless turmoil to rename that and
> then rename it back to value_range.
>
> I also notice there are already a few instance of local variable named
> tmp_range, which make name renames annoying.   Perhaps we should use
> Value_Range or something like that in the interim for the multi-type
> ranges?   Then the rename is trivial down the road, formatting will be
> unaffected, and then we're kinda sorta using the end_goal name?

OMG that is so ugly!  Although I guess it would be temporary.

Speaking of which, how far away are we from enabling ranger in VRP1?
Because once we do that, we can start nuking legacy and cleaning all
this up.

Aldy


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/5] Implement generic range temporaries.
  2022-05-31  6:21     ` Aldy Hernandez
@ 2022-05-31 16:40       ` Andrew MacLeod
  2022-06-01  9:01       ` Aldy Hernandez
  1 sibling, 0 replies; 14+ messages in thread
From: Andrew MacLeod @ 2022-05-31 16:40 UTC (permalink / raw)
  To: Aldy Hernandez; +Cc: GCC patches

On 5/31/22 02:21, Aldy Hernandez wrote:
> On Mon, May 30, 2022 at 4:56 PM Andrew MacLeod <amacleod@redhat.com> wrote:
>> On 5/30/22 09:27, Aldy Hernandez wrote:
>>> Now that we have generic ranges, we need a way to define generic local
>>> temporaries on the stack for intermediate calculations in the ranger
>>> and elsewhere.  We need temporaries analogous to int_range_max, but
>>> for any of the supported types (currently just integers, but soon
>>> integers, pointers, and floats).
>>>
>>> The tmp_range object is such a temporary.  It is designed to be
>>> transparently used as a vrange.  It shares vrange's abstract API, and
>>> implicitly casts itself to a vrange when passed around.
>>>
>>> The ultimate name will be value_range, but we need to remove legacy
>>> first for that to happen.  Until then, tmp_range will do.
>>>
>> I was going to suggest maybe renaming value_range to legacy_range or
>> something, and then start using value_range for ranges of any time.
>> Then it occurred to me that numerous places which use value_range
>> will/can continue to use value_range going forward.. ie
>>
>> value_range vr;
>>    if (!rvals->range_of_expr (vr, name, stmt))
>>      return -1;
>>
>> would be unaffected, to it would be pointless turmoil to rename that and
>> then rename it back to value_range.
>>
>> I also notice there are already a few instance of local variable named
>> tmp_range, which make name renames annoying.   Perhaps we should use
>> Value_Range or something like that in the interim for the multi-type
>> ranges?   Then the rename is trivial down the road, formatting will be
>> unaffected, and then we're kinda sorta using the end_goal name?
> OMG that is so ugly!  Although I guess it would be temporary.
>
> Speaking of which, how far away are we from enabling ranger in VRP1?
> Because once we do that, we can start nuking legacy and cleaning all
> this up.
>
> Aldy
>
Im thinking about making the switch mid juneish...   i still have a few 
verifications to make.  We want to leave legacy for at least a while so 
we can manually switch back to it for investigation of any issues that 
come up during the transition.   so id expect early august time frame 
before trying to remove legacy....    at least legacy VRP.

thats my thoughts anyway.

Andrew

Andrew


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/5] Implement abstract vrange class.
  2022-05-30 13:27 [PATCH 1/5] Implement abstract vrange class Aldy Hernandez
                   ` (3 preceding siblings ...)
  2022-05-30 13:27 ` [PATCH 5/5] Convert ranger and clients to vrange Aldy Hernandez
@ 2022-06-01  8:57 ` Aldy Hernandez
  4 siblings, 0 replies; 14+ messages in thread
From: Aldy Hernandez @ 2022-06-01  8:57 UTC (permalink / raw)
  To: GCC patches

[-- Attachment #1: Type: text/plain, Size: 23766 bytes --]

Final patch committed.

Includes support for class unsupported_range.

Re-tested on x86-64 Linux.

On Mon, May 30, 2022 at 3:28 PM Aldy Hernandez <aldyh@redhat.com> wrote:
>
> 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-equiv.cc |   6 ++
>  gcc/value-range-equiv.h  |   3 +-
>  gcc/value-range.cc       | 168 ++++++++++++++++++++++++++++++++-
>  gcc/value-range.h        | 195 ++++++++++++++++++++++++++++++++-------
>  gcc/vr-values.cc         |   6 +-
>  5 files changed, 338 insertions(+), 40 deletions(-)
>
> diff --git a/gcc/value-range-equiv.cc b/gcc/value-range-equiv.cc
> index 77c6f5ca99d..b0ae1288a09 100644
> --- a/gcc/value-range-equiv.cc
> +++ b/gcc/value-range-equiv.cc
> @@ -50,6 +50,12 @@ value_range_equiv::set (tree min, tree max, bitmap equiv,
>      check ();
>  }
>
> +void
> +value_range_equiv::set (tree min, tree max, value_range_kind kind)
> +{
> +  set (min, max, m_equiv, kind);
> +}
> +
>  void
>  value_range_equiv::set (tree val)
>  {
> diff --git a/gcc/value-range-equiv.h b/gcc/value-range-equiv.h
> index 0aa1069cb61..743ceb2b227 100644
> --- a/gcc/value-range-equiv.h
> +++ b/gcc/value-range-equiv.h
> @@ -41,9 +41,10 @@ class GTY((user)) value_range_equiv : public value_range
>    void move (value_range_equiv *);
>
>    /* Leaves equiv bitmap alone.  */
> +  virtual void set (tree, tree, value_range_kind = VR_RANGE) override;
>    void update (tree, tree, value_range_kind = VR_RANGE);
>    /* Deep-copies equiv bitmap argument.  */
> -  void set (tree, tree, bitmap = NULL, value_range_kind = VR_RANGE);
> +  void set (tree, tree, bitmap, value_range_kind = VR_RANGE);
>    void set (tree);
>
>    bool operator== (const value_range_equiv &) const /* = delete */;
> diff --git a/gcc/value-range.cc b/gcc/value-range.cc
> index 2e7385aecc2..97ff0614f48 100644
> --- a/gcc/value-range.cc
> +++ b/gcc/value-range.cc
> @@ -30,6 +30,162 @@ along with GCC; see the file COPYING3.  If not see
>  #include "fold-const.h"
>  #include "gimple-range.h"
>
> +// Default implementation when none has been defined.
> +
> +bool
> +vrange::contains_p (tree) const
> +{
> +  return false;
> +}
> +
> +// Default implementation when none has been defined.
> +
> +bool
> +vrange::singleton_p (tree *) const
> +{
> +  return false;
> +}
> +
> +// Assignment operator for generic ranges.  Copying incompatible types
> +// is not allowed.
> +
> +vrange &
> +vrange::operator= (const vrange &src)
> +{
> +  if (is_a <irange> (src))
> +    {
> +      as_a <irange> (*this) = as_a <irange> (src);
> +      return *this;
> +    }
> +  else
> +    gcc_unreachable ();
> +}
> +
> +// Equality operator for generic ranges.
> +
> +bool
> +vrange::operator== (const vrange &src) const
> +{
> +  if (is_a <irange> (src))
> +    return as_a <irange> (*this) == as_a <irange> (src);
> +  gcc_unreachable ();
> +}
> +
> +// Return TRUE if R fits in THIS.
> +
> +bool
> +irange::fits_p (const vrange &r) const
> +{
> +  return m_max_ranges >= as_a <irange> (r).num_pairs ();
> +}
> +
> +void
> +irange::set_nonnegative (tree type)
> +{
> +  set (build_int_cst (type, 0), TYPE_MAX_VALUE (type));
> +}
> +
> +unsupported_range::unsupported_range ()
> +{
> +  m_discriminator = VR_UNKNOWN;
> +  set_undefined ();
> +}
> +
> +void
> +unsupported_range::set (tree, tree, value_range_kind)
> +{
> +  gcc_unreachable ();
> +}
> +
> +tree
> +unsupported_range::type () const
> +{
> +  gcc_unreachable ();
> +  return nullptr;
> +}
> +
> +void
> +unsupported_range::set_undefined ()
> +{
> +  m_kind = VR_UNDEFINED;
> +}
> +
> +void
> +unsupported_range::set_varying (tree)
> +{
> +  gcc_unreachable ();
> +}
> +
> +void
> +unsupported_range::dump (FILE *file) const
> +{
> +  fprintf (file, "[unsupported_range] ");
> +  if (undefined_p ())
> +    {
> +      fprintf (file, "UNDEFINED");
> +      return;
> +    }
> +  if (varying_p ())
> +    {
> +      fprintf (file, "VARYING");
> +      return;
> +    }
> +  gcc_unreachable ();
> +}
> +
> +bool
> +unsupported_range::union_ (const vrange &)
> +{
> +  gcc_unreachable ();
> +  return false;
> +}
> +
> +bool
> +unsupported_range::intersect (const vrange &)
> +{
> +  gcc_unreachable ();
> +  return false;
> +}
> +
> +bool
> +unsupported_range::zero_p () const
> +{
> +  gcc_unreachable ();
> +  return false;
> +}
> +
> +bool
> +unsupported_range::nonzero_p () const
> +{
> +  gcc_unreachable ();
> +  return false;
> +}
> +
> +void
> +unsupported_range::set_nonzero (tree)
> +{
> +  gcc_unreachable ();
> +}
> +
> +void
> +unsupported_range::set_zero (tree)
> +{
> +  gcc_unreachable ();
> +}
> +
> +void
> +unsupported_range::set_nonnegative (tree)
> +{
> +  gcc_unreachable ();
> +}
> +
> +bool
> +unsupported_range::fits_p (const vrange &) const
> +{
> +  gcc_unreachable ();
> +  return false;
> +}
> +
>  // Here we copy between any two irange's.  The ranges can be legacy or
>  // multi-ranges, and copying between any combination works correctly.
>
> @@ -291,7 +447,7 @@ irange::set (tree min, tree max, value_range_kind kind)
>      }
>    if (kind == VR_UNDEFINED)
>      {
> -      set_undefined ();
> +      irange::set_undefined ();
>        return;
>      }
>
> @@ -370,6 +526,7 @@ irange::set (tree min, tree max, value_range_kind kind)
>  void
>  irange::verify_range ()
>  {
> +  gcc_checking_assert (m_discriminator == VR_IRANGE);
>    if (m_kind == VR_UNDEFINED)
>      {
>        gcc_checking_assert (m_num_ranges == 0);
> @@ -2087,6 +2244,7 @@ dump_bound_with_infinite_markers (FILE *file, tree bound)
>  void
>  irange::dump (FILE *file) const
>  {
> +  fprintf (file, "[irange] ");
>    if (undefined_p ())
>      {
>        fprintf (file, "UNDEFINED");
> @@ -2121,27 +2279,27 @@ irange::dump (FILE *file) const
>  }
>
>  void
> -irange::debug () const
> +vrange::debug () const
>  {
>    dump (stderr);
>    fprintf (stderr, "\n");
>  }
>
>  void
> -dump_value_range (FILE *file, const irange *vr)
> +dump_value_range (FILE *file, const vrange *vr)
>  {
>    vr->dump (file);
>  }
>
>  DEBUG_FUNCTION void
> -debug (const irange *vr)
> +debug (const vrange *vr)
>  {
>    dump_value_range (stderr, vr);
>    fprintf (stderr, "\n");
>  }
>
>  DEBUG_FUNCTION void
> -debug (const irange &vr)
> +debug (const vrange &vr)
>  {
>    debug (&vr);
>  }
> diff --git a/gcc/value-range.h b/gcc/value-range.h
> index ec59d2e4f23..0061f667092 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 <typename T> friend bool is_a (vrange &);
> +public:
> +  virtual void set (tree, tree, value_range_kind = VR_RANGE) = 0;
> +  virtual tree type () const = 0;
> +  virtual void set_varying (tree type) = 0;
> +  virtual void set_undefined () = 0;
> +  virtual void dump (FILE * = stderr) const = 0;
> +  virtual bool union_ (const vrange &) = 0;
> +  virtual bool intersect (const vrange &) = 0;
> +  virtual bool singleton_p (tree *result = NULL) const;
> +  virtual bool contains_p (tree cst) const;
> +  virtual bool zero_p () const = 0;
> +  virtual bool nonzero_p () const = 0;
> +  virtual void set_nonzero (tree type) = 0;
> +  virtual void set_zero (tree type) = 0;
> +  virtual void set_nonnegative (tree type) = 0;
> +  virtual bool fits_p (const vrange &r) const = 0;
> +
> +  static bool supports_type_p (tree);
> +
> +  bool varying_p () const;
> +  bool undefined_p () const;
> +  vrange& operator= (const vrange &);
> +  bool operator== (const vrange &) const;
> +  bool operator!= (const vrange &r) const { return !(*this == r); }
> +
> +  enum value_range_kind kind () const;         // DEPRECATED
> +  void debug () const;
> +
> +protected:
> +  ENUM_BITFIELD(value_range_kind) m_kind : 8;
> +  ENUM_BITFIELD(value_range_discriminator) m_discriminator : 4;
> +};
> +
> +// An integer range without any storage.
>
> -class GTY((user)) irange
> +class GTY((user)) irange : public vrange
>  {
>    friend class irange_allocator;
>  public:
>    // In-place setters.
> -  void set (tree, tree, value_range_kind = VR_RANGE);
> -  void set_nonzero (tree);
> -  void set_zero (tree);
> -  void set_varying (tree type);
> -  void set_undefined ();
> +  virtual void set (tree, tree, value_range_kind = VR_RANGE) override;
> +  virtual void set_nonzero (tree type) override;
> +  virtual void set_zero (tree type) override;
> +  virtual void set_nonnegative (tree type) override;
> +  virtual void set_varying (tree type) override;
> +  virtual void set_undefined () override;
>
>    // Range types.
>    static bool supports_type_p (tree);
> -  tree type () const;
> +  virtual tree type () const override;
>
>    // Iteration over sub-ranges.
>    unsigned num_pairs () const;
> @@ -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<typename T>
> +struct vrange_traits
> +{
> +  // Default to something unusable.
> +  typedef void range_type;
> +};
> +
> +template<>
> +struct vrange_traits<irange>
> +{
> +  typedef irange range_type;
> +};
> +
> +template <typename T>
> +inline bool
> +is_a (vrange &v)
> +{
> +  gcc_unreachable ();
> +  return false;
> +}
> +
> +template <typename T>
> +inline bool
> +is_a (const vrange &v)
> +{
> +  // Reuse is_a <vrange> to implement the const version.
> +  const T &derived = static_cast<const T &> (v);
> +  return is_a <T> (const_cast<T &> (derived));
> +}
> +
> +template <typename T>
> +inline T &
> +as_a (vrange &v)
> +{
> +  typedef typename vrange_traits<T>::range_type range_type;
> +  gcc_checking_assert (is_a <range_type> (v));
> +  return static_cast <range_type &> (v);
> +}
> +
> +template <typename T>
> +inline const T &
> +as_a (const vrange &v)
> +{
> +  typedef typename vrange_traits<T>::range_type range_type;
> +  gcc_checking_assert (is_a <range_type> (v));
> +  return static_cast <const range_type &> (v);
> +}
> +
> +// Specializations for the different range types.
> +
> +template <>
> +inline bool
> +is_a <irange> (vrange &v)
> +{
> +  return v.m_discriminator == VR_IRANGE;
> +}
> +
>  // This is a special int_range<1> with only one pair, plus
>  // VR_ANTI_RANGE magic to describe slightly more than can be described
>  // in one pair.  It is described in the code as a "legacy range" (as
> @@ -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<N> *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 <irange> (r));
>    dump_flags = m_flags;
>    return ret;
>  }
>
>  inline bool
> -irange::intersect (const irange &r)
> +irange::intersect (const vrange &r)
>  {
>    dump_flags_t m_flags = dump_flags;
>    dump_flags &= ~TDF_DETAILS;
> -  bool ret = irange::legacy_verbose_intersect (&r);
> +  bool ret = irange::legacy_verbose_intersect (&as_a <irange> (r));
>    dump_flags = m_flags;
>    return ret;
>  }
> @@ -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
> diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc
> index 47faa4ff938..6f8583c8d01 100644
> --- a/gcc/vr-values.cc
> +++ b/gcc/vr-values.cc
> @@ -883,7 +883,7 @@ vr_values::extract_range_from_binary_expr (value_range_equiv *vr,
>               wide_int wmax = wi::to_wide (max, TYPE_PRECISION (TREE_TYPE (max)));
>               tree range_min = build_zero_cst (expr_type);
>               tree range_max = wide_int_to_tree (expr_type, wmax - 1);
> -             vr->set (range_min, range_max);
> +             vr->set (range_min, range_max, NULL);
>               return;
>             }
>       }
> @@ -1275,7 +1275,7 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
>                       /* This is the boolean return value whether compare and
>                          exchange changed anything or not.  */
>                       vr->set (build_int_cst (type, 0),
> -                              build_int_cst (type, 1));
> +                              build_int_cst (type, 1), NULL);
>                       return;
>                     }
>                   break;
> @@ -1297,7 +1297,7 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
>                         vr->set_varying (type);
>                       else
>                         vr->set (build_int_cst (type, 0),
> -                                build_int_cst (type, 1));
> +                                build_int_cst (type, 1), NULL);
>                     }
>                   else if (types_compatible_p (type, TREE_TYPE (op0))
>                            && types_compatible_p (type, TREE_TYPE (op1)))
> --
> 2.36.1
>

[-- Attachment #2: 0001-Implement-abstract-vrange-class.patch --]
[-- Type: text/x-patch, Size: 21581 bytes --]

From 4f1bce19f6d51af1dfe1118cfbec19c55d3909fc Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <aldyh@redhat.com>
Date: Mon, 14 Mar 2022 14:04:56 +0100
Subject: [PATCH] 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-equiv.cc |   6 ++
 gcc/value-range-equiv.h  |   3 +-
 gcc/value-range.cc       | 168 ++++++++++++++++++++++++++++++++-
 gcc/value-range.h        | 195 ++++++++++++++++++++++++++++++++-------
 gcc/vr-values.cc         |   6 +-
 5 files changed, 338 insertions(+), 40 deletions(-)

diff --git a/gcc/value-range-equiv.cc b/gcc/value-range-equiv.cc
index 77c6f5ca99d..b0ae1288a09 100644
--- a/gcc/value-range-equiv.cc
+++ b/gcc/value-range-equiv.cc
@@ -50,6 +50,12 @@ value_range_equiv::set (tree min, tree max, bitmap equiv,
     check ();
 }
 
+void
+value_range_equiv::set (tree min, tree max, value_range_kind kind)
+{
+  set (min, max, m_equiv, kind);
+}
+
 void
 value_range_equiv::set (tree val)
 {
diff --git a/gcc/value-range-equiv.h b/gcc/value-range-equiv.h
index 0aa1069cb61..743ceb2b227 100644
--- a/gcc/value-range-equiv.h
+++ b/gcc/value-range-equiv.h
@@ -41,9 +41,10 @@ class GTY((user)) value_range_equiv : public value_range
   void move (value_range_equiv *);
 
   /* Leaves equiv bitmap alone.  */
+  virtual void set (tree, tree, value_range_kind = VR_RANGE) override;
   void update (tree, tree, value_range_kind = VR_RANGE);
   /* Deep-copies equiv bitmap argument.  */
-  void set (tree, tree, bitmap = NULL, value_range_kind = VR_RANGE);
+  void set (tree, tree, bitmap, value_range_kind = VR_RANGE);
   void set (tree);
 
   bool operator== (const value_range_equiv &) const /* = delete */;
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 2e7385aecc2..97ff0614f48 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -30,6 +30,162 @@ along with GCC; see the file COPYING3.  If not see
 #include "fold-const.h"
 #include "gimple-range.h"
 
+// Default implementation when none has been defined.
+
+bool
+vrange::contains_p (tree) const
+{
+  return false;
+}
+
+// Default implementation when none has been defined.
+
+bool
+vrange::singleton_p (tree *) const
+{
+  return false;
+}
+
+// Assignment operator for generic ranges.  Copying incompatible types
+// is not allowed.
+
+vrange &
+vrange::operator= (const vrange &src)
+{
+  if (is_a <irange> (src))
+    {
+      as_a <irange> (*this) = as_a <irange> (src);
+      return *this;
+    }
+  else
+    gcc_unreachable ();
+}
+
+// Equality operator for generic ranges.
+
+bool
+vrange::operator== (const vrange &src) const
+{
+  if (is_a <irange> (src))
+    return as_a <irange> (*this) == as_a <irange> (src);
+  gcc_unreachable ();
+}
+
+// Return TRUE if R fits in THIS.
+
+bool
+irange::fits_p (const vrange &r) const
+{
+  return m_max_ranges >= as_a <irange> (r).num_pairs ();
+}
+
+void
+irange::set_nonnegative (tree type)
+{
+  set (build_int_cst (type, 0), TYPE_MAX_VALUE (type));
+}
+
+unsupported_range::unsupported_range ()
+{
+  m_discriminator = VR_UNKNOWN;
+  set_undefined ();
+}
+
+void
+unsupported_range::set (tree, tree, value_range_kind)
+{
+  gcc_unreachable ();
+}
+
+tree
+unsupported_range::type () const
+{
+  gcc_unreachable ();
+  return nullptr;
+}
+
+void
+unsupported_range::set_undefined ()
+{
+  m_kind = VR_UNDEFINED;
+}
+
+void
+unsupported_range::set_varying (tree)
+{
+  gcc_unreachable ();
+}
+
+void
+unsupported_range::dump (FILE *file) const
+{
+  fprintf (file, "[unsupported_range] ");
+  if (undefined_p ())
+    {
+      fprintf (file, "UNDEFINED");
+      return;
+    }
+  if (varying_p ())
+    {
+      fprintf (file, "VARYING");
+      return;
+    }
+  gcc_unreachable ();
+}
+
+bool
+unsupported_range::union_ (const vrange &)
+{
+  gcc_unreachable ();
+  return false;
+}
+
+bool
+unsupported_range::intersect (const vrange &)
+{
+  gcc_unreachable ();
+  return false;
+}
+
+bool
+unsupported_range::zero_p () const
+{
+  gcc_unreachable ();
+  return false;
+}
+
+bool
+unsupported_range::nonzero_p () const
+{
+  gcc_unreachable ();
+  return false;
+}
+
+void
+unsupported_range::set_nonzero (tree)
+{
+  gcc_unreachable ();
+}
+
+void
+unsupported_range::set_zero (tree)
+{
+  gcc_unreachable ();
+}
+
+void
+unsupported_range::set_nonnegative (tree)
+{
+  gcc_unreachable ();
+}
+
+bool
+unsupported_range::fits_p (const vrange &) const
+{
+  gcc_unreachable ();
+  return false;
+}
+
 // Here we copy between any two irange's.  The ranges can be legacy or
 // multi-ranges, and copying between any combination works correctly.
 
@@ -291,7 +447,7 @@ irange::set (tree min, tree max, value_range_kind kind)
     }
   if (kind == VR_UNDEFINED)
     {
-      set_undefined ();
+      irange::set_undefined ();
       return;
     }
 
@@ -370,6 +526,7 @@ irange::set (tree min, tree max, value_range_kind kind)
 void
 irange::verify_range ()
 {
+  gcc_checking_assert (m_discriminator == VR_IRANGE);
   if (m_kind == VR_UNDEFINED)
     {
       gcc_checking_assert (m_num_ranges == 0);
@@ -2087,6 +2244,7 @@ dump_bound_with_infinite_markers (FILE *file, tree bound)
 void
 irange::dump (FILE *file) const
 {
+  fprintf (file, "[irange] ");
   if (undefined_p ())
     {
       fprintf (file, "UNDEFINED");
@@ -2121,27 +2279,27 @@ irange::dump (FILE *file) const
 }
 
 void
-irange::debug () const
+vrange::debug () const
 {
   dump (stderr);
   fprintf (stderr, "\n");
 }
 
 void
-dump_value_range (FILE *file, const irange *vr)
+dump_value_range (FILE *file, const vrange *vr)
 {
   vr->dump (file);
 }
 
 DEBUG_FUNCTION void
-debug (const irange *vr)
+debug (const vrange *vr)
 {
   dump_value_range (stderr, vr);
   fprintf (stderr, "\n");
 }
 
 DEBUG_FUNCTION void
-debug (const irange &vr)
+debug (const vrange &vr)
 {
   debug (&vr);
 }
diff --git a/gcc/value-range.h b/gcc/value-range.h
index ec59d2e4f23..0061f667092 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 <typename T> friend bool is_a (vrange &);
+public:
+  virtual void set (tree, tree, value_range_kind = VR_RANGE) = 0;
+  virtual tree type () const = 0;
+  virtual void set_varying (tree type) = 0;
+  virtual void set_undefined () = 0;
+  virtual void dump (FILE * = stderr) const = 0;
+  virtual bool union_ (const vrange &) = 0;
+  virtual bool intersect (const vrange &) = 0;
+  virtual bool singleton_p (tree *result = NULL) const;
+  virtual bool contains_p (tree cst) const;
+  virtual bool zero_p () const = 0;
+  virtual bool nonzero_p () const = 0;
+  virtual void set_nonzero (tree type) = 0;
+  virtual void set_zero (tree type) = 0;
+  virtual void set_nonnegative (tree type) = 0;
+  virtual bool fits_p (const vrange &r) const = 0;
+
+  static bool supports_type_p (tree);
+
+  bool varying_p () const;
+  bool undefined_p () const;
+  vrange& operator= (const vrange &);
+  bool operator== (const vrange &) const;
+  bool operator!= (const vrange &r) const { return !(*this == r); }
+
+  enum value_range_kind kind () const;		// DEPRECATED
+  void debug () const;
+
+protected:
+  ENUM_BITFIELD(value_range_kind) m_kind : 8;
+  ENUM_BITFIELD(value_range_discriminator) m_discriminator : 4;
+};
+
+// An integer range without any storage.
 
-class GTY((user)) irange
+class GTY((user)) irange : public vrange
 {
   friend class irange_allocator;
 public:
   // In-place setters.
-  void set (tree, tree, value_range_kind = VR_RANGE);
-  void set_nonzero (tree);
-  void set_zero (tree);
-  void set_varying (tree type);
-  void set_undefined ();
+  virtual void set (tree, tree, value_range_kind = VR_RANGE) override;
+  virtual void set_nonzero (tree type) override;
+  virtual void set_zero (tree type) override;
+  virtual void set_nonnegative (tree type) override;
+  virtual void set_varying (tree type) override;
+  virtual void set_undefined () override;
 
   // Range types.
   static bool supports_type_p (tree);
-  tree type () const;
+  virtual tree type () const override;
 
   // Iteration over sub-ranges.
   unsigned num_pairs () const;
@@ -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<typename T>
+struct vrange_traits
+{
+  // Default to something unusable.
+  typedef void range_type;
+};
+
+template<>
+struct vrange_traits<irange>
+{
+  typedef irange range_type;
+};
+
+template <typename T>
+inline bool
+is_a (vrange &v)
+{
+  gcc_unreachable ();
+  return false;
+}
+
+template <typename T>
+inline bool
+is_a (const vrange &v)
+{
+  // Reuse is_a <vrange> to implement the const version.
+  const T &derived = static_cast<const T &> (v);
+  return is_a <T> (const_cast<T &> (derived));
+}
+
+template <typename T>
+inline T &
+as_a (vrange &v)
+{
+  typedef typename vrange_traits<T>::range_type range_type;
+  gcc_checking_assert (is_a <range_type> (v));
+  return static_cast <range_type &> (v);
+}
+
+template <typename T>
+inline const T &
+as_a (const vrange &v)
+{
+  typedef typename vrange_traits<T>::range_type range_type;
+  gcc_checking_assert (is_a <range_type> (v));
+  return static_cast <const range_type &> (v);
+}
+
+// Specializations for the different range types.
+
+template <>
+inline bool
+is_a <irange> (vrange &v)
+{
+  return v.m_discriminator == VR_IRANGE;
+}
+
 // This is a special int_range<1> with only one pair, plus
 // VR_ANTI_RANGE magic to describe slightly more than can be described
 // in one pair.  It is described in the code as a "legacy range" (as
@@ -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<N> *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 <irange> (r));
   dump_flags = m_flags;
   return ret;
 }
 
 inline bool
-irange::intersect (const irange &r)
+irange::intersect (const vrange &r)
 {
   dump_flags_t m_flags = dump_flags;
   dump_flags &= ~TDF_DETAILS;
-  bool ret = irange::legacy_verbose_intersect (&r);
+  bool ret = irange::legacy_verbose_intersect (&as_a <irange> (r));
   dump_flags = m_flags;
   return ret;
 }
@@ -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
diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc
index 47faa4ff938..6f8583c8d01 100644
--- a/gcc/vr-values.cc
+++ b/gcc/vr-values.cc
@@ -883,7 +883,7 @@ vr_values::extract_range_from_binary_expr (value_range_equiv *vr,
 	      wide_int wmax = wi::to_wide (max, TYPE_PRECISION (TREE_TYPE (max)));
 	      tree range_min = build_zero_cst (expr_type);
 	      tree range_max = wide_int_to_tree (expr_type, wmax - 1);
-	      vr->set (range_min, range_max);
+	      vr->set (range_min, range_max, NULL);
 	      return;
 	    }
      }
@@ -1275,7 +1275,7 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
 		      /* This is the boolean return value whether compare and
 			 exchange changed anything or not.  */
 		      vr->set (build_int_cst (type, 0),
-			       build_int_cst (type, 1));
+			       build_int_cst (type, 1), NULL);
 		      return;
 		    }
 		  break;
@@ -1297,7 +1297,7 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
 			vr->set_varying (type);
 		      else
 			vr->set (build_int_cst (type, 0),
-				 build_int_cst (type, 1));
+				 build_int_cst (type, 1), NULL);
 		    }
 		  else if (types_compatible_p (type, TREE_TYPE (op0))
 			   && types_compatible_p (type, TREE_TYPE (op1)))
-- 
2.36.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/5] Implement generic range temporaries.
  2022-05-31  6:21     ` Aldy Hernandez
  2022-05-31 16:40       ` Andrew MacLeod
@ 2022-06-01  9:01       ` Aldy Hernandez
  1 sibling, 0 replies; 14+ messages in thread
From: Aldy Hernandez @ 2022-06-01  9:01 UTC (permalink / raw)
  To: Andrew MacLeod; +Cc: GCC patches

[-- Attachment #1: Type: text/plain, Size: 2291 bytes --]

Final patch committed.

tmp_range has been renamed to Value_Range.

Value_Range::init() has been renamed to set_type() which is more obvious.

Default constructor for Value_Range now points the vrange to the
unsupported_range object, so we always have an object available.

Re-tested on x86-64 Linux.

On Tue, May 31, 2022 at 8:21 AM Aldy Hernandez <aldyh@redhat.com> wrote:
>
> On Mon, May 30, 2022 at 4:56 PM Andrew MacLeod <amacleod@redhat.com> wrote:
> >
> > On 5/30/22 09:27, Aldy Hernandez wrote:
> > > Now that we have generic ranges, we need a way to define generic local
> > > temporaries on the stack for intermediate calculations in the ranger
> > > and elsewhere.  We need temporaries analogous to int_range_max, but
> > > for any of the supported types (currently just integers, but soon
> > > integers, pointers, and floats).
> > >
> > > The tmp_range object is such a temporary.  It is designed to be
> > > transparently used as a vrange.  It shares vrange's abstract API, and
> > > implicitly casts itself to a vrange when passed around.
> > >
> > > The ultimate name will be value_range, but we need to remove legacy
> > > first for that to happen.  Until then, tmp_range will do.
> > >
> > I was going to suggest maybe renaming value_range to legacy_range or
> > something, and then start using value_range for ranges of any time.
> > Then it occurred to me that numerous places which use value_range
> > will/can continue to use value_range going forward.. ie
> >
> > value_range vr;
> >   if (!rvals->range_of_expr (vr, name, stmt))
> >     return -1;
> >
> > would be unaffected, to it would be pointless turmoil to rename that and
> > then rename it back to value_range.
> >
> > I also notice there are already a few instance of local variable named
> > tmp_range, which make name renames annoying.   Perhaps we should use
> > Value_Range or something like that in the interim for the multi-type
> > ranges?   Then the rename is trivial down the road, formatting will be
> > unaffected, and then we're kinda sorta using the end_goal name?
>
> OMG that is so ugly!  Although I guess it would be temporary.
>
> Speaking of which, how far away are we from enabling ranger in VRP1?
> Because once we do that, we can start nuking legacy and cleaning all
> this up.
>
> Aldy

[-- Attachment #2: 0002-Implement-generic-range-temporaries.patch --]
[-- Type: text/x-patch, Size: 9458 bytes --]

From 59c8e96dd02383baec4c15665985da3caadaaa5e Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <aldyh@redhat.com>
Date: Mon, 14 Mar 2022 13:27:36 +0100
Subject: [PATCH] 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/gimple-range-fold.h  |   2 +-
 gcc/gimple-range-path.cc |   2 +-
 gcc/value-query.cc       |   3 +-
 gcc/value-range.cc       |  38 +++++++++++
 gcc/value-range.h        | 135 ++++++++++++++++++++++++++++++++++++++-
 5 files changed, 174 insertions(+), 6 deletions(-)

diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h
index 53a5bf85dd4..20cb73dabb9 100644
--- a/gcc/gimple-range-fold.h
+++ b/gcc/gimple-range-fold.h
@@ -81,7 +81,7 @@ gimple_range_type (const gimple *s)
 	    type = TREE_TYPE (type);
 	}
     }
-  if (irange::supports_type_p (type))
+  if (type && irange::supports_type_p (type))
     return type;
   return NULL_TREE;
 }
diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc
index 459d3797da7..66f433dd1d5 100644
--- a/gcc/gimple-range-path.cc
+++ b/gcc/gimple-range-path.cc
@@ -755,7 +755,7 @@ path_range_query::range_of_stmt (irange &r, gimple *stmt, tree)
 {
   tree type = gimple_range_type (stmt);
 
-  if (!irange::supports_type_p (type))
+  if (!type || !irange::supports_type_p (type))
     return false;
 
   // If resolving unknowns, fold the statement making use of any
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 9ccd802457b..26e3858103b 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -249,7 +249,8 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
   if (UNARY_CLASS_P (expr))
     {
       range_operator *op = range_op_handler (TREE_CODE (expr), type);
-      if (op)
+      tree op0_type = TREE_TYPE (TREE_OPERAND (expr, 0));
+      if (op && irange::supports_type_p (op0_type))
 	{
 	  int_range_max r0;
 	  range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 97ff0614f48..429672737a8 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -30,6 +30,42 @@ along with GCC; see the file COPYING3.  If not see
 #include "fold-const.h"
 #include "gimple-range.h"
 
+// Convenience function only available for integers and pointers.
+
+wide_int
+Value_Range::lower_bound () const
+{
+  if (is_a <irange> (*m_vrange))
+    return as_a <irange> (*m_vrange).lower_bound ();
+  gcc_unreachable ();
+}
+
+// Convenience function only available for integers and pointers.
+
+wide_int
+Value_Range::upper_bound () const
+{
+  if (is_a <irange> (*m_vrange))
+    return as_a <irange> (*m_vrange).upper_bound ();
+  gcc_unreachable ();
+}
+
+void
+Value_Range::dump (FILE *out) const
+{
+  if (m_vrange)
+    m_vrange->dump (out);
+  else
+    fprintf (out, "NULL");
+}
+
+DEBUG_FUNCTION void
+debug (const Value_Range &r)
+{
+  r.dump (stderr);
+  fprintf (stderr, "\n");
+}
+
 // Default implementation when none has been defined.
 
 bool
@@ -186,6 +222,8 @@ unsupported_range::fits_p (const vrange &) const
   return false;
 }
 
+unsupported_range Value_Range::m_unsupported;
+
 // Here we copy between any two irange's.  The ranges can be legacy or
 // multi-ranges, and copying between any combination works correctly.
 
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 0061f667092..b7ea8c76f87 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -54,6 +54,7 @@ enum value_range_discriminator
 class vrange
 {
   template <typename T> friend bool is_a (vrange &);
+  friend class Value_Range;
 public:
   virtual void set (tree, tree, value_range_kind = VR_RANGE) = 0;
   virtual tree type () const = 0;
@@ -313,6 +314,136 @@ typedef int_range<1> value_range;
 // calculations.
 typedef int_range<255> int_range_max;
 
+// This is an "infinite" precision range object for use in temporary
+// calculations for any of the handled types.  The object can be
+// transparently used as a vrange.
+
+class Value_Range
+{
+public:
+  Value_Range ();
+  Value_Range (const vrange &r);
+  Value_Range (tree type);
+  void set_type (tree type);
+  vrange& operator= (const vrange &);
+  bool operator== (const Value_Range &r) const;
+  bool operator!= (const Value_Range &r) const;
+  operator vrange &();
+  operator const vrange &() const;
+  void dump (FILE *out = stderr) const;
+
+  // Convenience methods for vrange compatability.
+  void set (tree min, tree max, value_range_kind kind = VR_RANGE)
+    { return m_vrange->set (min, max, kind); }
+  tree type () { return m_vrange->type (); }
+  enum value_range_kind kind () { return m_vrange->kind (); }
+  bool varying_p () const { return m_vrange->varying_p (); }
+  bool undefined_p () const { return m_vrange->undefined_p (); }
+  void set_varying (tree type) { m_vrange->set_varying (type); }
+  void set_undefined () { m_vrange->set_undefined (); }
+  bool union_ (const vrange &r) { return m_vrange->union_ (r); }
+  bool intersect (const vrange &r) { return m_vrange->intersect (r); }
+  bool singleton_p (tree *result = NULL) const
+    { return m_vrange->singleton_p (result); }
+  bool zero_p () const { return m_vrange->zero_p (); }
+  wide_int lower_bound () const; // For irange/prange compatability.
+  wide_int upper_bound () const; // For irange/prange compatability.
+private:
+  void init (tree type);
+  static unsupported_range m_unsupported;
+  vrange *m_vrange;
+  int_range_max m_irange;
+  DISABLE_COPY_AND_ASSIGN (Value_Range);
+};
+
+inline
+Value_Range::Value_Range ()
+{
+  m_vrange = &m_unsupported;
+}
+
+// Copy constructor from a vrange.
+
+inline
+Value_Range::Value_Range (const vrange &r)
+{
+  *this = r;
+}
+
+// Copy constructor from a TYPE.  The range of the temporary is set to
+// UNDEFINED.
+
+inline
+Value_Range::Value_Range (tree type)
+{
+  init (type);
+}
+
+// Initialize object so it is possible to store temporaries of TYPE
+// into it.
+
+inline void
+Value_Range::init (tree type)
+{
+  gcc_checking_assert (TYPE_P (type));
+
+  if (irange::supports_type_p (type))
+    m_vrange = &m_irange;
+  else
+    m_vrange = &m_unsupported;
+}
+
+// Set the temporary to allow storing temporaries of TYPE.  The range
+// of the temporary is set to UNDEFINED.
+
+inline void
+Value_Range::set_type (tree type)
+{
+  init (type);
+  m_vrange->set_undefined ();
+}
+
+// Assignment operator for temporaries.  Copying incompatible types is
+// allowed.
+
+inline vrange &
+Value_Range::operator= (const vrange &r)
+{
+  if (is_a <irange> (r))
+    {
+      m_irange = as_a <irange> (r);
+      m_vrange = &m_irange;
+    }
+  else
+    gcc_unreachable ();
+
+  return *m_vrange;
+}
+
+inline bool
+Value_Range::operator== (const Value_Range &r) const
+{
+  return *m_vrange == *r.m_vrange;
+}
+
+inline bool
+Value_Range::operator!= (const Value_Range &r) const
+{
+  return *m_vrange != *r.m_vrange;
+}
+
+inline
+Value_Range::operator vrange &()
+{
+  return *m_vrange;
+}
+
+inline
+Value_Range::operator const vrange &() const
+{
+  return *m_vrange;
+}
+
 // Returns true for an old-school value_range as described above.
 inline bool
 irange::legacy_mode_p () const
@@ -451,9 +582,7 @@ irange::nonzero_p () const
 inline bool
 irange::supports_type_p (tree type)
 {
-  if (type && (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type)))
-    return type;
-  return false;
+  return INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type);
 }
 
 inline bool
-- 
2.36.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/5] Convert range-op.* to vrange.
  2022-05-30 13:27 ` [PATCH 3/5] Convert range-op.* to vrange Aldy Hernandez
@ 2022-06-01  9:01   ` Aldy Hernandez
  0 siblings, 0 replies; 14+ messages in thread
From: Aldy Hernandez @ 2022-06-01  9:01 UTC (permalink / raw)
  To: GCC patches

[-- Attachment #1: Type: text/plain, Size: 50132 bytes --]

Final patch committed.

Re-tested on x86-64 Linux.

On Mon, May 30, 2022 at 3:28 PM Aldy Hernandez <aldyh@redhat.com> wrote:
>
> This patch provides the infrastructure to make range-ops type agnostic.
>
> First, the range_op_handler function has been replaced with an object
> of the same name.  It's coded in such a way to minimize changes to the
> code base, and to encapsulate the dispatch code.
>
> Instead of:
>
>         range_operator *op = range_op_handler (code, type);
>         if (op)
>           op->fold_range (...);
>
> We now do:
>         range_op_handler op (code, type);
>         if (op)
>           op->fold_range (...);
>
> I've folded gimple_range_handler into the range_op_handler class,
> since it's also a query into the range operators.
>
> Instead of:
>
>         range_operator *handler = gimple_range_handler (stmt);
>
> We now do:
>
>         range_op_handler handler (stmt);
>
> This all has the added benefit of moving all the dispatch code into an
> independent class and avoid polluting range_operator (which we'll
> further split later when frange and prange come live).
>
> There's this annoying "using" keyword that's been added to each
> operator due to hiding rules in C++.  The issue is that we will have
> different virtual versions of fold_range() for each combination of
> operands.  For example:
>
>         // Traditional binary op on irange's.
>         fold_range (irange &lhs, const irange &op1, const irange &op2);
>         // For POINTER_DIFF_EXPR:
>         fold_range (irange &lhs, const prange &op1, const prange &op2);
>         // Cast from irange to prange.
>         fold_range (prange &lhs, const irange &op1, const irange &op2);
>
> Overloading virtuals when there are multiple same named methods causes
> hidden virtuals warnings from -Woverloaded-virtual, thus the using
> keyword.  An alternative would be to have different names:
> fold_range_III, fold_range_IPP, fold_range_PII, but that's uglier
> still.
>
> Tested on x86-64 & ppc64le Linux.
>
> gcc/ChangeLog:
>
>         * gimple-range-edge.cc (gimple_outgoing_range_stmt_p): Adjust for
>         vrange and convert range_op_handler function calls to use the
>         identically named object.
>         * gimple-range-fold.cc (gimple_range_operand1): Same.
>         (gimple_range_operand2): Same.
>         (fold_using_range::fold_stmt): Same.
>         (fold_using_range::range_of_range_op): Same.
>         (fold_using_range::range_of_builtin_ubsan_call): Same.
>         (fold_using_range::relation_fold_and_or): Same.
>         (fur_source::register_outgoing_edges): Same.
>         * gimple-range-fold.h (gimple_range_handler): Remove.
>         * gimple-range-gori.cc (gimple_range_calc_op1): Adjust for vrange.
>         (gimple_range_calc_op2): Same.
>         (range_def_chain::get_def_chain): Same.
>         (gori_compute::compute_operand_range): Same.
>         (gori_compute::condexpr_adjust): Same.
>         * gimple-range.cc (gimple_ranger::prefill_name): Same.
>         (gimple_ranger::prefill_stmt_dependencies): Same.
>         * range-op.cc (get_bool_state): Same.
>         (class operator_equal): Add using clause.
>         (class operator_not_equal): Same.
>         (class operator_lt): Same.
>         (class operator_le): Same.
>         (class operator_gt): Same.
>         (class operator_ge): Same.
>         (class operator_plus): Same.
>         (class operator_minus): Same.
>         (class operator_mult): Same.
>         (class operator_exact_divide): Same.
>         (class operator_lshift): Same.
>         (class operator_rshift): Same.
>         (class operator_cast): Same.
>         (class operator_logical_and): Same.
>         (class operator_bitwise_and): Same.
>         (class operator_logical_or): Same.
>         (class operator_bitwise_or): Same.
>         (class operator_bitwise_xor): Same.
>         (class operator_trunc_mod): Same.
>         (class operator_logical_not): Same.
>         (class operator_bitwise_not): Same.
>         (class operator_cst): Same.
>         (class operator_identity): Same.
>         (class operator_unknown): Same.
>         (class operator_abs): Same.
>         (class operator_negate): Same.
>         (class operator_addr_expr): Same.
>         (class pointer_or_operator): Same.
>         (operator_plus::op1_range): Adjust for vrange.
>         (operator_minus::op1_range): Same.
>         (operator_mult::op1_range): Same.
>         (operator_cast::op1_range): Same.
>         (operator_bitwise_not::fold_range): Same.
>         (operator_negate::fold_range): Same.
>         (range_op_handler): Rename to...
>         (get_handler): ...this.
>         (range_op_handler::range_op_handler): New.
>         (range_op_handler::fold_range): New.
>         (range_op_handler::op1_range): New.
>         (range_op_handler::op2_range): New.
>         (range_op_handler::lhs_op1_relation): New.
>         (range_op_handler::lhs_op2_relation): New.
>         (range_op_handler::op1_op2_relation): New.
>         (range_cast): Adjust for vrange.
>         * range-op.h (range_op_handler): Remove function.
>         (range_cast): Adjust for vrange.
>         (class range_op_handler): New.
>         (get_bool_state): Adjust for vrange.
>         (empty_range_varying): Same.
>         (relop_early_resolve): Same.
>         * tree-data-ref.cc (compute_distributive_range): Same.
>         * tree-vrp.cc (get_range_op_handler): Remove.
>         (range_fold_binary_symbolics_p): Use range_op_handler class
>         instead of get_range_op_handler.
>         (range_fold_unary_symbolics_p): Same.
>         (range_fold_binary_expr): Same.
>         (range_fold_unary_expr): Same.
>         * value-query.cc (range_query::get_tree_range): Adjust for vrange.
> ---
>  gcc/gimple-range-edge.cc |   2 +-
>  gcc/gimple-range-fold.cc |  43 ++++----
>  gcc/gimple-range-fold.h  |  15 ---
>  gcc/gimple-range-gori.cc |  41 ++++----
>  gcc/gimple-range.cc      |   6 +-
>  gcc/range-op.cc          | 215 ++++++++++++++++++++++++++++++++++-----
>  gcc/range-op.h           |  45 ++++++--
>  gcc/tree-data-ref.cc     |   8 +-
>  gcc/tree-vrp.cc          |  44 ++++----
>  gcc/value-query.cc       |   8 +-
>  10 files changed, 303 insertions(+), 124 deletions(-)
>
> diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc
> index 0bee38ba770..5bbe23ae03d 100644
> --- a/gcc/gimple-range-edge.cc
> +++ b/gcc/gimple-range-edge.cc
> @@ -42,7 +42,7 @@ gimple_outgoing_range_stmt_p (basic_block bb)
>    if (!gsi_end_p (gsi))
>      {
>        gimple *s = gsi_stmt (gsi);
> -      if (is_a<gcond *> (s) && gimple_range_handler (s))
> +      if (is_a<gcond *> (s) && range_op_handler (s))
>         return gsi_stmt (gsi);
>        gswitch *sw = dyn_cast<gswitch *> (s);
>        if (sw && irange::supports_type_p (TREE_TYPE (gimple_switch_index (sw))))
> diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
> index 0a947c16c58..c53d2863d5e 100644
> --- a/gcc/gimple-range-fold.cc
> +++ b/gcc/gimple-range-fold.cc
> @@ -482,7 +482,7 @@ gimple_range_base_of_assignment (const gimple *stmt)
>  tree
>  gimple_range_operand1 (const gimple *stmt)
>  {
> -  gcc_checking_assert (gimple_range_handler (stmt));
> +  gcc_checking_assert (range_op_handler (stmt));
>
>    switch (gimple_code (stmt))
>      {
> @@ -515,7 +515,7 @@ gimple_range_operand1 (const gimple *stmt)
>  tree
>  gimple_range_operand2 (const gimple *stmt)
>  {
> -  gcc_checking_assert (gimple_range_handler (stmt));
> +  gcc_checking_assert (range_op_handler (stmt));
>
>    switch (gimple_code (stmt))
>      {
> @@ -551,7 +551,7 @@ fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name)
>        && gimple_assign_rhs_code (s) == ADDR_EXPR)
>      return range_of_address (r, s, src);
>
> -  if (gimple_range_handler (s))
> +  if (range_op_handler (s))
>      res = range_of_range_op (r, s, src);
>    else if (is_a<gphi *>(s))
>      res = range_of_phi (r, as_a<gphi *> (s), src);
> @@ -593,7 +593,7 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
>    tree type = gimple_range_type (s);
>    if (!type)
>      return false;
> -  range_operator *handler = gimple_range_handler (s);
> +  range_op_handler handler (s);
>    gcc_checking_assert (handler);
>
>    tree lhs = gimple_get_lhs (s);
> @@ -606,13 +606,13 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
>         {
>           // Fold range, and register any dependency if available.
>           int_range<2> r2 (type);
> -         handler->fold_range (r, type, range1, r2);
> +         handler.fold_range (r, type, range1, r2);
>           if (lhs && gimple_range_ssa_p (op1))
>             {
>               if (src.gori ())
>                 src.gori ()->register_dependency (lhs, op1);
>               relation_kind rel;
> -             rel = handler->lhs_op1_relation (r, range1, range1);
> +             rel = handler.lhs_op1_relation (r, range1, range1);
>               if (rel != VREL_VARYING)
>                 src.register_relation (s, rel, lhs, op1);
>             }
> @@ -629,7 +629,7 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
>               fputc ('\n', dump_file);
>             }
>           // Fold range, and register any dependency if available.
> -         handler->fold_range (r, type, range1, range2, rel);
> +         handler.fold_range (r, type, range1, range2, rel);
>           relation_fold_and_or (r, s, src);
>           if (lhs)
>             {
> @@ -640,13 +640,13 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
>                 }
>               if (gimple_range_ssa_p (op1))
>                 {
> -                 rel = handler->lhs_op1_relation (r, range1, range2, rel);
> +                 rel = handler.lhs_op1_relation (r, range1, range2, rel);
>                   if (rel != VREL_VARYING)
>                     src.register_relation (s, rel, lhs, op1);
>                 }
>               if (gimple_range_ssa_p (op2))
>                 {
> -                 rel= handler->lhs_op2_relation (r, range1, range2, rel);
> +                 rel= handler.lhs_op2_relation (r, range1, range2, rel);
>                   if (rel != VREL_VARYING)
>                     src.register_relation (s, rel, lhs, op2);
>                 }
> @@ -921,7 +921,7 @@ fold_using_range::range_of_builtin_ubsan_call (irange &r, gcall *call,
>    gcc_checking_assert (code == PLUS_EXPR || code == MINUS_EXPR
>                        || code == MULT_EXPR);
>    tree type = gimple_range_type (call);
> -  range_operator *op = range_op_handler (code, type);
> +  range_op_handler op (code, type);
>    gcc_checking_assert (op);
>    int_range_max ir0, ir1;
>    tree arg0 = gimple_call_arg (call, 0);
> @@ -935,7 +935,7 @@ fold_using_range::range_of_builtin_ubsan_call (irange &r, gcall *call,
>    // Pretend the arithmetic is wrapping.  If there is any overflow,
>    // we'll complain, but will actually do wrapping operation.
>    flag_wrapv = 1;
> -  op->fold_range (r, type, ir0, ir1, relation);
> +  op.fold_range (r, type, ir0, ir1, relation);
>    flag_wrapv = saved_flag_wrapv;
>
>    // If for both arguments vrp_valueize returned non-NULL, this should
> @@ -1391,8 +1391,8 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
>    else if (ssa1_dep1 != ssa2_dep2 || ssa1_dep2 != ssa2_dep1)
>      return;
>
> -  range_operator *handler1 = gimple_range_handler (SSA_NAME_DEF_STMT (ssa1));
> -  range_operator *handler2 = gimple_range_handler (SSA_NAME_DEF_STMT (ssa2));
> +  range_op_handler handler1 (SSA_NAME_DEF_STMT (ssa1));
> +  range_op_handler handler2 (SSA_NAME_DEF_STMT (ssa2));
>
>    // If either handler is not present, no relation is found.
>    if (!handler1 || !handler2)
> @@ -1400,8 +1400,8 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
>
>    int_range<2> bool_one (boolean_true_node, boolean_true_node);
>
> -  relation_kind relation1 = handler1->op1_op2_relation (bool_one);
> -  relation_kind relation2 = handler2->op1_op2_relation (bool_one);
> +  relation_kind relation1 = handler1.op1_op2_relation (bool_one);
> +  relation_kind relation2 = handler2.op1_op2_relation (bool_one);
>    if (relation1 == VREL_VARYING || relation2 == VREL_VARYING)
>      return;
>
> @@ -1441,7 +1441,6 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
>    int_range_max r;
>    int_range<2> e0_range, e1_range;
>    tree name;
> -  range_operator *handler;
>    basic_block bb = gimple_bb (s);
>
>    if (e0)
> @@ -1472,17 +1471,17 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
>    tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (s));
>    if (ssa1 && ssa2)
>      {
> -      handler = gimple_range_handler (s);
> +      range_op_handler handler (s);
>        gcc_checking_assert (handler);
>        if (e0)
>         {
> -         relation_kind relation = handler->op1_op2_relation (e0_range);
> +         relation_kind relation = handler.op1_op2_relation (e0_range);
>           if (relation != VREL_VARYING)
>             register_relation (e0, relation, ssa1, ssa2);
>         }
>        if (e1)
>         {
> -         relation_kind relation = handler->op1_op2_relation (e1_range);
> +         relation_kind relation = handler.op1_op2_relation (e1_range);
>           if (relation != VREL_VARYING)
>             register_relation (e1, relation, ssa1, ssa2);
>         }
> @@ -1501,7 +1500,7 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
>        if (TREE_CODE (TREE_TYPE (name)) != BOOLEAN_TYPE)
>         continue;
>        gimple *stmt = SSA_NAME_DEF_STMT (name);
> -      handler = gimple_range_handler (stmt);
> +      range_op_handler handler (stmt);
>        if (!handler)
>         continue;
>        tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
> @@ -1511,14 +1510,14 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
>           if (e0 && gori ()->outgoing_edge_range_p (r, e0, name, *m_query)
>               && r.singleton_p ())
>             {
> -             relation_kind relation = handler->op1_op2_relation (r);
> +             relation_kind relation = handler.op1_op2_relation (r);
>               if (relation != VREL_VARYING)
>                 register_relation (e0, relation, ssa1, ssa2);
>             }
>           if (e1 && gori ()->outgoing_edge_range_p (r, e1, name, *m_query)
>               && r.singleton_p ())
>             {
> -             relation_kind relation = handler->op1_op2_relation (r);
> +             relation_kind relation = handler.op1_op2_relation (r);
>               if (relation != VREL_VARYING)
>                 register_relation (e1, relation, ssa1, ssa2);
>             }
> diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h
> index 20cb73dabb9..4b5d4b6e0b8 100644
> --- a/gcc/gimple-range-fold.h
> +++ b/gcc/gimple-range-fold.h
> @@ -41,21 +41,6 @@ bool fold_range (irange &r, gimple *s, irange &r1);
>  bool fold_range (irange &r, gimple *s, irange &r1, irange &r2);
>  bool fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector);
>
> -// Return the range_operator pointer for this statement.  This routine
> -// can also be used to gate whether a routine is range-ops enabled.
> -
> -static inline range_operator *
> -gimple_range_handler (const gimple *s)
> -{
> -  if (const gassign *ass = dyn_cast<const gassign *> (s))
> -    return range_op_handler (gimple_assign_rhs_code (ass),
> -                            TREE_TYPE (gimple_assign_lhs (ass)));
> -  if (const gcond *cond = dyn_cast<const gcond *> (s))
> -    return range_op_handler (gimple_cond_code (cond),
> -                            TREE_TYPE (gimple_cond_lhs (cond)));
> -  return NULL;
> -}
> -
>  // Return the type of range which statement S calculates.  If the type is
>  // unsupported or no type can be determined, return NULL_TREE.
>
> diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
> index 3e15eb5192d..0e0cf2128e7 100644
> --- a/gcc/gimple-range-gori.cc
> +++ b/gcc/gimple-range-gori.cc
> @@ -44,9 +44,9 @@ gimple_range_calc_op1 (irange &r, const gimple *stmt, const irange &lhs_range)
>    // Unary operations require the type of the first operand in the
>    // second range position.
>    tree type = TREE_TYPE (gimple_range_operand1 (stmt));
> -  int_range<2> type_range (type);
> -  return gimple_range_handler (stmt)->op1_range (r, type, lhs_range,
> -                                                type_range);
> +  tmp_range type_range (type);
> +  type_range.set_varying (type);
> +  return range_op_handler (stmt).op1_range (r, type, lhs_range, type_range);
>  }
>
>  // Calculate what we can determine of the range of this statement's
> @@ -72,12 +72,12 @@ gimple_range_calc_op1 (irange &r, const gimple *stmt,
>        // This is sometimes invoked on single operand stmts.
>        if (gimple_num_ops (stmt) < 3)
>         return false;
> -      int_range<2> trange (TREE_TYPE (gimple_range_operand2 (stmt)));
> -      return gimple_range_handler (stmt)->op1_range (r, type, lhs_range,
> -                                                    trange);
> +      tree op2_type = TREE_TYPE (gimple_range_operand2 (stmt));
> +      tmp_range trange (op2_type);
> +      trange.set_varying (op2_type);
> +      return range_op_handler (stmt).op1_range (r, type, lhs_range, trange);
>      }
> -  return gimple_range_handler (stmt)->op1_range (r, type, lhs_range,
> -                                                op2_range);
> +  return range_op_handler (stmt).op1_range (r, type, lhs_range, op2_range);
>  }
>
>  // Calculate what we can determine of the range of this statement's
> @@ -97,12 +97,13 @@ gimple_range_calc_op2 (irange &r, const gimple *stmt,
>    // If op1 is undefined, solve as if it is varying.
>    if (op1_range.undefined_p ())
>      {
> -      int_range<2> trange (TREE_TYPE (gimple_range_operand1 (stmt)));
> -      return gimple_range_handler (stmt)->op2_range (r, type, lhs_range,
> -                                                    trange);
> +      tree op1_type = TREE_TYPE (gimple_range_operand1 (stmt));
> +      tmp_range trange (op1_type);
> +      trange.set_varying (op1_type);
> +      return range_op_handler (stmt).op2_range (r, type, lhs_range, trange);
>      }
> -  return gimple_range_handler (stmt)->op2_range (r, type, lhs_range,
> -                                                op1_range);
> +  return range_op_handler (stmt).op2_range (r, type, lhs_range,
> +                                           op1_range);
>  }
>
>  // Return TRUE if GS is a logical && or || expression.
> @@ -346,7 +347,7 @@ range_def_chain::get_def_chain (tree name)
>      }
>
>    gimple *stmt = SSA_NAME_DEF_STMT (name);
> -  if (gimple_range_handler (stmt))
> +  if (range_op_handler (stmt))
>      {
>        ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
>        ssa2 = gimple_range_ssa_p (gimple_range_operand2 (stmt));
> @@ -707,7 +708,7 @@ gori_compute::compute_operand_range (irange &r, gimple *stmt,
>    if (is_a<gswitch *> (stmt))
>      return compute_operand_range_switch (r, as_a<gswitch *> (stmt), lhs, name,
>                                          src);
> -  if (!gimple_range_handler (stmt))
> +  if (!range_op_handler (stmt))
>      return false;
>
>    tree op1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
> @@ -1328,7 +1329,7 @@ gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond,
>    tree type = TREE_TYPE (gimple_assign_rhs1 (cond_def));
>    if (!range_compatible_p (type, TREE_TYPE (gimple_assign_rhs2 (cond_def))))
>      return false;
> -  range_operator *hand = range_op_handler (gimple_assign_rhs_code (cond_def), type);
> +  range_op_handler hand (gimple_assign_rhs_code (cond_def), type);
>    if (!hand)
>      return false;
>
> @@ -1351,18 +1352,18 @@ gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond,
>    // the op1 or op2 routines based on its location.
>    if (c1)
>      {
> -      if (!hand->op1_range (cond_false, type, m_bool_zero, cr))
> +      if (!hand.op1_range (cond_false, type, m_bool_zero, cr))
>         return false;
> -      if (!hand->op1_range (cond_true, type, m_bool_one, cr))
> +      if (!hand.op1_range (cond_true, type, m_bool_one, cr))
>         return false;
>        cond_false.intersect (cl);
>        cond_true.intersect (cl);
>      }
>    else
>      {
> -      if (!hand->op2_range (cond_false, type, m_bool_zero, cl))
> +      if (!hand.op2_range (cond_false, type, m_bool_zero, cl))
>         return false;
> -      if (!hand->op2_range (cond_true, type, m_bool_one, cl))
> +      if (!hand.op2_range (cond_true, type, m_bool_one, cl))
>         return false;
>        cond_false.intersect (cr);
>        cond_true.intersect (cr);
> diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
> index f5e9e77bc71..32d57c9e3db 100644
> --- a/gcc/gimple-range.cc
> +++ b/gcc/gimple-range.cc
> @@ -339,7 +339,7 @@ gimple_ranger::prefill_name (irange &r, tree name)
>    if (!gimple_range_ssa_p (name))
>      return;
>    gimple *stmt = SSA_NAME_DEF_STMT (name);
> -  if (!gimple_range_handler (stmt) && !is_a<gphi *> (stmt))
> +  if (!range_op_handler (stmt) && !is_a<gphi *> (stmt))
>      return;
>
>    bool current;
> @@ -363,7 +363,7 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
>    gcc_checking_assert (stmt && gimple_bb (stmt));
>
>    // Only pre-process range-ops and phis.
> -  if (!gimple_range_handler (stmt) && !is_a<gphi *> (stmt))
> +  if (!range_op_handler (stmt) && !is_a<gphi *> (stmt))
>      return;
>
>    // Mark where on the stack we are starting.
> @@ -419,7 +419,7 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
>         }
>        else
>         {
> -         gcc_checking_assert (gimple_range_handler (stmt));
> +         gcc_checking_assert (range_op_handler (stmt));
>           tree op = gimple_range_operand2 (stmt);
>           if (op)
>             prefill_name (r, op);
> diff --git a/gcc/range-op.cc b/gcc/range-op.cc
> index c88da8caa6c..6f6d2da573a 100644
> --- a/gcc/range-op.cc
> +++ b/gcc/range-op.cc
> @@ -420,7 +420,7 @@ create_possibly_reversed_range (irange &r, tree type,
>  // return the equivalent range for TYPE in R; if FALSE/TRUE, do nothing.
>
>  bool_range_state
> -get_bool_state (irange &r, const irange &lhs, tree val_type)
> +get_bool_state (vrange &r, const vrange &lhs, tree val_type)
>  {
>    // If there is no result, then this is unexecutable.
>    if (lhs.undefined_p ())
> @@ -446,6 +446,9 @@ get_bool_state (irange &r, const irange &lhs, tree val_type)
>
>  class operator_equal : public range_operator
>  {
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
> +  using range_operator::op2_range;
>  public:
>    virtual bool fold_range (irange &r, tree type,
>                            const irange &op1,
> @@ -562,6 +565,9 @@ operator_equal::op2_range (irange &r, tree type,
>
>  class operator_not_equal : public range_operator
>  {
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
> +  using range_operator::op2_range;
>  public:
>    virtual bool fold_range (irange &r, tree type,
>                            const irange &op1,
> @@ -738,6 +744,9 @@ build_ge (irange &r, tree type, const wide_int &val)
>
>  class operator_lt :  public range_operator
>  {
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
> +  using range_operator::op2_range;
>  public:
>    virtual bool fold_range (irange &r, tree type,
>                            const irange &op1,
> @@ -846,6 +855,9 @@ operator_lt::op2_range (irange &r, tree type,
>
>  class operator_le :  public range_operator
>  {
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
> +  using range_operator::op2_range;
>  public:
>    virtual bool fold_range (irange &r, tree type,
>                            const irange &op1,
> @@ -954,6 +966,9 @@ operator_le::op2_range (irange &r, tree type,
>
>  class operator_gt :  public range_operator
>  {
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
> +  using range_operator::op2_range;
>  public:
>    virtual bool fold_range (irange &r, tree type,
>                            const irange &op1,
> @@ -1061,6 +1076,9 @@ operator_gt::op2_range (irange &r, tree type,
>
>  class operator_ge :  public range_operator
>  {
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
> +  using range_operator::op2_range;
>  public:
>    virtual bool fold_range (irange &r, tree type,
>                            const irange &op1,
> @@ -1169,6 +1187,10 @@ operator_ge::op2_range (irange &r, tree type,
>
>  class operator_plus : public range_operator
>  {
> +  using range_operator::op1_range;
> +  using range_operator::op2_range;
> +  using range_operator::lhs_op1_relation;
> +  using range_operator::lhs_op2_relation;
>  public:
>    virtual bool op1_range (irange &r, tree type,
>                           const irange &lhs,
> @@ -1286,7 +1308,7 @@ operator_plus::op1_range (irange &r, tree type,
>                           const irange &op2,
>                           relation_kind rel ATTRIBUTE_UNUSED) const
>  {
> -  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op2);
> +  return range_op_handler (MINUS_EXPR, type).fold_range (r, type, lhs, op2);
>  }
>
>  bool
> @@ -1295,12 +1317,15 @@ operator_plus::op2_range (irange &r, tree type,
>                           const irange &op1,
>                           relation_kind rel ATTRIBUTE_UNUSED) const
>  {
> -  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op1);
> +  return range_op_handler (MINUS_EXPR, type).fold_range (r, type, lhs, op1);
>  }
>
>
>  class operator_minus : public range_operator
>  {
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
> +  using range_operator::op2_range;
>  public:
>    virtual bool op1_range (irange &r, tree type,
>                           const irange &lhs,
> @@ -1445,7 +1470,7 @@ operator_minus::op1_range (irange &r, tree type,
>                            const irange &op2,
>                            relation_kind rel ATTRIBUTE_UNUSED) const
>  {
> -  return range_op_handler (PLUS_EXPR, type)->fold_range (r, type, lhs, op2);
> +  return range_op_handler (PLUS_EXPR, type).fold_range (r, type, lhs, op2);
>  }
>
>  bool
> @@ -1597,6 +1622,8 @@ cross_product_operator::wi_cross_product (irange &r, tree type,
>
>  class operator_mult : public cross_product_operator
>  {
> +  using range_operator::op1_range;
> +  using range_operator::op2_range;
>  public:
>    virtual void wi_fold (irange &r, tree type,
>                         const wide_int &lh_lb,
> @@ -1629,8 +1656,8 @@ operator_mult::op1_range (irange &r, tree type,
>      return false;
>
>    if (op2.singleton_p (&offset) && !integer_zerop (offset))
> -    return range_op_handler (TRUNC_DIV_EXPR, type)->fold_range (r, type,
> -                                                               lhs, op2);
> +    return range_op_handler (TRUNC_DIV_EXPR, type).fold_range (r, type,
> +                                                              lhs, op2);
>    return false;
>  }
>
> @@ -1857,6 +1884,7 @@ operator_div op_ceil_div (CEIL_DIV_EXPR);
>
>  class operator_exact_divide : public operator_div
>  {
> +  using range_operator::op1_range;
>  public:
>    operator_exact_divide () : operator_div (TRUNC_DIV_EXPR) { }
>    virtual bool op1_range (irange &r, tree type,
> @@ -1881,13 +1909,15 @@ operator_exact_divide::op1_range (irange &r, tree type,
>    // If op2 is a multiple of 2, we would be able to set some non-zero bits.
>    if (op2.singleton_p (&offset)
>        && !integer_zerop (offset))
> -    return range_op_handler (MULT_EXPR, type)->fold_range (r, type, lhs, op2);
> +    return range_op_handler (MULT_EXPR, type).fold_range (r, type, lhs, op2);
>    return false;
>  }
>
>
>  class operator_lshift : public cross_product_operator
>  {
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
>  public:
>    virtual bool op1_range (irange &r, tree type,
>                           const irange &lhs,
> @@ -1909,6 +1939,9 @@ public:
>
>  class operator_rshift : public cross_product_operator
>  {
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
> +  using range_operator::lhs_op1_relation;
>  public:
>    virtual bool fold_range (irange &r, tree type,
>                            const irange &op1,
> @@ -2248,6 +2281,8 @@ operator_rshift::wi_fold (irange &r, tree type,
>
>  class operator_cast: public range_operator
>  {
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
>  public:
>    virtual bool fold_range (irange &r, tree type,
>                            const irange &op1,
> @@ -2417,10 +2452,9 @@ operator_cast::op1_range (irange &r, tree type,
>           // Add this to the unsigned LHS range(s).
>           int_range_max lim_range (type, lim, lim);
>           int_range_max lhs_neg;
> -         range_op_handler (PLUS_EXPR, type)->fold_range (lhs_neg,
> -                                                         type,
> -                                                         converted_lhs,
> -                                                         lim_range);
> +         range_op_handler (PLUS_EXPR, type).fold_range (lhs_neg, type,
> +                                                        converted_lhs,
> +                                                        lim_range);
>           // lhs_neg now has all the negative versions of the LHS.
>           // Now union in all the values from SIGNED MIN (0x80000) to
>           // lim-1 in order to fill in all the ranges with the upper
> @@ -2469,6 +2503,9 @@ operator_cast::op1_range (irange &r, tree type,
>
>  class operator_logical_and : public range_operator
>  {
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
> +  using range_operator::op2_range;
>  public:
>    virtual bool fold_range (irange &r, tree type,
>                            const irange &lh,
> @@ -2542,6 +2579,9 @@ operator_logical_and::op2_range (irange &r, tree type,
>
>  class operator_bitwise_and : public range_operator
>  {
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
> +  using range_operator::op2_range;
>  public:
>    virtual bool fold_range (irange &r, tree type,
>                            const irange &lh,
> @@ -2988,6 +3028,9 @@ operator_bitwise_and::op2_range (irange &r, tree type,
>
>  class operator_logical_or : public range_operator
>  {
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
> +  using range_operator::op2_range;
>  public:
>    virtual bool fold_range (irange &r, tree type,
>                            const irange &lh,
> @@ -3051,6 +3094,8 @@ operator_logical_or::op2_range (irange &r, tree type,
>
>  class operator_bitwise_or : public range_operator
>  {
> +  using range_operator::op1_range;
> +  using range_operator::op2_range;
>  public:
>    virtual bool op1_range (irange &r, tree type,
>                           const irange &lhs,
> @@ -3155,6 +3200,8 @@ operator_bitwise_or::op2_range (irange &r, tree type,
>
>  class operator_bitwise_xor : public range_operator
>  {
> +  using range_operator::op1_range;
> +  using range_operator::op2_range;
>  public:
>    virtual void wi_fold (irange &r, tree type,
>                         const wide_int &lh_lb,
> @@ -3296,6 +3343,8 @@ operator_bitwise_xor::op2_range (irange &r, tree type,
>
>  class operator_trunc_mod : public range_operator
>  {
> +  using range_operator::op1_range;
> +  using range_operator::op2_range;
>  public:
>    virtual void wi_fold (irange &r, tree type,
>                         const wide_int &lh_lb,
> @@ -3432,6 +3481,8 @@ operator_trunc_mod::op2_range (irange &r, tree type,
>
>  class operator_logical_not : public range_operator
>  {
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
>  public:
>    virtual bool fold_range (irange &r, tree type,
>                            const irange &lh,
> @@ -3487,6 +3538,8 @@ operator_logical_not::op1_range (irange &r,
>
>  class operator_bitwise_not : public range_operator
>  {
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
>  public:
>    virtual bool fold_range (irange &r, tree type,
>                            const irange &lh,
> @@ -3513,8 +3566,7 @@ operator_bitwise_not::fold_range (irange &r, tree type,
>    // ~X is simply -1 - X.
>    int_range<1> minusone (type, wi::minus_one (TYPE_PRECISION (type)),
>                          wi::minus_one (TYPE_PRECISION (type)));
> -  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, minusone,
> -                                                         lh);
> +  return range_op_handler (MINUS_EXPR, type).fold_range (r, type, minusone, lh);
>  }
>
>  bool
> @@ -3533,6 +3585,7 @@ operator_bitwise_not::op1_range (irange &r, tree type,
>
>  class operator_cst : public range_operator
>  {
> +  using range_operator::fold_range;
>  public:
>    virtual bool fold_range (irange &r, tree type,
>                            const irange &op1,
> @@ -3553,6 +3606,9 @@ operator_cst::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
>
>  class operator_identity : public range_operator
>  {
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
> +  using range_operator::lhs_op1_relation;
>  public:
>    virtual bool fold_range (irange &r, tree type,
>                            const irange &op1,
> @@ -3605,6 +3661,7 @@ operator_identity::op1_range (irange &r, tree type ATTRIBUTE_UNUSED,
>
>  class operator_unknown : public range_operator
>  {
> +  using range_operator::fold_range;
>  public:
>    virtual bool fold_range (irange &r, tree type,
>                            const irange &op1,
> @@ -3625,6 +3682,7 @@ operator_unknown::fold_range (irange &r, tree type,
>
>  class operator_abs : public range_operator
>  {
> +  using range_operator::op1_range;
>   public:
>    virtual void wi_fold (irange &r, tree type,
>                         const wide_int &lh_lb,
> @@ -3790,6 +3848,8 @@ operator_absu::wi_fold (irange &r, tree type,
>
>  class operator_negate : public range_operator
>  {
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
>   public:
>    virtual bool fold_range (irange &r, tree type,
>                            const irange &op1,
> @@ -3810,9 +3870,8 @@ operator_negate::fold_range (irange &r, tree type,
>    if (empty_range_varying (r, type, lh, rh))
>      return true;
>    // -X is simply 0 - X.
> -  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type,
> -                                                         range_zero (type),
> -                                                         lh);
> +  return range_op_handler (MINUS_EXPR, type).fold_range (r, type,
> +                                                        range_zero (type), lh);
>  }
>
>  bool
> @@ -3828,6 +3887,8 @@ operator_negate::op1_range (irange &r, tree type,
>
>  class operator_addr_expr : public range_operator
>  {
> +  using range_operator::fold_range;
> +  using range_operator::op1_range;
>  public:
>    virtual bool fold_range (irange &r, tree type,
>                            const irange &op1,
> @@ -3978,6 +4039,8 @@ pointer_and_operator::wi_fold (irange &r, tree type,
>
>  class pointer_or_operator : public range_operator
>  {
> +  using range_operator::op1_range;
> +  using range_operator::op2_range;
>  public:
>    virtual bool op1_range (irange &r, tree type,
>                           const irange &lhs,
> @@ -4139,8 +4202,8 @@ pointer_table::pointer_table ()
>
>  // The tables are hidden and accessed via a simple extern function.
>
> -range_operator *
> -range_op_handler (enum tree_code code, tree type)
> +static inline range_operator *
> +get_handler (enum tree_code code, tree type)
>  {
>    // First check if there is a pointer specialization.
>    if (POINTER_TYPE_P (type))
> @@ -4150,16 +4213,120 @@ range_op_handler (enum tree_code code, tree type)
>    return NULL;
>  }
>
> +range_op_handler::range_op_handler (tree_code code, tree type)
> +{
> +  m_op = get_handler (code, type);
> +}
> +
> +range_op_handler::range_op_handler (const gimple *s)
> +{
> +  if (const gassign *ass = dyn_cast<const gassign *> (s))
> +    {
> +      enum tree_code code = gimple_assign_rhs_code (ass);
> +      // The LHS of a comparison is always an int, so we must look at
> +      // the operands.
> +      if (TREE_CODE_CLASS (code) == tcc_comparison)
> +       m_op = get_handler (code, TREE_TYPE (gimple_assign_rhs1 (ass)));
> +      else
> +       m_op = get_handler (code, TREE_TYPE (gimple_assign_lhs (ass)));
> +    }
> +  else if (const gcond *cond = dyn_cast<const gcond *> (s))
> +    m_op = get_handler (gimple_cond_code (cond),
> +                       TREE_TYPE (gimple_cond_lhs (cond)));
> +  else
> +    m_op = NULL;
> +}
> +
> +bool
> +range_op_handler::fold_range (vrange &r, tree type,
> +                             const vrange &lh,
> +                             const vrange &rh,
> +                             relation_kind rel) const
> +{
> +  if (is_a <irange> (lh))
> +    return m_op->fold_range (as_a <irange> (r), type,
> +                            as_a <irange> (lh),
> +                            as_a <irange> (rh), rel);
> +  gcc_unreachable ();
> +  return false;
> +}
> +
> +bool
> +range_op_handler::op1_range (vrange &r, tree type,
> +                            const vrange &lhs,
> +                            const vrange &op2,
> +                            relation_kind rel) const
> +{
> +  if (is_a <irange> (r))
> +    return m_op->op1_range (as_a <irange> (r), type,
> +                           as_a <irange> (lhs),
> +                           as_a <irange> (op2), rel);
> +  gcc_unreachable ();
> +  return false;
> +}
> +
> +bool
> +range_op_handler::op2_range (vrange &r, tree type,
> +                            const vrange &lhs,
> +                            const vrange &op1,
> +                            relation_kind rel) const
> +{
> +  if (is_a <irange> (r))
> +    return m_op->op2_range (as_a <irange> (r), type,
> +                           as_a <irange> (lhs),
> +                           as_a <irange> (op1), rel);
> +  gcc_unreachable ();
> +  return false;
> +}
> +
> +relation_kind
> +range_op_handler::lhs_op1_relation (const vrange &lhs,
> +                                   const vrange &op1,
> +                                   const vrange &op2,
> +                                   relation_kind rel) const
> +{
> +  if (is_a <irange> (op1))
> +    return m_op->lhs_op1_relation (as_a <irange> (lhs),
> +                                  as_a <irange> (op1), as_a <irange> (op2), rel);
> +  gcc_unreachable ();
> +  return VREL_VARYING;
> +}
> +
> +relation_kind
> +range_op_handler::lhs_op2_relation (const vrange &lhs,
> +                                   const vrange &op1,
> +                                   const vrange &op2,
> +                                   relation_kind rel) const
> +{
> +  if (is_a <irange> (op1))
> +    return m_op->lhs_op2_relation (as_a <irange> (lhs),
> +                                  as_a <irange> (op1), as_a <irange> (op2), rel);
> +  gcc_unreachable ();
> +  return VREL_VARYING;
> +}
> +
> +relation_kind
> +range_op_handler::op1_op2_relation (const vrange &lhs) const
> +{
> +  return m_op->op1_op2_relation (as_a <irange> (lhs));
> +}
> +
>  // Cast the range in R to TYPE.
>
> -void
> -range_cast (irange &r, tree type)
> +bool
> +range_cast (vrange &r, tree type)
>  {
> -  int_range_max tmp = r;
> -  range_operator *op = range_op_handler (CONVERT_EXPR, type);
> +  tmp_range tmp (r);
> +  tmp_range varying (type);
> +  varying.set_varying (type);
> +  range_op_handler op (CONVERT_EXPR, type);
>    // Call op_convert, if it fails, the result is varying.
> -  if (!op->fold_range (r, type, tmp, int_range<1> (type)))
> -    r.set_varying (type);
> +  if (!op || !op.fold_range (r, type, tmp, varying))
> +    {
> +      r.set_varying (type);
> +      return false;
> +    }
> +  return true;
>  }
>
>  #if CHECKING_P
> diff --git a/gcc/range-op.h b/gcc/range-op.h
> index 5fdda326d4b..d0f50689897 100644
> --- a/gcc/range-op.h
> +++ b/gcc/range-op.h
> @@ -108,8 +108,39 @@ protected:
>                          const wide_int &rh_ub) const;
>  };
>
> -extern range_operator *range_op_handler (enum tree_code code, tree type);
> -extern void range_cast (irange &, tree type);
> +class range_op_handler
> +{
> +public:
> +  range_op_handler (enum tree_code code, tree type);
> +  range_op_handler (const gimple *s);
> +  operator bool () const { return m_op; }
> +
> +  bool fold_range (vrange &r, tree type,
> +                  const vrange &lh,
> +                  const vrange &rh,
> +                  relation_kind rel = VREL_VARYING) const;
> +  bool op1_range (vrange &r, tree type,
> +                 const vrange &lhs,
> +                 const vrange &op2,
> +                 relation_kind rel = VREL_VARYING) const;
> +  bool op2_range (vrange &r, tree type,
> +                 const vrange &lhs,
> +                 const vrange &op1,
> +                 relation_kind rel = VREL_VARYING) const;
> +  relation_kind lhs_op1_relation (const vrange &lhs,
> +                                 const vrange &op1,
> +                                 const vrange &op2,
> +                                 relation_kind = VREL_VARYING) const;
> +  relation_kind lhs_op2_relation (const vrange &lhs,
> +                                 const vrange &op1,
> +                                 const vrange &op2,
> +                                 relation_kind = VREL_VARYING) const;
> +  relation_kind op1_op2_relation (const vrange &lhs) const;
> +private:
> +  range_operator *m_op;
> +};
> +
> +extern bool range_cast (vrange &, tree type);
>  extern void wi_set_zero_nonzero_bits (tree type,
>                                       const wide_int &, const wide_int &,
>                                       wide_int &maybe_nonzero,
> @@ -124,7 +155,7 @@ relation_kind gt_op1_op2_relation (const irange &lhs);
>  relation_kind ge_op1_op2_relation (const irange &lhs);
>
>  enum bool_range_state { BRS_FALSE, BRS_TRUE, BRS_EMPTY, BRS_FULL };
> -bool_range_state get_bool_state (irange &r, const irange &lhs, tree val_type);
> +bool_range_state get_bool_state (vrange &r, const vrange &lhs, tree val_type);
>
>  // If the range of either op1 or op2 is undefined, set the result to
>  // varying and return TRUE.  If the caller truely cares about a result,
> @@ -132,8 +163,8 @@ bool_range_state get_bool_state (irange &r, const irange &lhs, tree val_type);
>  // treated as a varying.
>
>  inline bool
> -empty_range_varying (irange &r, tree type,
> -                    const irange &op1, const irange & op2)
> +empty_range_varying (vrange &r, tree type,
> +                    const vrange &op1, const vrange & op2)
>  {
>    if (op1.undefined_p () || op2.undefined_p ())
>      {
> @@ -150,8 +181,8 @@ empty_range_varying (irange &r, tree type,
>  // return false.
>
>  inline bool
> -relop_early_resolve (irange &r, tree type, const irange &op1,
> -                    const irange &op2, relation_kind rel,
> +relop_early_resolve (irange &r, tree type, const vrange &op1,
> +                    const vrange &op2, relation_kind rel,
>                      relation_kind my_rel)
>  {
>    // If known relation is a complete subset of this relation, always true.
> diff --git a/gcc/tree-data-ref.cc b/gcc/tree-data-ref.cc
> index 397792c3584..ae05fe74b95 100644
> --- a/gcc/tree-data-ref.cc
> +++ b/gcc/tree-data-ref.cc
> @@ -593,8 +593,8 @@ compute_distributive_range (tree type, value_range &op0_range,
>    gcc_assert (INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_TRAPS (type));
>    if (result_range)
>      {
> -      range_operator *op = range_op_handler (code, type);
> -      op->fold_range (*result_range, type, op0_range, op1_range);
> +      range_op_handler op (code, type);
> +      op.fold_range (*result_range, type, op0_range, op1_range);
>      }
>
>    /* The distributive property guarantees that if TYPE is no narrower
> @@ -639,10 +639,10 @@ compute_distributive_range (tree type, value_range &op0_range,
>    range_cast (op0_range, ssizetype);
>    range_cast (op1_range, ssizetype);
>    value_range wide_range;
> -  range_operator *op = range_op_handler (code, ssizetype);
> +  range_op_handler op (code, ssizetype);
>    bool saved_flag_wrapv = flag_wrapv;
>    flag_wrapv = 1;
> -  op->fold_range (wide_range, ssizetype, op0_range, op1_range);
> +  op.fold_range (wide_range, ssizetype, op0_range, op1_range);
>    flag_wrapv = saved_flag_wrapv;
>    if (wide_range.num_pairs () != 1 || !range_int_cst_p (&wide_range))
>      return false;
> diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
> index 0784d658567..3c7b5af4737 100644
> --- a/gcc/tree-vrp.cc
> +++ b/gcc/tree-vrp.cc
> @@ -924,20 +924,6 @@ extract_range_from_plus_minus_expr (value_range *vr,
>      vr->set (min, max, kind);
>  }
>
> -/* Return the range-ops handler for CODE and EXPR_TYPE.  If no
> -   suitable operator is found, return NULL and set VR to VARYING.  */
> -
> -static const range_operator *
> -get_range_op_handler (value_range *vr,
> -                     enum tree_code code,
> -                     tree expr_type)
> -{
> -  const range_operator *op = range_op_handler (code, expr_type);
> -  if (!op)
> -    vr->set_varying (expr_type);
> -  return op;
> -}
> -
>  /* If the types passed are supported, return TRUE, otherwise set VR to
>     VARYING and return FALSE.  */
>
> @@ -1005,10 +991,12 @@ range_fold_binary_symbolics_p (value_range *vr,
>                                                 &vr0, &vr1);
>           return true;
>         }
> -      const range_operator *op = get_range_op_handler (vr, code, expr_type);
> +      range_op_handler op (code, expr_type);
> +      if (!op)
> +       vr->set_varying (expr_type);
>        vr0.normalize_symbolics ();
>        vr1.normalize_symbolics ();
> -      return op->fold_range (*vr, expr_type, vr0, vr1);
> +      return op.fold_range (*vr, expr_type, vr0, vr1);
>      }
>    return false;
>  }
> @@ -1040,10 +1028,12 @@ range_fold_unary_symbolics_p (value_range *vr,
>           range_fold_binary_expr (vr, MINUS_EXPR, expr_type, &minusone, vr0);
>           return true;
>         }
> -      const range_operator *op = get_range_op_handler (vr, code, expr_type);
> +      range_op_handler op (code, expr_type);
> +      if (!op)
> +       vr->set_varying (expr_type);
>        value_range vr0_cst (*vr0);
>        vr0_cst.normalize_symbolics ();
> -      return op->fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
> +      return op.fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
>      }
>    return false;
>  }
> @@ -1060,9 +1050,12 @@ range_fold_binary_expr (value_range *vr,
>    if (!supported_types_p (vr, expr_type)
>        || !defined_ranges_p (vr, vr0_, vr1_))
>      return;
> -  const range_operator *op = get_range_op_handler (vr, code, expr_type);
> +  range_op_handler op (code, expr_type);
>    if (!op)
> -    return;
> +    {
> +      vr->set_varying (expr_type);
> +      return;
> +    }
>
>    if (range_fold_binary_symbolics_p (vr, code, expr_type, vr0_, vr1_))
>      return;
> @@ -1075,7 +1068,7 @@ range_fold_binary_expr (value_range *vr,
>      vr1.set_varying (expr_type);
>    vr0.normalize_addresses ();
>    vr1.normalize_addresses ();
> -  op->fold_range (*vr, expr_type, vr0, vr1);
> +  op.fold_range (*vr, expr_type, vr0, vr1);
>  }
>
>  /* Perform a unary operation on a range.  */
> @@ -1089,16 +1082,19 @@ range_fold_unary_expr (value_range *vr,
>    if (!supported_types_p (vr, expr_type, vr0_type)
>        || !defined_ranges_p (vr, vr0))
>      return;
> -  const range_operator *op = get_range_op_handler (vr, code, expr_type);
> +  range_op_handler op (code, expr_type);
>    if (!op)
> -    return;
> +    {
> +      vr->set_varying (expr_type);
> +      return;
> +    }
>
>    if (range_fold_unary_symbolics_p (vr, code, expr_type, vr0))
>      return;
>
>    value_range vr0_cst (*vr0);
>    vr0_cst.normalize_addresses ();
> -  op->fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
> +  op.fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
>  }
>
>  /* If the range of values taken by OP can be inferred after STMT executes,
> diff --git a/gcc/value-query.cc b/gcc/value-query.cc
> index 26e3858103b..31e56eeae53 100644
> --- a/gcc/value-query.cc
> +++ b/gcc/value-query.cc
> @@ -234,13 +234,13 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
>      }
>    if (BINARY_CLASS_P (expr))
>      {
> -      range_operator *op = range_op_handler (TREE_CODE (expr), type);
> +      range_op_handler op (TREE_CODE (expr), type);
>        if (op)
>         {
>           int_range_max r0, r1;
>           range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
>           range_of_expr (r1, TREE_OPERAND (expr, 1), stmt);
> -         op->fold_range (r, type, r0, r1);
> +         op.fold_range (r, type, r0, r1);
>         }
>        else
>         r.set_varying (type);
> @@ -248,13 +248,13 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
>      }
>    if (UNARY_CLASS_P (expr))
>      {
> -      range_operator *op = range_op_handler (TREE_CODE (expr), type);
> +      range_op_handler op (TREE_CODE (expr), type);
>        tree op0_type = TREE_TYPE (TREE_OPERAND (expr, 0));
>        if (op && irange::supports_type_p (op0_type))
>         {
>           int_range_max r0;
>           range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
> -         op->fold_range (r, type, r0, int_range<1> (type));
> +         op.fold_range (r, type, r0, int_range<1> (type));
>         }
>        else
>         r.set_varying (type);
> --
> 2.36.1
>

[-- Attachment #2: 0003-Convert-range-op.-to-vrange.patch --]
[-- Type: text/x-patch, Size: 43951 bytes --]

From cf5bea76f9d84f6218f0a5085db63a50aed9d95a Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <aldyh@redhat.com>
Date: Mon, 14 Mar 2022 13:31:18 +0100
Subject: [PATCH] Convert range-op.* to vrange.

This patch provides the infrastructure to make range-ops type agnostic.

First, the range_op_handler function has been replaced with an object
of the same name.  It's coded in such a way to minimize changes to the
code base, and to encapsulate the dispatch code.

Instead of:

	range_operator *op = range_op_handler (code, type);
	if (op)
	  op->fold_range (...);

We now do:
	range_op_handler op (code, type);
	if (op)
	  op->fold_range (...);

I've folded gimple_range_handler into the range_op_handler class,
since it's also a query into the range operators.

Instead of:

	range_operator *handler = gimple_range_handler (stmt);

We now do:

	range_op_handler handler (stmt);

This all has the added benefit of moving all the dispatch code into an
independent class and avoid polluting range_operator (which we'll
further split later when frange and prange come live).

There's this annoying "using" keyword that's been added to each
operator due to hiding rules in C++.  The issue is that we will have
different virtual versions of fold_range() for each combination of
operands.  For example:

	// Traditional binary op on irange's.
	fold_range (irange &lhs, const irange &op1, const irange &op2);
	// For POINTER_DIFF_EXPR:
	fold_range (irange &lhs, const prange &op1, const prange &op2);
	// Cast from irange to prange.
	fold_range (prange &lhs, const irange &op1, const irange &op2);

Overloading virtuals when there are multiple same named methods causes
hidden virtuals warnings from -Woverloaded-virtual, thus the using
keyword.  An alternative would be to have different names:
fold_range_III, fold_range_IPP, fold_range_PII, but that's uglier
still.

Tested on x86-64 & ppc64le Linux.

gcc/ChangeLog:

	* gimple-range-edge.cc (gimple_outgoing_range_stmt_p): Adjust for
	vrange and convert range_op_handler function calls to use the
	identically named object.
	* gimple-range-fold.cc (gimple_range_operand1): Same.
	(gimple_range_operand2): Same.
	(fold_using_range::fold_stmt): Same.
	(fold_using_range::range_of_range_op): Same.
	(fold_using_range::range_of_builtin_ubsan_call): Same.
	(fold_using_range::relation_fold_and_or): Same.
	(fur_source::register_outgoing_edges): Same.
	* gimple-range-fold.h (gimple_range_handler): Remove.
	* gimple-range-gori.cc (gimple_range_calc_op1): Adjust for vrange.
	(gimple_range_calc_op2): Same.
	(range_def_chain::get_def_chain): Same.
	(gori_compute::compute_operand_range): Same.
	(gori_compute::condexpr_adjust): Same.
	* gimple-range.cc (gimple_ranger::prefill_name): Same.
	(gimple_ranger::prefill_stmt_dependencies): Same.
	* range-op.cc (get_bool_state): Same.
	(class operator_equal): Add using clause.
	(class operator_not_equal): Same.
	(class operator_lt): Same.
	(class operator_le): Same.
	(class operator_gt): Same.
	(class operator_ge): Same.
	(class operator_plus): Same.
	(class operator_minus): Same.
	(class operator_mult): Same.
	(class operator_exact_divide): Same.
	(class operator_lshift): Same.
	(class operator_rshift): Same.
	(class operator_cast): Same.
	(class operator_logical_and): Same.
	(class operator_bitwise_and): Same.
	(class operator_logical_or): Same.
	(class operator_bitwise_or): Same.
	(class operator_bitwise_xor): Same.
	(class operator_trunc_mod): Same.
	(class operator_logical_not): Same.
	(class operator_bitwise_not): Same.
	(class operator_cst): Same.
	(class operator_identity): Same.
	(class operator_unknown): Same.
	(class operator_abs): Same.
	(class operator_negate): Same.
	(class operator_addr_expr): Same.
	(class pointer_or_operator): Same.
	(operator_plus::op1_range): Adjust for vrange.
	(operator_minus::op1_range): Same.
	(operator_mult::op1_range): Same.
	(operator_cast::op1_range): Same.
	(operator_bitwise_not::fold_range): Same.
	(operator_negate::fold_range): Same.
	(range_op_handler): Rename to...
	(get_handler): ...this.
	(range_op_handler::range_op_handler): New.
	(range_op_handler::fold_range): New.
	(range_op_handler::op1_range): New.
	(range_op_handler::op2_range): New.
	(range_op_handler::lhs_op1_relation): New.
	(range_op_handler::lhs_op2_relation): New.
	(range_op_handler::op1_op2_relation): New.
	(range_cast): Adjust for vrange.
	* range-op.h (range_op_handler): Remove function.
	(range_cast): Adjust for vrange.
	(class range_op_handler): New.
	(get_bool_state): Adjust for vrange.
	(empty_range_varying): Same.
	(relop_early_resolve): Same.
	* tree-data-ref.cc (compute_distributive_range): Same.
	* tree-vrp.cc (get_range_op_handler): Remove.
	(range_fold_binary_symbolics_p): Use range_op_handler class
	instead of get_range_op_handler.
	(range_fold_unary_symbolics_p): Same.
	(range_fold_binary_expr): Same.
	(range_fold_unary_expr): Same.
	* value-query.cc (range_query::get_tree_range): Adjust for vrange.
---
 gcc/gimple-range-edge.cc |   2 +-
 gcc/gimple-range-fold.cc |  43 ++++----
 gcc/gimple-range-fold.h  |  15 ---
 gcc/gimple-range-gori.cc |  41 ++++----
 gcc/gimple-range.cc      |   6 +-
 gcc/range-op.cc          | 215 ++++++++++++++++++++++++++++++++++-----
 gcc/range-op.h           |  45 ++++++--
 gcc/tree-data-ref.cc     |   8 +-
 gcc/tree-vrp.cc          |  44 ++++----
 gcc/value-query.cc       |   8 +-
 10 files changed, 303 insertions(+), 124 deletions(-)

diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc
index 0bee38ba770..5bbe23ae03d 100644
--- a/gcc/gimple-range-edge.cc
+++ b/gcc/gimple-range-edge.cc
@@ -42,7 +42,7 @@ gimple_outgoing_range_stmt_p (basic_block bb)
   if (!gsi_end_p (gsi))
     {
       gimple *s = gsi_stmt (gsi);
-      if (is_a<gcond *> (s) && gimple_range_handler (s))
+      if (is_a<gcond *> (s) && range_op_handler (s))
 	return gsi_stmt (gsi);
       gswitch *sw = dyn_cast<gswitch *> (s);
       if (sw && irange::supports_type_p (TREE_TYPE (gimple_switch_index (sw))))
diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 0a947c16c58..c53d2863d5e 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -482,7 +482,7 @@ gimple_range_base_of_assignment (const gimple *stmt)
 tree
 gimple_range_operand1 (const gimple *stmt)
 {
-  gcc_checking_assert (gimple_range_handler (stmt));
+  gcc_checking_assert (range_op_handler (stmt));
 
   switch (gimple_code (stmt))
     {
@@ -515,7 +515,7 @@ gimple_range_operand1 (const gimple *stmt)
 tree
 gimple_range_operand2 (const gimple *stmt)
 {
-  gcc_checking_assert (gimple_range_handler (stmt));
+  gcc_checking_assert (range_op_handler (stmt));
 
   switch (gimple_code (stmt))
     {
@@ -551,7 +551,7 @@ fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name)
       && gimple_assign_rhs_code (s) == ADDR_EXPR)
     return range_of_address (r, s, src);
 
-  if (gimple_range_handler (s))
+  if (range_op_handler (s))
     res = range_of_range_op (r, s, src);
   else if (is_a<gphi *>(s))
     res = range_of_phi (r, as_a<gphi *> (s), src);
@@ -593,7 +593,7 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
   tree type = gimple_range_type (s);
   if (!type)
     return false;
-  range_operator *handler = gimple_range_handler (s);
+  range_op_handler handler (s);
   gcc_checking_assert (handler);
 
   tree lhs = gimple_get_lhs (s);
@@ -606,13 +606,13 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
 	{
 	  // Fold range, and register any dependency if available.
 	  int_range<2> r2 (type);
-	  handler->fold_range (r, type, range1, r2);
+	  handler.fold_range (r, type, range1, r2);
 	  if (lhs && gimple_range_ssa_p (op1))
 	    {
 	      if (src.gori ())
 		src.gori ()->register_dependency (lhs, op1);
 	      relation_kind rel;
-	      rel = handler->lhs_op1_relation (r, range1, range1);
+	      rel = handler.lhs_op1_relation (r, range1, range1);
 	      if (rel != VREL_VARYING)
 		src.register_relation (s, rel, lhs, op1);
 	    }
@@ -629,7 +629,7 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
 	      fputc ('\n', dump_file);
 	    }
 	  // Fold range, and register any dependency if available.
-	  handler->fold_range (r, type, range1, range2, rel);
+	  handler.fold_range (r, type, range1, range2, rel);
 	  relation_fold_and_or (r, s, src);
 	  if (lhs)
 	    {
@@ -640,13 +640,13 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
 		}
 	      if (gimple_range_ssa_p (op1))
 		{
-		  rel = handler->lhs_op1_relation (r, range1, range2, rel);
+		  rel = handler.lhs_op1_relation (r, range1, range2, rel);
 		  if (rel != VREL_VARYING)
 		    src.register_relation (s, rel, lhs, op1);
 		}
 	      if (gimple_range_ssa_p (op2))
 		{
-		  rel= handler->lhs_op2_relation (r, range1, range2, rel);
+		  rel= handler.lhs_op2_relation (r, range1, range2, rel);
 		  if (rel != VREL_VARYING)
 		    src.register_relation (s, rel, lhs, op2);
 		}
@@ -921,7 +921,7 @@ fold_using_range::range_of_builtin_ubsan_call (irange &r, gcall *call,
   gcc_checking_assert (code == PLUS_EXPR || code == MINUS_EXPR
 		       || code == MULT_EXPR);
   tree type = gimple_range_type (call);
-  range_operator *op = range_op_handler (code, type);
+  range_op_handler op (code, type);
   gcc_checking_assert (op);
   int_range_max ir0, ir1;
   tree arg0 = gimple_call_arg (call, 0);
@@ -935,7 +935,7 @@ fold_using_range::range_of_builtin_ubsan_call (irange &r, gcall *call,
   // Pretend the arithmetic is wrapping.  If there is any overflow,
   // we'll complain, but will actually do wrapping operation.
   flag_wrapv = 1;
-  op->fold_range (r, type, ir0, ir1, relation);
+  op.fold_range (r, type, ir0, ir1, relation);
   flag_wrapv = saved_flag_wrapv;
 
   // If for both arguments vrp_valueize returned non-NULL, this should
@@ -1391,8 +1391,8 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
   else if (ssa1_dep1 != ssa2_dep2 || ssa1_dep2 != ssa2_dep1)
     return;
 
-  range_operator *handler1 = gimple_range_handler (SSA_NAME_DEF_STMT (ssa1));
-  range_operator *handler2 = gimple_range_handler (SSA_NAME_DEF_STMT (ssa2));
+  range_op_handler handler1 (SSA_NAME_DEF_STMT (ssa1));
+  range_op_handler handler2 (SSA_NAME_DEF_STMT (ssa2));
 
   // If either handler is not present, no relation is found.
   if (!handler1 || !handler2)
@@ -1400,8 +1400,8 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
 
   int_range<2> bool_one (boolean_true_node, boolean_true_node);
 
-  relation_kind relation1 = handler1->op1_op2_relation (bool_one);
-  relation_kind relation2 = handler2->op1_op2_relation (bool_one);
+  relation_kind relation1 = handler1.op1_op2_relation (bool_one);
+  relation_kind relation2 = handler2.op1_op2_relation (bool_one);
   if (relation1 == VREL_VARYING || relation2 == VREL_VARYING)
     return;
 
@@ -1441,7 +1441,6 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
   int_range_max r;
   int_range<2> e0_range, e1_range;
   tree name;
-  range_operator *handler;
   basic_block bb = gimple_bb (s);
 
   if (e0)
@@ -1472,17 +1471,17 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
   tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (s));
   if (ssa1 && ssa2)
     {
-      handler = gimple_range_handler (s);
+      range_op_handler handler (s);
       gcc_checking_assert (handler);
       if (e0)
 	{
-	  relation_kind relation = handler->op1_op2_relation (e0_range);
+	  relation_kind relation = handler.op1_op2_relation (e0_range);
 	  if (relation != VREL_VARYING)
 	    register_relation (e0, relation, ssa1, ssa2);
 	}
       if (e1)
 	{
-	  relation_kind relation = handler->op1_op2_relation (e1_range);
+	  relation_kind relation = handler.op1_op2_relation (e1_range);
 	  if (relation != VREL_VARYING)
 	    register_relation (e1, relation, ssa1, ssa2);
 	}
@@ -1501,7 +1500,7 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
       if (TREE_CODE (TREE_TYPE (name)) != BOOLEAN_TYPE)
 	continue;
       gimple *stmt = SSA_NAME_DEF_STMT (name);
-      handler = gimple_range_handler (stmt);
+      range_op_handler handler (stmt);
       if (!handler)
 	continue;
       tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
@@ -1511,14 +1510,14 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
 	  if (e0 && gori ()->outgoing_edge_range_p (r, e0, name, *m_query)
 	      && r.singleton_p ())
 	    {
-	      relation_kind relation = handler->op1_op2_relation (r);
+	      relation_kind relation = handler.op1_op2_relation (r);
 	      if (relation != VREL_VARYING)
 		register_relation (e0, relation, ssa1, ssa2);
 	    }
 	  if (e1 && gori ()->outgoing_edge_range_p (r, e1, name, *m_query)
 	      && r.singleton_p ())
 	    {
-	      relation_kind relation = handler->op1_op2_relation (r);
+	      relation_kind relation = handler.op1_op2_relation (r);
 	      if (relation != VREL_VARYING)
 		register_relation (e1, relation, ssa1, ssa2);
 	    }
diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h
index 20cb73dabb9..4b5d4b6e0b8 100644
--- a/gcc/gimple-range-fold.h
+++ b/gcc/gimple-range-fold.h
@@ -41,21 +41,6 @@ bool fold_range (irange &r, gimple *s, irange &r1);
 bool fold_range (irange &r, gimple *s, irange &r1, irange &r2);
 bool fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector);
 
-// Return the range_operator pointer for this statement.  This routine
-// can also be used to gate whether a routine is range-ops enabled.
-
-static inline range_operator *
-gimple_range_handler (const gimple *s)
-{
-  if (const gassign *ass = dyn_cast<const gassign *> (s))
-    return range_op_handler (gimple_assign_rhs_code (ass),
-			     TREE_TYPE (gimple_assign_lhs (ass)));
-  if (const gcond *cond = dyn_cast<const gcond *> (s))
-    return range_op_handler (gimple_cond_code (cond),
-			     TREE_TYPE (gimple_cond_lhs (cond)));
-  return NULL;
-}
-
 // Return the type of range which statement S calculates.  If the type is
 // unsupported or no type can be determined, return NULL_TREE.
 
diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index 3e15eb5192d..72032132cac 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -44,9 +44,9 @@ gimple_range_calc_op1 (irange &r, const gimple *stmt, const irange &lhs_range)
   // Unary operations require the type of the first operand in the
   // second range position.
   tree type = TREE_TYPE (gimple_range_operand1 (stmt));
-  int_range<2> type_range (type);
-  return gimple_range_handler (stmt)->op1_range (r, type, lhs_range,
-						 type_range);
+  Value_Range type_range (type);
+  type_range.set_varying (type);
+  return range_op_handler (stmt).op1_range (r, type, lhs_range, type_range);
 }
 
 // Calculate what we can determine of the range of this statement's
@@ -72,12 +72,12 @@ gimple_range_calc_op1 (irange &r, const gimple *stmt,
       // This is sometimes invoked on single operand stmts.
       if (gimple_num_ops (stmt) < 3)
 	return false;
-      int_range<2> trange (TREE_TYPE (gimple_range_operand2 (stmt)));
-      return gimple_range_handler (stmt)->op1_range (r, type, lhs_range,
-						     trange);
+      tree op2_type = TREE_TYPE (gimple_range_operand2 (stmt));
+      Value_Range trange (op2_type);
+      trange.set_varying (op2_type);
+      return range_op_handler (stmt).op1_range (r, type, lhs_range, trange);
     }
-  return gimple_range_handler (stmt)->op1_range (r, type, lhs_range,
-						 op2_range);
+  return range_op_handler (stmt).op1_range (r, type, lhs_range, op2_range);
 }
 
 // Calculate what we can determine of the range of this statement's
@@ -97,12 +97,13 @@ gimple_range_calc_op2 (irange &r, const gimple *stmt,
   // If op1 is undefined, solve as if it is varying.
   if (op1_range.undefined_p ())
     {
-      int_range<2> trange (TREE_TYPE (gimple_range_operand1 (stmt)));
-      return gimple_range_handler (stmt)->op2_range (r, type, lhs_range,
-						     trange);
+      tree op1_type = TREE_TYPE (gimple_range_operand1 (stmt));
+      Value_Range trange (op1_type);
+      trange.set_varying (op1_type);
+      return range_op_handler (stmt).op2_range (r, type, lhs_range, trange);
     }
-  return gimple_range_handler (stmt)->op2_range (r, type, lhs_range,
-						 op1_range);
+  return range_op_handler (stmt).op2_range (r, type, lhs_range,
+					    op1_range);
 }
 
 // Return TRUE if GS is a logical && or || expression.
@@ -346,7 +347,7 @@ range_def_chain::get_def_chain (tree name)
     }
 
   gimple *stmt = SSA_NAME_DEF_STMT (name);
-  if (gimple_range_handler (stmt))
+  if (range_op_handler (stmt))
     {
       ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
       ssa2 = gimple_range_ssa_p (gimple_range_operand2 (stmt));
@@ -707,7 +708,7 @@ gori_compute::compute_operand_range (irange &r, gimple *stmt,
   if (is_a<gswitch *> (stmt))
     return compute_operand_range_switch (r, as_a<gswitch *> (stmt), lhs, name,
 					 src);
-  if (!gimple_range_handler (stmt))
+  if (!range_op_handler (stmt))
     return false;
 
   tree op1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
@@ -1328,7 +1329,7 @@ gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond,
   tree type = TREE_TYPE (gimple_assign_rhs1 (cond_def));
   if (!range_compatible_p (type, TREE_TYPE (gimple_assign_rhs2 (cond_def))))
     return false;
-  range_operator *hand = range_op_handler (gimple_assign_rhs_code (cond_def), type);
+  range_op_handler hand (gimple_assign_rhs_code (cond_def), type);
   if (!hand)
     return false;
 
@@ -1351,18 +1352,18 @@ gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond,
   // the op1 or op2 routines based on its location.
   if (c1)
     {
-      if (!hand->op1_range (cond_false, type, m_bool_zero, cr))
+      if (!hand.op1_range (cond_false, type, m_bool_zero, cr))
 	return false;
-      if (!hand->op1_range (cond_true, type, m_bool_one, cr))
+      if (!hand.op1_range (cond_true, type, m_bool_one, cr))
 	return false;
       cond_false.intersect (cl);
       cond_true.intersect (cl);
     }
   else
     {
-      if (!hand->op2_range (cond_false, type, m_bool_zero, cl))
+      if (!hand.op2_range (cond_false, type, m_bool_zero, cl))
 	return false;
-      if (!hand->op2_range (cond_true, type, m_bool_one, cl))
+      if (!hand.op2_range (cond_true, type, m_bool_one, cl))
 	return false;
       cond_false.intersect (cr);
       cond_true.intersect (cr);
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 53f4865af3b..0a99787fc75 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -339,7 +339,7 @@ gimple_ranger::prefill_name (irange &r, tree name)
   if (!gimple_range_ssa_p (name))
     return;
   gimple *stmt = SSA_NAME_DEF_STMT (name);
-  if (!gimple_range_handler (stmt) && !is_a<gphi *> (stmt))
+  if (!range_op_handler (stmt) && !is_a<gphi *> (stmt))
     return;
 
   bool current;
@@ -363,7 +363,7 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
   gcc_checking_assert (stmt && gimple_bb (stmt));
 
   // Only pre-process range-ops and phis.
-  if (!gimple_range_handler (stmt) && !is_a<gphi *> (stmt))
+  if (!range_op_handler (stmt) && !is_a<gphi *> (stmt))
     return;
 
   // Mark where on the stack we are starting.
@@ -419,7 +419,7 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
 	}
       else
 	{
-	  gcc_checking_assert (gimple_range_handler (stmt));
+	  gcc_checking_assert (range_op_handler (stmt));
 	  tree op = gimple_range_operand2 (stmt);
 	  if (op)
 	    prefill_name (r, op);
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index c88da8caa6c..028b4b7237c 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -420,7 +420,7 @@ create_possibly_reversed_range (irange &r, tree type,
 // return the equivalent range for TYPE in R; if FALSE/TRUE, do nothing.
 
 bool_range_state
-get_bool_state (irange &r, const irange &lhs, tree val_type)
+get_bool_state (vrange &r, const vrange &lhs, tree val_type)
 {
   // If there is no result, then this is unexecutable.
   if (lhs.undefined_p ())
@@ -446,6 +446,9 @@ get_bool_state (irange &r, const irange &lhs, tree val_type)
 
 class operator_equal : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -562,6 +565,9 @@ operator_equal::op2_range (irange &r, tree type,
 
 class operator_not_equal : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -738,6 +744,9 @@ build_ge (irange &r, tree type, const wide_int &val)
 
 class operator_lt :  public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -846,6 +855,9 @@ operator_lt::op2_range (irange &r, tree type,
 
 class operator_le :  public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -954,6 +966,9 @@ operator_le::op2_range (irange &r, tree type,
 
 class operator_gt :  public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -1061,6 +1076,9 @@ operator_gt::op2_range (irange &r, tree type,
 
 class operator_ge :  public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -1169,6 +1187,10 @@ operator_ge::op2_range (irange &r, tree type,
 
 class operator_plus : public range_operator
 {
+  using range_operator::op1_range;
+  using range_operator::op2_range;
+  using range_operator::lhs_op1_relation;
+  using range_operator::lhs_op2_relation;
 public:
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
@@ -1286,7 +1308,7 @@ operator_plus::op1_range (irange &r, tree type,
 			  const irange &op2,
 			  relation_kind rel ATTRIBUTE_UNUSED) const
 {
-  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op2);
+  return range_op_handler (MINUS_EXPR, type).fold_range (r, type, lhs, op2);
 }
 
 bool
@@ -1295,12 +1317,15 @@ operator_plus::op2_range (irange &r, tree type,
 			  const irange &op1,
 			  relation_kind rel ATTRIBUTE_UNUSED) const
 {
-  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, lhs, op1);
+  return range_op_handler (MINUS_EXPR, type).fold_range (r, type, lhs, op1);
 }
 
 
 class operator_minus : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
@@ -1445,7 +1470,7 @@ operator_minus::op1_range (irange &r, tree type,
 			   const irange &op2,
 			   relation_kind rel ATTRIBUTE_UNUSED) const
 {
-  return range_op_handler (PLUS_EXPR, type)->fold_range (r, type, lhs, op2);
+  return range_op_handler (PLUS_EXPR, type).fold_range (r, type, lhs, op2);
 }
 
 bool
@@ -1597,6 +1622,8 @@ cross_product_operator::wi_cross_product (irange &r, tree type,
 
 class operator_mult : public cross_product_operator
 {
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual void wi_fold (irange &r, tree type,
 		        const wide_int &lh_lb,
@@ -1629,8 +1656,8 @@ operator_mult::op1_range (irange &r, tree type,
     return false;
 
   if (op2.singleton_p (&offset) && !integer_zerop (offset))
-    return range_op_handler (TRUNC_DIV_EXPR, type)->fold_range (r, type,
-								lhs, op2);
+    return range_op_handler (TRUNC_DIV_EXPR, type).fold_range (r, type,
+							       lhs, op2);
   return false;
 }
 
@@ -1857,6 +1884,7 @@ operator_div op_ceil_div (CEIL_DIV_EXPR);
 
 class operator_exact_divide : public operator_div
 {
+  using range_operator::op1_range;
 public:
   operator_exact_divide () : operator_div (TRUNC_DIV_EXPR) { }
   virtual bool op1_range (irange &r, tree type,
@@ -1881,13 +1909,15 @@ operator_exact_divide::op1_range (irange &r, tree type,
   // If op2 is a multiple of 2, we would be able to set some non-zero bits.
   if (op2.singleton_p (&offset)
       && !integer_zerop (offset))
-    return range_op_handler (MULT_EXPR, type)->fold_range (r, type, lhs, op2);
+    return range_op_handler (MULT_EXPR, type).fold_range (r, type, lhs, op2);
   return false;
 }
 
 
 class operator_lshift : public cross_product_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
 public:
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
@@ -1909,6 +1939,9 @@ public:
 
 class operator_rshift : public cross_product_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::lhs_op1_relation;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -2248,6 +2281,8 @@ operator_rshift::wi_fold (irange &r, tree type,
 
 class operator_cast: public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -2417,10 +2452,9 @@ operator_cast::op1_range (irange &r, tree type,
 	  // Add this to the unsigned LHS range(s).
 	  int_range_max lim_range (type, lim, lim);
 	  int_range_max lhs_neg;
-	  range_op_handler (PLUS_EXPR, type)->fold_range (lhs_neg,
-							  type,
-							  converted_lhs,
-							  lim_range);
+	  range_op_handler (PLUS_EXPR, type).fold_range (lhs_neg, type,
+							 converted_lhs,
+							 lim_range);
 	  // lhs_neg now has all the negative versions of the LHS.
 	  // Now union in all the values from SIGNED MIN (0x80000) to
 	  // lim-1 in order to fill in all the ranges with the upper
@@ -2469,6 +2503,9 @@ operator_cast::op1_range (irange &r, tree type,
 
 class operator_logical_and : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &lh,
@@ -2542,6 +2579,9 @@ operator_logical_and::op2_range (irange &r, tree type,
 
 class operator_bitwise_and : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &lh,
@@ -2988,6 +3028,9 @@ operator_bitwise_and::op2_range (irange &r, tree type,
 
 class operator_logical_or : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &lh,
@@ -3051,6 +3094,8 @@ operator_logical_or::op2_range (irange &r, tree type,
 
 class operator_bitwise_or : public range_operator
 {
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
@@ -3155,6 +3200,8 @@ operator_bitwise_or::op2_range (irange &r, tree type,
 
 class operator_bitwise_xor : public range_operator
 {
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual void wi_fold (irange &r, tree type,
 		        const wide_int &lh_lb,
@@ -3296,6 +3343,8 @@ operator_bitwise_xor::op2_range (irange &r, tree type,
 
 class operator_trunc_mod : public range_operator
 {
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual void wi_fold (irange &r, tree type,
 		        const wide_int &lh_lb,
@@ -3432,6 +3481,8 @@ operator_trunc_mod::op2_range (irange &r, tree type,
 
 class operator_logical_not : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &lh,
@@ -3487,6 +3538,8 @@ operator_logical_not::op1_range (irange &r,
 
 class operator_bitwise_not : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &lh,
@@ -3513,8 +3566,7 @@ operator_bitwise_not::fold_range (irange &r, tree type,
   // ~X is simply -1 - X.
   int_range<1> minusone (type, wi::minus_one (TYPE_PRECISION (type)),
 			 wi::minus_one (TYPE_PRECISION (type)));
-  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type, minusone,
-							  lh);
+  return range_op_handler (MINUS_EXPR, type).fold_range (r, type, minusone, lh);
 }
 
 bool
@@ -3533,6 +3585,7 @@ operator_bitwise_not::op1_range (irange &r, tree type,
 
 class operator_cst : public range_operator
 {
+  using range_operator::fold_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -3553,6 +3606,9 @@ operator_cst::fold_range (irange &r, tree type ATTRIBUTE_UNUSED,
 
 class operator_identity : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::lhs_op1_relation;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -3605,6 +3661,7 @@ operator_identity::op1_range (irange &r, tree type ATTRIBUTE_UNUSED,
 
 class operator_unknown : public range_operator
 {
+  using range_operator::fold_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -3625,6 +3682,7 @@ operator_unknown::fold_range (irange &r, tree type,
 
 class operator_abs : public range_operator
 {
+  using range_operator::op1_range;
  public:
   virtual void wi_fold (irange &r, tree type,
 		        const wide_int &lh_lb,
@@ -3790,6 +3848,8 @@ operator_absu::wi_fold (irange &r, tree type,
 
 class operator_negate : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
  public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -3810,9 +3870,8 @@ operator_negate::fold_range (irange &r, tree type,
   if (empty_range_varying (r, type, lh, rh))
     return true;
   // -X is simply 0 - X.
-  return range_op_handler (MINUS_EXPR, type)->fold_range (r, type,
-							  range_zero (type),
-							  lh);
+  return range_op_handler (MINUS_EXPR, type).fold_range (r, type,
+							 range_zero (type), lh);
 }
 
 bool
@@ -3828,6 +3887,8 @@ operator_negate::op1_range (irange &r, tree type,
 
 class operator_addr_expr : public range_operator
 {
+  using range_operator::fold_range;
+  using range_operator::op1_range;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -3978,6 +4039,8 @@ pointer_and_operator::wi_fold (irange &r, tree type,
 
 class pointer_or_operator : public range_operator
 {
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
@@ -4139,8 +4202,8 @@ pointer_table::pointer_table ()
 
 // The tables are hidden and accessed via a simple extern function.
 
-range_operator *
-range_op_handler (enum tree_code code, tree type)
+static inline range_operator *
+get_handler (enum tree_code code, tree type)
 {
   // First check if there is a pointer specialization.
   if (POINTER_TYPE_P (type))
@@ -4150,16 +4213,120 @@ range_op_handler (enum tree_code code, tree type)
   return NULL;
 }
 
+range_op_handler::range_op_handler (tree_code code, tree type)
+{
+  m_op = get_handler (code, type);
+}
+
+range_op_handler::range_op_handler (const gimple *s)
+{
+  if (const gassign *ass = dyn_cast<const gassign *> (s))
+    {
+      enum tree_code code = gimple_assign_rhs_code (ass);
+      // The LHS of a comparison is always an int, so we must look at
+      // the operands.
+      if (TREE_CODE_CLASS (code) == tcc_comparison)
+	m_op = get_handler (code, TREE_TYPE (gimple_assign_rhs1 (ass)));
+      else
+	m_op = get_handler (code, TREE_TYPE (gimple_assign_lhs (ass)));
+    }
+  else if (const gcond *cond = dyn_cast<const gcond *> (s))
+    m_op = get_handler (gimple_cond_code (cond),
+			TREE_TYPE (gimple_cond_lhs (cond)));
+  else
+    m_op = NULL;
+}
+
+bool
+range_op_handler::fold_range (vrange &r, tree type,
+			      const vrange &lh,
+			      const vrange &rh,
+			      relation_kind rel) const
+{
+  if (is_a <irange> (lh))
+    return m_op->fold_range (as_a <irange> (r), type,
+			     as_a <irange> (lh),
+			     as_a <irange> (rh), rel);
+  gcc_unreachable ();
+  return false;
+}
+
+bool
+range_op_handler::op1_range (vrange &r, tree type,
+			     const vrange &lhs,
+			     const vrange &op2,
+			     relation_kind rel) const
+{
+  if (is_a <irange> (r))
+    return m_op->op1_range (as_a <irange> (r), type,
+			    as_a <irange> (lhs),
+			    as_a <irange> (op2), rel);
+  gcc_unreachable ();
+  return false;
+}
+
+bool
+range_op_handler::op2_range (vrange &r, tree type,
+			     const vrange &lhs,
+			     const vrange &op1,
+			     relation_kind rel) const
+{
+  if (is_a <irange> (r))
+    return m_op->op2_range (as_a <irange> (r), type,
+			    as_a <irange> (lhs),
+			    as_a <irange> (op1), rel);
+  gcc_unreachable ();
+  return false;
+}
+
+relation_kind
+range_op_handler::lhs_op1_relation (const vrange &lhs,
+				    const vrange &op1,
+				    const vrange &op2,
+				    relation_kind rel) const
+{
+  if (is_a <irange> (op1))
+    return m_op->lhs_op1_relation (as_a <irange> (lhs),
+				   as_a <irange> (op1), as_a <irange> (op2), rel);
+  gcc_unreachable ();
+  return VREL_VARYING;
+}
+
+relation_kind
+range_op_handler::lhs_op2_relation (const vrange &lhs,
+				    const vrange &op1,
+				    const vrange &op2,
+				    relation_kind rel) const
+{
+  if (is_a <irange> (op1))
+    return m_op->lhs_op2_relation (as_a <irange> (lhs),
+				   as_a <irange> (op1), as_a <irange> (op2), rel);
+  gcc_unreachable ();
+  return VREL_VARYING;
+}
+
+relation_kind
+range_op_handler::op1_op2_relation (const vrange &lhs) const
+{
+  return m_op->op1_op2_relation (as_a <irange> (lhs));
+}
+
 // Cast the range in R to TYPE.
 
-void
-range_cast (irange &r, tree type)
+bool
+range_cast (vrange &r, tree type)
 {
-  int_range_max tmp = r;
-  range_operator *op = range_op_handler (CONVERT_EXPR, type);
+  Value_Range tmp (r);
+  Value_Range varying (type);
+  varying.set_varying (type);
+  range_op_handler op (CONVERT_EXPR, type);
   // Call op_convert, if it fails, the result is varying.
-  if (!op->fold_range (r, type, tmp, int_range<1> (type)))
-    r.set_varying (type);
+  if (!op || !op.fold_range (r, type, tmp, varying))
+    {
+      r.set_varying (type);
+      return false;
+    }
+  return true;
 }
 
 #if CHECKING_P
diff --git a/gcc/range-op.h b/gcc/range-op.h
index 300974fbb78..262c796180d 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -108,8 +108,39 @@ protected:
 			 const wide_int &rh_ub) const;
 };
 
-extern range_operator *range_op_handler (enum tree_code code, tree type);
-extern void range_cast (irange &, tree type);
+class range_op_handler
+{
+public:
+  range_op_handler (enum tree_code code, tree type);
+  range_op_handler (const gimple *s);
+  operator bool () const { return m_op; }
+
+  bool fold_range (vrange &r, tree type,
+		   const vrange &lh,
+		   const vrange &rh,
+		   relation_kind rel = VREL_VARYING) const;
+  bool op1_range (vrange &r, tree type,
+		  const vrange &lhs,
+		  const vrange &op2,
+		  relation_kind rel = VREL_VARYING) const;
+  bool op2_range (vrange &r, tree type,
+		  const vrange &lhs,
+		  const vrange &op1,
+		  relation_kind rel = VREL_VARYING) const;
+  relation_kind lhs_op1_relation (const vrange &lhs,
+				  const vrange &op1,
+				  const vrange &op2,
+				  relation_kind = VREL_VARYING) const;
+  relation_kind lhs_op2_relation (const vrange &lhs,
+				  const vrange &op1,
+				  const vrange &op2,
+				  relation_kind = VREL_VARYING) const;
+  relation_kind op1_op2_relation (const vrange &lhs) const;
+private:
+  range_operator *m_op;
+};
+
+extern bool range_cast (vrange &, tree type);
 extern void wi_set_zero_nonzero_bits (tree type,
 				      const wide_int &, const wide_int &,
 				      wide_int &maybe_nonzero,
@@ -124,7 +155,7 @@ relation_kind gt_op1_op2_relation (const irange &lhs);
 relation_kind ge_op1_op2_relation (const irange &lhs);
 
 enum bool_range_state { BRS_FALSE, BRS_TRUE, BRS_EMPTY, BRS_FULL };
-bool_range_state get_bool_state (irange &r, const irange &lhs, tree val_type);
+bool_range_state get_bool_state (vrange &r, const vrange &lhs, tree val_type);
 
 // If the range of either op1 or op2 is undefined, set the result to
 // varying and return TRUE.  If the caller truely cares about a result,
@@ -132,8 +163,8 @@ bool_range_state get_bool_state (irange &r, const irange &lhs, tree val_type);
 // treated as a varying.
 
 inline bool
-empty_range_varying (irange &r, tree type,
-		     const irange &op1, const irange & op2)
+empty_range_varying (vrange &r, tree type,
+		     const vrange &op1, const vrange & op2)
 {
   if (op1.undefined_p () || op2.undefined_p ())
     {
@@ -150,8 +181,8 @@ empty_range_varying (irange &r, tree type,
 // return false.
 
 inline bool
-relop_early_resolve (irange &r, tree type, const irange &op1,
-		     const irange &op2, relation_kind rel,
+relop_early_resolve (irange &r, tree type, const vrange &op1,
+		     const vrange &op2, relation_kind rel,
 		     relation_kind my_rel)
 {
   // If known relation is a complete subset of this relation, always true.
diff --git a/gcc/tree-data-ref.cc b/gcc/tree-data-ref.cc
index 397792c3584..ae05fe74b95 100644
--- a/gcc/tree-data-ref.cc
+++ b/gcc/tree-data-ref.cc
@@ -593,8 +593,8 @@ compute_distributive_range (tree type, value_range &op0_range,
   gcc_assert (INTEGRAL_TYPE_P (type) && !TYPE_OVERFLOW_TRAPS (type));
   if (result_range)
     {
-      range_operator *op = range_op_handler (code, type);
-      op->fold_range (*result_range, type, op0_range, op1_range);
+      range_op_handler op (code, type);
+      op.fold_range (*result_range, type, op0_range, op1_range);
     }
 
   /* The distributive property guarantees that if TYPE is no narrower
@@ -639,10 +639,10 @@ compute_distributive_range (tree type, value_range &op0_range,
   range_cast (op0_range, ssizetype);
   range_cast (op1_range, ssizetype);
   value_range wide_range;
-  range_operator *op = range_op_handler (code, ssizetype);
+  range_op_handler op (code, ssizetype);
   bool saved_flag_wrapv = flag_wrapv;
   flag_wrapv = 1;
-  op->fold_range (wide_range, ssizetype, op0_range, op1_range);
+  op.fold_range (wide_range, ssizetype, op0_range, op1_range);
   flag_wrapv = saved_flag_wrapv;
   if (wide_range.num_pairs () != 1 || !range_int_cst_p (&wide_range))
     return false;
diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
index 62ae5a967f3..74277617b66 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -924,20 +924,6 @@ extract_range_from_plus_minus_expr (value_range *vr,
     vr->set (min, max, kind);
 }
 
-/* Return the range-ops handler for CODE and EXPR_TYPE.  If no
-   suitable operator is found, return NULL and set VR to VARYING.  */
-
-static const range_operator *
-get_range_op_handler (value_range *vr,
-		      enum tree_code code,
-		      tree expr_type)
-{
-  const range_operator *op = range_op_handler (code, expr_type);
-  if (!op)
-    vr->set_varying (expr_type);
-  return op;
-}
-
 /* If the types passed are supported, return TRUE, otherwise set VR to
    VARYING and return FALSE.  */
 
@@ -1005,10 +991,12 @@ range_fold_binary_symbolics_p (value_range *vr,
 						&vr0, &vr1);
 	  return true;
 	}
-      const range_operator *op = get_range_op_handler (vr, code, expr_type);
+      range_op_handler op (code, expr_type);
+      if (!op)
+	vr->set_varying (expr_type);
       vr0.normalize_symbolics ();
       vr1.normalize_symbolics ();
-      return op->fold_range (*vr, expr_type, vr0, vr1);
+      return op.fold_range (*vr, expr_type, vr0, vr1);
     }
   return false;
 }
@@ -1040,10 +1028,12 @@ range_fold_unary_symbolics_p (value_range *vr,
 	  range_fold_binary_expr (vr, MINUS_EXPR, expr_type, &minusone, vr0);
 	  return true;
 	}
-      const range_operator *op = get_range_op_handler (vr, code, expr_type);
+      range_op_handler op (code, expr_type);
+      if (!op)
+	vr->set_varying (expr_type);
       value_range vr0_cst (*vr0);
       vr0_cst.normalize_symbolics ();
-      return op->fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
+      return op.fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
     }
   return false;
 }
@@ -1060,9 +1050,12 @@ range_fold_binary_expr (value_range *vr,
   if (!supported_types_p (vr, expr_type)
       || !defined_ranges_p (vr, vr0_, vr1_))
     return;
-  const range_operator *op = get_range_op_handler (vr, code, expr_type);
+  range_op_handler op (code, expr_type);
   if (!op)
-    return;
+    {
+      vr->set_varying (expr_type);
+      return;
+    }
 
   if (range_fold_binary_symbolics_p (vr, code, expr_type, vr0_, vr1_))
     return;
@@ -1075,7 +1068,7 @@ range_fold_binary_expr (value_range *vr,
     vr1.set_varying (expr_type);
   vr0.normalize_addresses ();
   vr1.normalize_addresses ();
-  op->fold_range (*vr, expr_type, vr0, vr1);
+  op.fold_range (*vr, expr_type, vr0, vr1);
 }
 
 /* Perform a unary operation on a range.  */
@@ -1089,16 +1082,19 @@ range_fold_unary_expr (value_range *vr,
   if (!supported_types_p (vr, expr_type, vr0_type)
       || !defined_ranges_p (vr, vr0))
     return;
-  const range_operator *op = get_range_op_handler (vr, code, expr_type);
+  range_op_handler op (code, expr_type);
   if (!op)
-    return;
+    {
+      vr->set_varying (expr_type);
+      return;
+    }
 
   if (range_fold_unary_symbolics_p (vr, code, expr_type, vr0))
     return;
 
   value_range vr0_cst (*vr0);
   vr0_cst.normalize_addresses ();
-  op->fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
+  op.fold_range (*vr, expr_type, vr0_cst, value_range (expr_type));
 }
 
 /* If the range of values taken by OP can be inferred after STMT executes,
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 26e3858103b..31e56eeae53 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -234,13 +234,13 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
     }
   if (BINARY_CLASS_P (expr))
     {
-      range_operator *op = range_op_handler (TREE_CODE (expr), type);
+      range_op_handler op (TREE_CODE (expr), type);
       if (op)
 	{
 	  int_range_max r0, r1;
 	  range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
 	  range_of_expr (r1, TREE_OPERAND (expr, 1), stmt);
-	  op->fold_range (r, type, r0, r1);
+	  op.fold_range (r, type, r0, r1);
 	}
       else
 	r.set_varying (type);
@@ -248,13 +248,13 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
     }
   if (UNARY_CLASS_P (expr))
     {
-      range_operator *op = range_op_handler (TREE_CODE (expr), type);
+      range_op_handler op (TREE_CODE (expr), type);
       tree op0_type = TREE_TYPE (TREE_OPERAND (expr, 0));
       if (op && irange::supports_type_p (op0_type))
 	{
 	  int_range_max r0;
 	  range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
-	  op->fold_range (r, type, r0, int_range<1> (type));
+	  op.fold_range (r, type, r0, int_range<1> (type));
 	}
       else
 	r.set_varying (type);
-- 
2.36.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 4/5] Revamp irange_allocator to handle vranges.
  2022-05-30 13:27 ` [PATCH 4/5] Revamp irange_allocator to handle vranges Aldy Hernandez
@ 2022-06-01  9:02   ` Aldy Hernandez
  0 siblings, 0 replies; 14+ messages in thread
From: Aldy Hernandez @ 2022-06-01  9:02 UTC (permalink / raw)
  To: GCC patches

[-- Attachment #1: Type: text/plain, Size: 19061 bytes --]

Final patch committed.

Re-tested on x86-64 Linux.

On Mon, May 30, 2022 at 3:28 PM Aldy Hernandez <aldyh@redhat.com> wrote:
>
> 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 <typename T> 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 <irange> (some_irange);
>       frange *f = allocator.clone <frange> (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-side-effect.cc (side_effect_manager::get_nonzero):
>         Same.
>         (side_effect_manager::add_range): Same.
>         * gimple-range-side-effect.h (class side_effect_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/gimple-range-cache.cc       | 55 +++++++++++-----------
>  gcc/gimple-range-cache.h        |  4 +-
>  gcc/gimple-range-edge.cc        |  4 +-
>  gcc/gimple-range-edge.h         |  2 +-
>  gcc/gimple-range-side-effect.cc | 13 ++++--
>  gcc/gimple-range-side-effect.h  |  2 +-
>  gcc/value-range.h               | 82 +++++++++++++++++++++------------
>  7 files changed, 96 insertions(+), 66 deletions(-)
>
> diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
> index c726393b380..9c541993fb6 100644
> --- a/gcc/gimple-range-cache.cc
> +++ b/gcc/gimple-range-cache.cc
> @@ -75,7 +75,7 @@ ssa_block_ranges::dump (FILE *f)
>  class sbr_vector : public ssa_block_ranges
>  {
>  public:
> -  sbr_vector (tree t, irange_allocator *allocator);
> +  sbr_vector (tree t, vrange_allocator *allocator);
>
>    virtual bool set_bb_range (const_basic_block bb, const irange &r) override;
>    virtual bool get_bb_range (irange &r, const_basic_block bb) override;
> @@ -86,20 +86,21 @@ protected:
>    int_range<2> m_varying;
>    int_range<2> m_undefined;
>    tree m_type;
> -  irange_allocator *m_irange_allocator;
> +  vrange_allocator *m_range_allocator;
>    void grow ();
>  };
>
>
>  // Initialize a block cache for an ssa_name of type T.
>
> -sbr_vector::sbr_vector (tree t, irange_allocator *allocator)
> +sbr_vector::sbr_vector (tree t, vrange_allocator *allocator)
>  {
>    gcc_checking_assert (TYPE_P (t));
>    m_type = t;
> -  m_irange_allocator = allocator;
> +  m_range_allocator = allocator;
>    m_tab_size = last_basic_block_for_fn (cfun) + 1;
> -  m_tab = (irange **)allocator->get_memory (m_tab_size * sizeof (irange *));
> +  m_tab = static_cast <irange **>
> +    (allocator->alloc (m_tab_size * sizeof (irange *)));
>    memset (m_tab, 0, m_tab_size * sizeof (irange *));
>
>    // Create the cached type range.
> @@ -121,8 +122,8 @@ sbr_vector::grow ()
>    int new_size = inc + curr_bb_size;
>
>    // Allocate new memory, copy the old vector and clear the new space.
> -  irange **t = (irange **)m_irange_allocator->get_memory (new_size
> -                                                         * sizeof (irange *));
> +  irange **t = static_cast <irange **>
> +    (m_range_allocator->alloc (new_size * sizeof (irange *)));
>    memcpy (t, m_tab, m_tab_size * sizeof (irange *));
>    memset (t + m_tab_size, 0, (new_size - m_tab_size) * sizeof (irange *));
>
> @@ -143,7 +144,7 @@ sbr_vector::set_bb_range (const_basic_block bb, const irange &r)
>    else if (r.undefined_p ())
>      m = &m_undefined;
>    else
> -    m = m_irange_allocator->allocate (r);
> +    m = m_range_allocator->clone (r);
>    m_tab[bb->index] = m;
>    return true;
>  }
> @@ -191,14 +192,14 @@ sbr_vector::bb_range_p (const_basic_block bb)
>  class sbr_sparse_bitmap : public ssa_block_ranges
>  {
>  public:
> -  sbr_sparse_bitmap (tree t, irange_allocator *allocator, bitmap_obstack *bm);
> +  sbr_sparse_bitmap (tree t, vrange_allocator *allocator, bitmap_obstack *bm);
>    virtual bool set_bb_range (const_basic_block bb, const irange &r) override;
>    virtual bool get_bb_range (irange &r, const_basic_block bb) override;
>    virtual bool bb_range_p (const_basic_block bb) override;
>  private:
>    void bitmap_set_quad (bitmap head, int quad, int quad_value);
>    int bitmap_get_quad (const_bitmap head, int quad);
> -  irange_allocator *m_irange_allocator;
> +  vrange_allocator *m_range_allocator;
>    irange *m_range[SBR_NUM];
>    bitmap_head bitvec;
>    tree m_type;
> @@ -206,23 +207,25 @@ private:
>
>  // Initialize a block cache for an ssa_name of type T.
>
> -sbr_sparse_bitmap::sbr_sparse_bitmap (tree t, irange_allocator *allocator,
> -                               bitmap_obstack *bm)
> +sbr_sparse_bitmap::sbr_sparse_bitmap (tree t, vrange_allocator *allocator,
> +                                     bitmap_obstack *bm)
>  {
>    gcc_checking_assert (TYPE_P (t));
>    m_type = t;
>    bitmap_initialize (&bitvec, bm);
>    bitmap_tree_view (&bitvec);
> -  m_irange_allocator = allocator;
> +  m_range_allocator = allocator;
>    // Pre-cache varying.
> -  m_range[0] = m_irange_allocator->allocate (2);
> +  m_range[0] = static_cast <irange *> (m_range_allocator->alloc_vrange (t));
>    m_range[0]->set_varying (t);
>    // Pre-cache zero and non-zero values for pointers.
>    if (POINTER_TYPE_P (t))
>      {
> -      m_range[1] = m_irange_allocator->allocate (2);
> +      m_range[1]
> +       = static_cast <irange *> (m_range_allocator->alloc_vrange (t));
>        m_range[1]->set_nonzero (t);
> -      m_range[2] = m_irange_allocator->allocate (2);
> +      m_range[2]
> +       = static_cast <irange *> (m_range_allocator->alloc_vrange (t));
>        m_range[2]->set_zero (t);
>      }
>    else
> @@ -267,7 +270,7 @@ sbr_sparse_bitmap::set_bb_range (const_basic_block bb, const irange &r)
>      if (!m_range[x] || r == *(m_range[x]))
>        {
>         if (!m_range[x])
> -         m_range[x] = m_irange_allocator->allocate (r);
> +         m_range[x] = m_range_allocator->clone (r);
>         bitmap_set_quad (&bitvec, bb->index, x + 1);
>         return true;
>        }
> @@ -312,14 +315,14 @@ block_range_cache::block_range_cache ()
>    bitmap_obstack_initialize (&m_bitmaps);
>    m_ssa_ranges.create (0);
>    m_ssa_ranges.safe_grow_cleared (num_ssa_names);
> -  m_irange_allocator = new irange_allocator;
> +  m_range_allocator = new vrange_allocator;
>  }
>
>  // Remove any m_block_caches which have been created.
>
>  block_range_cache::~block_range_cache ()
>  {
> -  delete m_irange_allocator;
> +  delete m_range_allocator;
>    // Release the vector itself.
>    m_ssa_ranges.release ();
>    bitmap_obstack_release (&m_bitmaps);
> @@ -341,17 +344,17 @@ block_range_cache::set_bb_range (tree name, const_basic_block bb,
>        // Use sparse representation if there are too many basic blocks.
>        if (last_basic_block_for_fn (cfun) > param_evrp_sparse_threshold)
>         {
> -         void *r = m_irange_allocator->get_memory (sizeof (sbr_sparse_bitmap));
> +         void *r = m_range_allocator->alloc (sizeof (sbr_sparse_bitmap));
>           m_ssa_ranges[v] = new (r) sbr_sparse_bitmap (TREE_TYPE (name),
> -                                                      m_irange_allocator,
> +                                                      m_range_allocator,
>                                                        &m_bitmaps);
>         }
>        else
>         {
>           // Otherwise use the default vector implemntation.
> -         void *r = m_irange_allocator->get_memory (sizeof (sbr_vector));
> +         void *r = m_range_allocator->alloc (sizeof (sbr_vector));
>           m_ssa_ranges[v] = new (r) sbr_vector (TREE_TYPE (name),
> -                                               m_irange_allocator);
> +                                               m_range_allocator);
>         }
>      }
>    return m_ssa_ranges[v]->set_bb_range (bb, r);
> @@ -467,7 +470,7 @@ block_range_cache::dump (FILE *f, basic_block bb, bool print_varying)
>  ssa_global_cache::ssa_global_cache ()
>  {
>    m_tab.create (0);
> -  m_irange_allocator = new irange_allocator;
> +  m_range_allocator = new vrange_allocator;
>  }
>
>  // Deconstruct a global cache.
> @@ -475,7 +478,7 @@ ssa_global_cache::ssa_global_cache ()
>  ssa_global_cache::~ssa_global_cache ()
>  {
>    m_tab.release ();
> -  delete m_irange_allocator;
> +  delete m_range_allocator;
>  }
>
>  // Retrieve the global range of NAME from cache memory if it exists.
> @@ -509,7 +512,7 @@ ssa_global_cache::set_global_range (tree name, const irange &r)
>    if (m && m->fits_p (r))
>      *m = r;
>    else
> -    m_tab[v] = m_irange_allocator->allocate (r);
> +    m_tab[v] = m_range_allocator->clone (r);
>    return m != NULL;
>  }
>
> diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h
> index 555fe32513f..2472cd04f47 100644
> --- a/gcc/gimple-range-cache.h
> +++ b/gcc/gimple-range-cache.h
> @@ -44,7 +44,7 @@ private:
>    vec<class ssa_block_ranges *> m_ssa_ranges;
>    ssa_block_ranges &get_block_ranges (tree name);
>    ssa_block_ranges *query_block_ranges (tree name);
> -  irange_allocator *m_irange_allocator;
> +  vrange_allocator *m_range_allocator;
>    bitmap_obstack m_bitmaps;
>  };
>
> @@ -64,7 +64,7 @@ public:
>    void dump (FILE *f = stderr);
>  private:
>    vec<irange *> m_tab;
> -  class irange_allocator *m_irange_allocator;
> +  vrange_allocator *m_range_allocator;
>  };
>
>  // This class provides all the caches a global ranger may need, and makes
> diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc
> index 5bbe23ae03d..5264e627c9a 100644
> --- a/gcc/gimple-range-edge.cc
> +++ b/gcc/gimple-range-edge.cc
> @@ -166,13 +166,13 @@ gimple_outgoing_range::calc_switch_ranges (gswitch *sw)
>        // If there was an existing range and it doesn't fit, we lose the memory.
>        // It'll get reclaimed when the obstack is freed.  This seems less
>        // intrusive than allocating max ranges for each case.
> -      slot = m_range_allocator.allocate (case_range);
> +      slot = m_range_allocator.clone <irange> (case_range);
>      }
>
>    irange *&slot = m_edge_table->get_or_insert (default_edge, &existed);
>    // This should be the first call into this switch.
>    gcc_checking_assert (!existed);
> -  irange *dr = m_range_allocator.allocate (default_range);
> +  irange *dr = m_range_allocator.clone <irange> (default_range);
>    slot = dr;
>  }
>
> diff --git a/gcc/gimple-range-edge.h b/gcc/gimple-range-edge.h
> index c131b3309cc..ce383b0aa6f 100644
> --- a/gcc/gimple-range-edge.h
> +++ b/gcc/gimple-range-edge.h
> @@ -47,7 +47,7 @@ private:
>
>    int m_max_edges;
>    hash_map<edge, irange *> *m_edge_table;
> -  irange_allocator m_range_allocator;
> +  vrange_allocator m_range_allocator;
>  };
>
>  // If there is a range control statement at the end of block BB, return it.
> diff --git a/gcc/gimple-range-side-effect.cc b/gcc/gimple-range-side-effect.cc
> index 2c8c77dc569..8d2ac35bc8d 100644
> --- a/gcc/gimple-range-side-effect.cc
> +++ b/gcc/gimple-range-side-effect.cc
> @@ -189,8 +189,10 @@ side_effect_manager::get_nonzero (tree name)
>      m_nonzero.safe_grow_cleared (num_ssa_names + 20);
>    if (!m_nonzero[v])
>      {
> -      m_nonzero[v] = m_range_allocator.allocate (2);
> -      m_nonzero[v]->set_nonzero (TREE_TYPE (name));
> +      tree type = TREE_TYPE (name);
> +      m_nonzero[v]
> +       = static_cast <irange *> (m_range_allocator.alloc_vrange (type));
> +      m_nonzero[v]->set_nonzero (type);
>      }
>    return *(m_nonzero[v]);
>  }
> @@ -259,14 +261,17 @@ side_effect_manager::add_range (tree name, basic_block bb, const irange &r)
>        if (ptr->range->fits_p (cur))
>         *(ptr->range) = cur;
>        else
> -       ptr->range = m_range_allocator.allocate (cur);
> +       {
> +         vrange &v = cur;
> +         ptr->range = static_cast <irange *> (m_range_allocator.clone (v));
> +       }
>        return;
>      }
>
>    // Otherwise create a record.
>    bitmap_set_bit (m_on_exit[bb->index].m_names, SSA_NAME_VERSION (name));
>    ptr = (exit_range *)obstack_alloc (&m_list_obstack, sizeof (exit_range));
> -  ptr->range = m_range_allocator.allocate (r);
> +  ptr->range = m_range_allocator.clone (r);
>    ptr->name = name;
>    ptr->next = m_on_exit[bb->index].head;
>    m_on_exit[bb->index].head = ptr;
> diff --git a/gcc/gimple-range-side-effect.h b/gcc/gimple-range-side-effect.h
> index 848d94ba6d7..d76d6eb34f2 100644
> --- a/gcc/gimple-range-side-effect.h
> +++ b/gcc/gimple-range-side-effect.h
> @@ -76,7 +76,7 @@ private:
>    bitmap m_seen;
>    bitmap_obstack m_bitmaps;
>    struct obstack m_list_obstack;
> -  irange_allocator m_range_allocator;
> +  vrange_allocator m_range_allocator;
>  };
>
>  #endif // GCC_GIMPLE_RANGE_SIDE_H
> diff --git a/gcc/value-range.h b/gcc/value-range.h
> index d51998145da..a5da53f595e 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;
> @@ -892,56 +892,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 <typename T> 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.
> @@ -951,17 +958,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 <tree *> (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 <irange> (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 <vrange> (const vrange &src)
> +{
> +  if (is_a <irange> (src))
> +    return clone <irange> (as_a <irange> (src));
> +
> +  gcc_unreachable ();
> +}
> +
>  #endif // GCC_VALUE_RANGE_H
> --
> 2.36.1
>

[-- Attachment #2: 0004-Revamp-irange_allocator-to-handle-vranges.patch --]
[-- Type: text/x-patch, Size: 17461 bytes --]

From f1c2ed68bf1af43bb836b91fa7a5f13b0ccd8006 Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <aldyh@redhat.com>
Date: Sun, 22 May 2022 20:17:39 +0200
Subject: [PATCH] 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 <typename T> 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 <irange> (some_irange);
      frange *f = allocator.clone <frange> (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-side-effect.cc (side_effect_manager::get_nonzero):
	Same.
	(side_effect_manager::add_range): Same.
	* gimple-range-side-effect.h (class side_effect_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/gimple-range-cache.cc | 55 +++++++++++++-------------
 gcc/gimple-range-cache.h  |  4 +-
 gcc/gimple-range-edge.cc  |  4 +-
 gcc/gimple-range-edge.h   |  2 +-
 gcc/gimple-range-infer.cc | 13 +++++--
 gcc/gimple-range-infer.h  |  2 +-
 gcc/value-range.h         | 82 +++++++++++++++++++++++++--------------
 7 files changed, 96 insertions(+), 66 deletions(-)

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 6e73ac706ac..25ade1300af 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -75,7 +75,7 @@ ssa_block_ranges::dump (FILE *f)
 class sbr_vector : public ssa_block_ranges
 {
 public:
-  sbr_vector (tree t, irange_allocator *allocator);
+  sbr_vector (tree t, vrange_allocator *allocator);
 
   virtual bool set_bb_range (const_basic_block bb, const irange &r) override;
   virtual bool get_bb_range (irange &r, const_basic_block bb) override;
@@ -86,20 +86,21 @@ protected:
   int_range<2> m_varying;
   int_range<2> m_undefined;
   tree m_type;
-  irange_allocator *m_irange_allocator;
+  vrange_allocator *m_range_allocator;
   void grow ();
 };
 
 
 // Initialize a block cache for an ssa_name of type T.
 
-sbr_vector::sbr_vector (tree t, irange_allocator *allocator)
+sbr_vector::sbr_vector (tree t, vrange_allocator *allocator)
 {
   gcc_checking_assert (TYPE_P (t));
   m_type = t;
-  m_irange_allocator = allocator;
+  m_range_allocator = allocator;
   m_tab_size = last_basic_block_for_fn (cfun) + 1;
-  m_tab = (irange **)allocator->get_memory (m_tab_size * sizeof (irange *));
+  m_tab = static_cast <irange **>
+    (allocator->alloc (m_tab_size * sizeof (irange *)));
   memset (m_tab, 0, m_tab_size * sizeof (irange *));
 
   // Create the cached type range.
@@ -121,8 +122,8 @@ sbr_vector::grow ()
   int new_size = inc + curr_bb_size;
 
   // Allocate new memory, copy the old vector and clear the new space.
-  irange **t = (irange **)m_irange_allocator->get_memory (new_size
-							  * sizeof (irange *));
+  irange **t = static_cast <irange **>
+    (m_range_allocator->alloc (new_size * sizeof (irange *)));
   memcpy (t, m_tab, m_tab_size * sizeof (irange *));
   memset (t + m_tab_size, 0, (new_size - m_tab_size) * sizeof (irange *));
 
@@ -143,7 +144,7 @@ sbr_vector::set_bb_range (const_basic_block bb, const irange &r)
   else if (r.undefined_p ())
     m = &m_undefined;
   else
-    m = m_irange_allocator->allocate (r);
+    m = m_range_allocator->clone (r);
   m_tab[bb->index] = m;
   return true;
 }
@@ -191,14 +192,14 @@ sbr_vector::bb_range_p (const_basic_block bb)
 class sbr_sparse_bitmap : public ssa_block_ranges
 {
 public:
-  sbr_sparse_bitmap (tree t, irange_allocator *allocator, bitmap_obstack *bm);
+  sbr_sparse_bitmap (tree t, vrange_allocator *allocator, bitmap_obstack *bm);
   virtual bool set_bb_range (const_basic_block bb, const irange &r) override;
   virtual bool get_bb_range (irange &r, const_basic_block bb) override;
   virtual bool bb_range_p (const_basic_block bb) override;
 private:
   void bitmap_set_quad (bitmap head, int quad, int quad_value);
   int bitmap_get_quad (const_bitmap head, int quad);
-  irange_allocator *m_irange_allocator;
+  vrange_allocator *m_range_allocator;
   irange *m_range[SBR_NUM];
   bitmap_head bitvec;
   tree m_type;
@@ -206,23 +207,25 @@ private:
 
 // Initialize a block cache for an ssa_name of type T.
 
-sbr_sparse_bitmap::sbr_sparse_bitmap (tree t, irange_allocator *allocator,
-				bitmap_obstack *bm)
+sbr_sparse_bitmap::sbr_sparse_bitmap (tree t, vrange_allocator *allocator,
+				      bitmap_obstack *bm)
 {
   gcc_checking_assert (TYPE_P (t));
   m_type = t;
   bitmap_initialize (&bitvec, bm);
   bitmap_tree_view (&bitvec);
-  m_irange_allocator = allocator;
+  m_range_allocator = allocator;
   // Pre-cache varying.
-  m_range[0] = m_irange_allocator->allocate (2);
+  m_range[0] = static_cast <irange *> (m_range_allocator->alloc_vrange (t));
   m_range[0]->set_varying (t);
   // Pre-cache zero and non-zero values for pointers.
   if (POINTER_TYPE_P (t))
     {
-      m_range[1] = m_irange_allocator->allocate (2);
+      m_range[1]
+	= static_cast <irange *> (m_range_allocator->alloc_vrange (t));
       m_range[1]->set_nonzero (t);
-      m_range[2] = m_irange_allocator->allocate (2);
+      m_range[2]
+	= static_cast <irange *> (m_range_allocator->alloc_vrange (t));
       m_range[2]->set_zero (t);
     }
   else
@@ -267,7 +270,7 @@ sbr_sparse_bitmap::set_bb_range (const_basic_block bb, const irange &r)
     if (!m_range[x] || r == *(m_range[x]))
       {
 	if (!m_range[x])
-	  m_range[x] = m_irange_allocator->allocate (r);
+	  m_range[x] = m_range_allocator->clone (r);
 	bitmap_set_quad (&bitvec, bb->index, x + 1);
 	return true;
       }
@@ -312,14 +315,14 @@ block_range_cache::block_range_cache ()
   bitmap_obstack_initialize (&m_bitmaps);
   m_ssa_ranges.create (0);
   m_ssa_ranges.safe_grow_cleared (num_ssa_names);
-  m_irange_allocator = new irange_allocator;
+  m_range_allocator = new vrange_allocator;
 }
 
 // Remove any m_block_caches which have been created.
 
 block_range_cache::~block_range_cache ()
 {
-  delete m_irange_allocator;
+  delete m_range_allocator;
   // Release the vector itself.
   m_ssa_ranges.release ();
   bitmap_obstack_release (&m_bitmaps);
@@ -341,17 +344,17 @@ block_range_cache::set_bb_range (tree name, const_basic_block bb,
       // Use sparse representation if there are too many basic blocks.
       if (last_basic_block_for_fn (cfun) > param_evrp_sparse_threshold)
 	{
-	  void *r = m_irange_allocator->get_memory (sizeof (sbr_sparse_bitmap));
+	  void *r = m_range_allocator->alloc (sizeof (sbr_sparse_bitmap));
 	  m_ssa_ranges[v] = new (r) sbr_sparse_bitmap (TREE_TYPE (name),
-						       m_irange_allocator,
+						       m_range_allocator,
 						       &m_bitmaps);
 	}
       else
 	{
 	  // Otherwise use the default vector implemntation.
-	  void *r = m_irange_allocator->get_memory (sizeof (sbr_vector));
+	  void *r = m_range_allocator->alloc (sizeof (sbr_vector));
 	  m_ssa_ranges[v] = new (r) sbr_vector (TREE_TYPE (name),
-						m_irange_allocator);
+						m_range_allocator);
 	}
     }
   return m_ssa_ranges[v]->set_bb_range (bb, r);
@@ -467,7 +470,7 @@ block_range_cache::dump (FILE *f, basic_block bb, bool print_varying)
 ssa_global_cache::ssa_global_cache ()
 {
   m_tab.create (0);
-  m_irange_allocator = new irange_allocator;
+  m_range_allocator = new vrange_allocator;
 }
 
 // Deconstruct a global cache.
@@ -475,7 +478,7 @@ ssa_global_cache::ssa_global_cache ()
 ssa_global_cache::~ssa_global_cache ()
 {
   m_tab.release ();
-  delete m_irange_allocator;
+  delete m_range_allocator;
 }
 
 // Retrieve the global range of NAME from cache memory if it exists. 
@@ -509,7 +512,7 @@ ssa_global_cache::set_global_range (tree name, const irange &r)
   if (m && m->fits_p (r))
     *m = r;
   else
-    m_tab[v] = m_irange_allocator->allocate (r);
+    m_tab[v] = m_range_allocator->clone (r);
   return m != NULL;
 }
 
diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h
index d56e56c201c..73d12f35abe 100644
--- a/gcc/gimple-range-cache.h
+++ b/gcc/gimple-range-cache.h
@@ -44,7 +44,7 @@ private:
   vec<class ssa_block_ranges *> m_ssa_ranges;
   ssa_block_ranges &get_block_ranges (tree name);
   ssa_block_ranges *query_block_ranges (tree name);
-  irange_allocator *m_irange_allocator;
+  vrange_allocator *m_range_allocator;
   bitmap_obstack m_bitmaps;
 };
 
@@ -64,7 +64,7 @@ public:
   void dump (FILE *f = stderr);
 private:
   vec<irange *> m_tab;
-  class irange_allocator *m_irange_allocator;
+  vrange_allocator *m_range_allocator;
 };
 
 // This class provides all the caches a global ranger may need, and makes 
diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc
index 5bbe23ae03d..5264e627c9a 100644
--- a/gcc/gimple-range-edge.cc
+++ b/gcc/gimple-range-edge.cc
@@ -166,13 +166,13 @@ gimple_outgoing_range::calc_switch_ranges (gswitch *sw)
       // If there was an existing range and it doesn't fit, we lose the memory.
       // It'll get reclaimed when the obstack is freed.  This seems less
       // intrusive than allocating max ranges for each case.
-      slot = m_range_allocator.allocate (case_range);
+      slot = m_range_allocator.clone <irange> (case_range);
     }
 
   irange *&slot = m_edge_table->get_or_insert (default_edge, &existed);
   // This should be the first call into this switch.
   gcc_checking_assert (!existed);
-  irange *dr = m_range_allocator.allocate (default_range);
+  irange *dr = m_range_allocator.clone <irange> (default_range);
   slot = dr;
 }
 
diff --git a/gcc/gimple-range-edge.h b/gcc/gimple-range-edge.h
index c131b3309cc..ce383b0aa6f 100644
--- a/gcc/gimple-range-edge.h
+++ b/gcc/gimple-range-edge.h
@@ -47,7 +47,7 @@ private:
 
   int m_max_edges;
   hash_map<edge, irange *> *m_edge_table;
-  irange_allocator m_range_allocator;
+  vrange_allocator m_range_allocator;
 };
 
 // If there is a range control statement at the end of block BB, return it.
diff --git a/gcc/gimple-range-infer.cc b/gcc/gimple-range-infer.cc
index 545d4f2de3d..14ddfb803d8 100644
--- a/gcc/gimple-range-infer.cc
+++ b/gcc/gimple-range-infer.cc
@@ -189,8 +189,10 @@ infer_range_manager::get_nonzero (tree name)
     m_nonzero.safe_grow_cleared (num_ssa_names + 20);
   if (!m_nonzero[v])
     {
-      m_nonzero[v] = m_range_allocator.allocate (2);
-      m_nonzero[v]->set_nonzero (TREE_TYPE (name));
+      tree type = TREE_TYPE (name);
+      m_nonzero[v]
+	= static_cast <irange *> (m_range_allocator.alloc_vrange (type));
+      m_nonzero[v]->set_nonzero (type);
     }
   return *(m_nonzero[v]);
 }
@@ -259,14 +261,17 @@ infer_range_manager::add_range (tree name, basic_block bb, const irange &r)
       if (ptr->range->fits_p (cur))
 	*(ptr->range) = cur;
       else
-	ptr->range = m_range_allocator.allocate (cur);
+	{
+	  vrange &v = cur;
+	  ptr->range = static_cast <irange *> (m_range_allocator.clone (v));
+	}
       return;
     }
 
   // Otherwise create a record.
   bitmap_set_bit (m_on_exit[bb->index].m_names, SSA_NAME_VERSION (name));
   ptr = (exit_range *)obstack_alloc (&m_list_obstack, sizeof (exit_range));
-  ptr->range = m_range_allocator.allocate (r);
+  ptr->range = m_range_allocator.clone (r);
   ptr->name = name;
   ptr->next = m_on_exit[bb->index].head;
   m_on_exit[bb->index].head = ptr;
diff --git a/gcc/gimple-range-infer.h b/gcc/gimple-range-infer.h
index 412958fe28e..65f6e83809d 100644
--- a/gcc/gimple-range-infer.h
+++ b/gcc/gimple-range-infer.h
@@ -78,7 +78,7 @@ private:
   bitmap m_seen;
   bitmap_obstack m_bitmaps;
   struct obstack m_list_obstack;
-  irange_allocator m_range_allocator;
+  vrange_allocator m_range_allocator;
 };
 
 #endif // GCC_GIMPLE_RANGE_SIDE_H
diff --git a/gcc/value-range.h b/gcc/value-range.h
index b7ea8c76f87..5cd0e0ef76a 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 <typename T> 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 <tree *> (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 <irange> (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 <vrange> (const vrange &src)
+{
+  if (is_a <irange> (src))
+    return clone <irange> (as_a <irange> (src));
+
+  gcc_unreachable ();
+}
+
 #endif // GCC_VALUE_RANGE_H
-- 
2.36.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/5] Convert ranger and clients to vrange.
  2022-05-30 13:27 ` [PATCH 5/5] Convert ranger and clients to vrange Aldy Hernandez
@ 2022-06-01  9:04   ` Aldy Hernandez
  2022-06-27  0:33     ` Xi Ruoyao
  0 siblings, 1 reply; 14+ messages in thread
From: Aldy Hernandez @ 2022-06-01  9:04 UTC (permalink / raw)
  To: GCC patches

[-- Attachment #1: Type: text/plain, Size: 117785 bytes --]

Final patch committed.

All users but one of Value_Range::set_type() have been removed in
favor of using a constructor taking a type.   We still need to delay
initialization for one use in gimple_infer_range, as it has an array
of temporaries for which the type is not known until later.

Re-tested on x86-64 Linux.

On Mon, May 30, 2022 at 3:28 PM Aldy Hernandez <aldyh@redhat.com> wrote:
>
> Finally, the meat of the work.  Convert ranger and associated clients
> to vrange.
>
> Everything's relatively mechanical given the previous patches.  I did
> include a minor cleanup in the edge code.  There's no need to check
> that the type of the switch is an integer as non-integer switches are
> invalid.  I verified this with an appropriately coded assert.
>
> Tested on x86-64 & ppc64le Linux.
>
> gcc/ChangeLog:
>
>         * gimple-range-cache.cc (ssa_block_ranges::dump): Convert to vrange.
>         (sbr_vector::sbr_vector): Same.
>         (sbr_vector::grow): Same.
>         (sbr_vector::set_bb_range): Same.
>         (sbr_vector::get_bb_range): Same.
>         (sbr_sparse_bitmap::sbr_sparse_bitmap): Same.
>         (sbr_sparse_bitmap::set_bb_range): Same.
>         (sbr_sparse_bitmap::get_bb_range): Same.
>         (block_range_cache::set_bb_range): Same.
>         (block_range_cache::get_bb_range): Same.
>         (block_range_cache::dump): Same.
>         (ssa_global_cache::get_global_range): Same.
>         (ssa_global_cache::set_global_range): Same.
>         (ssa_global_cache::clear): Same.
>         (ssa_global_cache::dump): Same.
>         (ranger_cache::get_global_range): Same.
>         (ranger_cache::set_global_range): Same.
>         (ranger_cache::range_of_def): Same.
>         (ranger_cache::entry_range): Same.
>         (ranger_cache::exit_range): Same.
>         (ranger_cache::edge_range): Same.
>         (ranger_cache::range_of_expr): Same.
>         (ranger_cache::range_on_edge): Same.
>         (ranger_cache::block_range): Same.
>         (ranger_cache::propagate_cache): Same.
>         (ranger_cache::fill_block_cache): Same.
>         (ranger_cache::range_from_dom): Same.
>         * gimple-range-cache.h: Same.
>         * gimple-range-edge.cc (gimple_outgoing_range::get_edge_range):
>         Same.
>         (gimple_outgoing_range::switch_edge_range): Same.
>         (gimple_outgoing_range::edge_range_p): Same.
>         * gimple-range-edge.h: Same.
>         * gimple-range-fold.cc (fur_source::get_operand): Same.
>         (fur_source::get_phi_operand): Same.
>         (fur_edge::get_operand): Same.
>         (fur_edge::get_phi_operand): Same.
>         (fur_stmt::get_operand): Same.
>         (fur_stmt::get_phi_operand): Same.
>         (fur_list::fur_list): Same.
>         (fur_list::get_operand): Same.
>         (fur_list::get_phi_operand): Same.
>         (fold_range): Same.
>         (adjust_imagpart_expr): Same.
>         (adjust_realpart_expr): Same.
>         (gimple_range_adjustment): Same.
>         (fold_using_range::fold_stmt): Same.
>         (fold_using_range::range_of_range_op): Same.
>         (fold_using_range::range_of_address): Same.
>         (fold_using_range::range_of_phi): Same.
>         (fold_using_range::range_of_call): Same.
>         (fold_using_range::range_of_builtin_call): Same.
>         (fold_using_range::range_of_builtin_int_call): Same.
>         (fold_using_range::range_of_cond_expr): Same.
>         (fur_source::register_outgoing_edges): Same.
>         * gimple-range-fold.h (fold_range): Same.
>         (gimple_range_type): Same.
>         (gimple_range_ssa_p): Same.
>         * gimple-range-gori.cc (gimple_range_calc_op1): Same.
>         (gimple_range_calc_op2): Same.
>         (gori_compute::compute_operand_range_switch): Same.
>         (gori_compute::compute_operand_range): Same.
>         (gori_compute::logical_combine): Same.
>         (gori_compute::compute_logical_operands): Same.
>         (gori_compute::compute_operand1_range): Same.
>         (gori_compute::compute_operand2_range): Same.
>         (gori_compute::compute_operand1_and_operand2_range): Same.
>         (gori_compute::outgoing_edge_range_p): Same.
>         (gori_compute::condexpr_adjust): Same.
>         * gimple-range-gori.h (gimple_range_calc_op1): Same.
>         (gimple_range_calc_op2): Same.
>         * gimple-range-path.cc (path_range_query::get_cache): Same.
>         (path_range_query::set_cache): Same.
>         (path_range_query::range_on_path_entry): Same.
>         (path_range_query::internal_range_of_expr): Same.
>         (path_range_query::range_of_expr): Same.
>         (path_range_query::ssa_range_in_phi): Same.
>         (path_range_query::range_defined_in_block): Same.
>         (path_range_query::compute_ranges_in_phis): Same.
>         (path_range_query::compute_ranges_in_block): Same.
>         (path_range_query::add_to_imports): Same.
>         (path_range_query::range_of_stmt): Same.
>         * gimple-range-path.h: Same.
>         * gimple-range-side-effect.cc (stmt_side_effects::add_range): Same.
>         (side_effect_manager::~side_effect_manager): Same.
>         (side_effect_manager::get_nonzero): Same.
>         (side_effect_manager::maybe_adjust_range): Same.
>         (side_effect_manager::add_range): Same.
>         * gimple-range-side-effect.h: Same.
>         * gimple-range-tests.cc: Same.
>         * gimple-range-trace.cc (range_tracer::trailer): Same.
>         (debug_seed_ranger): Same.
>         * gimple-range-trace.h: Same.
>         * gimple-range.cc (gimple_ranger::range_of_expr): Same.
>         (gimple_ranger::range_on_entry): Same.
>         (gimple_ranger::range_on_exit): Same.
>         (gimple_ranger::range_on_edge): Same.
>         (gimple_ranger::fold_range_internal): Same.
>         (gimple_ranger::range_of_stmt): Same.
>         (gimple_ranger::prefill_name): Same.
>         (gimple_ranger::prefill_stmt_dependencies): Same.
>         (gimple_ranger::export_global_ranges): Same.
>         (gimple_ranger::dump_bb): Same.
>         * gimple-range.h: Same.
>         * gimple-ssa-warn-access.cc (check_nul_terminated_array): Same.
>         (memmodel_to_uhwi): Same.
>         * tree-ssa-loop-niter.cc (refine_value_range_using_guard): Same.
>         (determine_value_range): Same.
>         (record_nonwrapping_iv): Same.
>         (infer_loop_bounds_from_signedness): Same.
>         (scev_var_range_cant_overflow): Same.
>         * tree-ssa-threadedge.cc (hybrid_jt_simplifier::simplify): Same.
>         * value-query.cc (range_query::range_on_edge): Same.
>         (range_query::range_of_stmt): Same.
>         (range_query::value_of_expr): Same.
>         (range_query::value_on_edge): Same.
>         (range_query::value_of_stmt): Same.
>         (range_query::get_tree_range): Same.
>         (update_global_range): Same.
>         (get_range_global): Same.
>         (gimple_range_global): Same.
>         (global_range_query::range_of_expr): Same.
>         (range_query::query_relation): Same.
>         * value-query.h (gimple_range_global): Same.
>         (update_global_range): Same.
>         * vr-values.cc (vr_values::range_of_expr): Same.
>         (bounds_of_var_in_loop): Same.
>         (simplify_using_ranges::vrp_visit_cond_stmt): Same.
>         * vr-values.h (class vr_values): Same.
> ---
>  gcc/gimple-range-cache.cc       | 136 ++++++++++++++++--------------
>  gcc/gimple-range-cache.h        |  32 +++----
>  gcc/gimple-range-edge.cc        |  12 +--
>  gcc/gimple-range-edge.h         |   2 +-
>  gcc/gimple-range-fold.cc        | 144 +++++++++++++++++++-------------
>  gcc/gimple-range-fold.h         |  37 ++++----
>  gcc/gimple-range-gori.cc        | 116 ++++++++++++++-----------
>  gcc/gimple-range-gori.h         |  42 +++++-----
>  gcc/gimple-range-path.cc        |  47 ++++++-----
>  gcc/gimple-range-path.h         |  16 ++--
>  gcc/gimple-range-side-effect.cc |  20 ++---
>  gcc/gimple-range-side-effect.h  |  14 ++--
>  gcc/gimple-range-tests.cc       |   3 +-
>  gcc/gimple-range-trace.cc       |   9 +-
>  gcc/gimple-range-trace.h        |   2 +-
>  gcc/gimple-range.cc             |  44 ++++++----
>  gcc/gimple-range.h              |  14 ++--
>  gcc/gimple-ssa-warn-access.cc   |   7 +-
>  gcc/tree-ssa-loop-niter.cc      |  16 ++--
>  gcc/tree-ssa-threadedge.cc      |   4 +-
>  gcc/value-query.cc              |  73 ++++++++--------
>  gcc/value-query.h               |  16 ++--
>  gcc/vr-values.cc                |  29 ++++---
>  gcc/vr-values.h                 |   2 +-
>  24 files changed, 457 insertions(+), 380 deletions(-)
>
> diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
> index 9c541993fb6..4983e4d3aa7 100644
> --- a/gcc/gimple-range-cache.cc
> +++ b/gcc/gimple-range-cache.cc
> @@ -44,11 +44,14 @@ along with GCC; see the file COPYING3.  If not see
>  class ssa_block_ranges
>  {
>  public:
> -  virtual bool set_bb_range (const_basic_block bb, const irange &r) = 0;
> -  virtual bool get_bb_range (irange &r, const_basic_block bb) = 0;
> +  ssa_block_ranges (tree t) : m_type (t) { }
> +  virtual bool set_bb_range (const_basic_block bb, const vrange &r) = 0;
> +  virtual bool get_bb_range (vrange &r, const_basic_block bb) = 0;
>    virtual bool bb_range_p (const_basic_block bb) = 0;
>
>    void dump(FILE *f);
> +private:
> +  tree m_type;
>  };
>
>  // Print the list of known ranges for file F in a nice format.
> @@ -57,7 +60,7 @@ void
>  ssa_block_ranges::dump (FILE *f)
>  {
>    basic_block bb;
> -  int_range_max r;
> +  tmp_range r (m_type);
>
>    FOR_EACH_BB_FN (bb, cfun)
>      if (get_bb_range (r, bb))
> @@ -77,14 +80,14 @@ class sbr_vector : public ssa_block_ranges
>  public:
>    sbr_vector (tree t, vrange_allocator *allocator);
>
> -  virtual bool set_bb_range (const_basic_block bb, const irange &r) override;
> -  virtual bool get_bb_range (irange &r, const_basic_block bb) override;
> +  virtual bool set_bb_range (const_basic_block bb, const vrange &r) override;
> +  virtual bool get_bb_range (vrange &r, const_basic_block bb) override;
>    virtual bool bb_range_p (const_basic_block bb) override;
>  protected:
> -  irange **m_tab;      // Non growing vector.
> +  vrange **m_tab;      // Non growing vector.
>    int m_tab_size;
> -  int_range<2> m_varying;
> -  int_range<2> m_undefined;
> +  vrange *m_varying;
> +  vrange *m_undefined;
>    tree m_type;
>    vrange_allocator *m_range_allocator;
>    void grow ();
> @@ -94,18 +97,21 @@ protected:
>  // Initialize a block cache for an ssa_name of type T.
>
>  sbr_vector::sbr_vector (tree t, vrange_allocator *allocator)
> +  : ssa_block_ranges (t)
>  {
>    gcc_checking_assert (TYPE_P (t));
>    m_type = t;
>    m_range_allocator = allocator;
>    m_tab_size = last_basic_block_for_fn (cfun) + 1;
> -  m_tab = static_cast <irange **>
> -    (allocator->alloc (m_tab_size * sizeof (irange *)));
> -  memset (m_tab, 0, m_tab_size * sizeof (irange *));
> +  m_tab = static_cast <vrange **>
> +    (allocator->alloc (m_tab_size * sizeof (vrange *)));
> +  memset (m_tab, 0, m_tab_size * sizeof (vrange *));
>
>    // Create the cached type range.
> -  m_varying.set_varying (t);
> -  m_undefined.set_undefined ();
> +  m_varying = m_range_allocator->alloc_vrange (t);
> +  m_undefined = m_range_allocator->alloc_vrange (t);
> +  m_varying->set_varying (t);
> +  m_undefined->set_undefined ();
>  }
>
>  // Grow the vector when the CFG has increased in size.
> @@ -122,10 +128,10 @@ sbr_vector::grow ()
>    int new_size = inc + curr_bb_size;
>
>    // Allocate new memory, copy the old vector and clear the new space.
> -  irange **t = static_cast <irange **>
> -    (m_range_allocator->alloc (new_size * sizeof (irange *)));
> -  memcpy (t, m_tab, m_tab_size * sizeof (irange *));
> -  memset (t + m_tab_size, 0, (new_size - m_tab_size) * sizeof (irange *));
> +  vrange **t = static_cast <vrange **>
> +    (m_range_allocator->alloc (new_size * sizeof (vrange *)));
> +  memcpy (t, m_tab, m_tab_size * sizeof (vrange *));
> +  memset (t + m_tab_size, 0, (new_size - m_tab_size) * sizeof (vrange *));
>
>    m_tab = t;
>    m_tab_size = new_size;
> @@ -134,15 +140,15 @@ sbr_vector::grow ()
>  // Set the range for block BB to be R.
>
>  bool
> -sbr_vector::set_bb_range (const_basic_block bb, const irange &r)
> +sbr_vector::set_bb_range (const_basic_block bb, const vrange &r)
>  {
> -  irange *m;
> +  vrange *m;
>    if (bb->index >= m_tab_size)
>      grow ();
>    if (r.varying_p ())
> -    m = &m_varying;
> +    m = m_varying;
>    else if (r.undefined_p ())
> -    m = &m_undefined;
> +    m = m_undefined;
>    else
>      m = m_range_allocator->clone (r);
>    m_tab[bb->index] = m;
> @@ -153,11 +159,11 @@ sbr_vector::set_bb_range (const_basic_block bb, const irange &r)
>  // there is no range.
>
>  bool
> -sbr_vector::get_bb_range (irange &r, const_basic_block bb)
> +sbr_vector::get_bb_range (vrange &r, const_basic_block bb)
>  {
>    if (bb->index >= m_tab_size)
>      return false;
> -  irange *m = m_tab[bb->index];
> +  vrange *m = m_tab[bb->index];
>    if (m)
>      {
>        r = *m;
> @@ -193,14 +199,14 @@ class sbr_sparse_bitmap : public ssa_block_ranges
>  {
>  public:
>    sbr_sparse_bitmap (tree t, vrange_allocator *allocator, bitmap_obstack *bm);
> -  virtual bool set_bb_range (const_basic_block bb, const irange &r) override;
> -  virtual bool get_bb_range (irange &r, const_basic_block bb) override;
> +  virtual bool set_bb_range (const_basic_block bb, const vrange &r) override;
> +  virtual bool get_bb_range (vrange &r, const_basic_block bb) override;
>    virtual bool bb_range_p (const_basic_block bb) override;
>  private:
>    void bitmap_set_quad (bitmap head, int quad, int quad_value);
>    int bitmap_get_quad (const_bitmap head, int quad);
>    vrange_allocator *m_range_allocator;
> -  irange *m_range[SBR_NUM];
> +  vrange *m_range[SBR_NUM];
>    bitmap_head bitvec;
>    tree m_type;
>  };
> @@ -209,6 +215,7 @@ private:
>
>  sbr_sparse_bitmap::sbr_sparse_bitmap (tree t, vrange_allocator *allocator,
>                                       bitmap_obstack *bm)
> +  : ssa_block_ranges (t)
>  {
>    gcc_checking_assert (TYPE_P (t));
>    m_type = t;
> @@ -216,16 +223,14 @@ sbr_sparse_bitmap::sbr_sparse_bitmap (tree t, vrange_allocator *allocator,
>    bitmap_tree_view (&bitvec);
>    m_range_allocator = allocator;
>    // Pre-cache varying.
> -  m_range[0] = static_cast <irange *> (m_range_allocator->alloc_vrange (t));
> +  m_range[0] = m_range_allocator->alloc_vrange (t);
>    m_range[0]->set_varying (t);
>    // Pre-cache zero and non-zero values for pointers.
>    if (POINTER_TYPE_P (t))
>      {
> -      m_range[1]
> -       = static_cast <irange *> (m_range_allocator->alloc_vrange (t));
> +      m_range[1] = m_range_allocator->alloc_vrange (t);
>        m_range[1]->set_nonzero (t);
> -      m_range[2]
> -       = static_cast <irange *> (m_range_allocator->alloc_vrange (t));
> +      m_range[2] = m_range_allocator->alloc_vrange (t);
>        m_range[2]->set_zero (t);
>      }
>    else
> @@ -257,7 +262,7 @@ sbr_sparse_bitmap::bitmap_get_quad (const_bitmap head, int quad)
>  // Set the range on entry to basic block BB to R.
>
>  bool
> -sbr_sparse_bitmap::set_bb_range (const_basic_block bb, const irange &r)
> +sbr_sparse_bitmap::set_bb_range (const_basic_block bb, const vrange &r)
>  {
>    if (r.undefined_p ())
>      {
> @@ -283,7 +288,7 @@ sbr_sparse_bitmap::set_bb_range (const_basic_block bb, const irange &r)
>  // there is no range.
>
>  bool
> -sbr_sparse_bitmap::get_bb_range (irange &r, const_basic_block bb)
> +sbr_sparse_bitmap::get_bb_range (vrange &r, const_basic_block bb)
>  {
>    int value = bitmap_get_quad (&bitvec, bb->index);
>
> @@ -333,7 +338,7 @@ block_range_cache::~block_range_cache ()
>
>  bool
>  block_range_cache::set_bb_range (tree name, const_basic_block bb,
> -                                const irange &r)
> +                                const vrange &r)
>  {
>    unsigned v = SSA_NAME_VERSION (name);
>    if (v >= m_ssa_ranges.length ())
> @@ -379,7 +384,7 @@ block_range_cache::query_block_ranges (tree name)
>  // is one.
>
>  bool
> -block_range_cache::get_bb_range (irange &r, tree name, const_basic_block bb)
> +block_range_cache::get_bb_range (vrange &r, tree name, const_basic_block bb)
>  {
>    ssa_block_ranges *ptr = query_block_ranges (name);
>    if (ptr)
> @@ -423,12 +428,13 @@ void
>  block_range_cache::dump (FILE *f, basic_block bb, bool print_varying)
>  {
>    unsigned x;
> -  int_range_max r;
>    bool summarize_varying = false;
>    for (x = 1; x < m_ssa_ranges.length (); ++x)
>      {
>        if (!gimple_range_ssa_p (ssa_name (x)))
>         continue;
> +
> +      tmp_range r (TREE_TYPE (ssa_name (x)));
>        if (m_ssa_ranges[x] && m_ssa_ranges[x]->get_bb_range (r, bb))
>         {
>           if (!print_varying && r.varying_p ())
> @@ -450,6 +456,8 @@ block_range_cache::dump (FILE *f, basic_block bb, bool print_varying)
>         {
>           if (!gimple_range_ssa_p (ssa_name (x)))
>             continue;
> +
> +         tmp_range r (TREE_TYPE (ssa_name (x)));
>           if (m_ssa_ranges[x] && m_ssa_ranges[x]->get_bb_range (r, bb))
>             {
>               if (r.varying_p ())
> @@ -485,13 +493,13 @@ ssa_global_cache::~ssa_global_cache ()
>  // Return the value in R.
>
>  bool
> -ssa_global_cache::get_global_range (irange &r, tree name) const
> +ssa_global_cache::get_global_range (vrange &r, tree name) const
>  {
>    unsigned v = SSA_NAME_VERSION (name);
>    if (v >= m_tab.length ())
>      return false;
>
> -  irange *stow = m_tab[v];
> +  vrange *stow = m_tab[v];
>    if (!stow)
>      return false;
>    r = *stow;
> @@ -502,13 +510,13 @@ ssa_global_cache::get_global_range (irange &r, tree name) const
>  // Return TRUE if there was already a range set, otherwise false.
>
>  bool
> -ssa_global_cache::set_global_range (tree name, const irange &r)
> +ssa_global_cache::set_global_range (tree name, const vrange &r)
>  {
>    unsigned v = SSA_NAME_VERSION (name);
>    if (v >= m_tab.length ())
>      m_tab.safe_grow_cleared (num_ssa_names + 1);
>
> -  irange *m = m_tab[v];
> +  vrange *m = m_tab[v];
>    if (m && m->fits_p (r))
>      *m = r;
>    else
> @@ -533,7 +541,7 @@ void
>  ssa_global_cache::clear ()
>  {
>    if (m_tab.address ())
> -    memset (m_tab.address(), 0, m_tab.length () * sizeof (irange *));
> +    memset (m_tab.address(), 0, m_tab.length () * sizeof (vrange *));
>  }
>
>  // Dump the contents of the global cache to F.
> @@ -545,8 +553,9 @@ ssa_global_cache::dump (FILE *f)
>    bool print_header = true;
>    for (unsigned x = 1; x < num_ssa_names; x++)
>      {
> -      int_range_max r;
> +      tmp_range r;
>        if (gimple_range_ssa_p (ssa_name (x)) &&
> +         r.init (TREE_TYPE (ssa_name (x))) &&
>           get_global_range (r, ssa_name (x))  && !r.varying_p ())
>         {
>           if (print_header)
> @@ -809,11 +818,11 @@ ranger_cache::dump_bb (FILE *f, basic_block bb)
>  // global range is not set, and return the legacy global value in R.
>
>  bool
> -ranger_cache::get_global_range (irange &r, tree name) const
> +ranger_cache::get_global_range (vrange &r, tree name) const
>  {
>    if (m_globals.get_global_range (r, name))
>      return true;
> -  r = gimple_range_global (name);
> +  gimple_range_global (r, name);
>    return false;
>  }
>
> @@ -825,7 +834,7 @@ ranger_cache::get_global_range (irange &r, tree name) const
>  // After this call, the global cache will have a value.
>
>  bool
> -ranger_cache::get_global_range (irange &r, tree name, bool &current_p)
> +ranger_cache::get_global_range (vrange &r, tree name, bool &current_p)
>  {
>    bool had_global = get_global_range (r, name);
>
> @@ -847,7 +856,7 @@ ranger_cache::get_global_range (irange &r, tree name, bool &current_p)
>  //  Set the global range of NAME to R and give it a timestamp.
>
>  void
> -ranger_cache::set_global_range (tree name, const irange &r)
> +ranger_cache::set_global_range (tree name, const vrange &r)
>  {
>    if (m_globals.set_global_range (name, r))
>      {
> @@ -882,7 +891,7 @@ ranger_cache::set_global_range (tree name, const irange &r)
>  // get the best global value available.
>
>  void
> -ranger_cache::range_of_def (irange &r, tree name, basic_block bb)
> +ranger_cache::range_of_def (vrange &r, tree name, basic_block bb)
>  {
>    gcc_checking_assert (gimple_range_ssa_p (name));
>    gcc_checking_assert (!bb || bb == gimple_bb (SSA_NAME_DEF_STMT (name)));
> @@ -895,7 +904,7 @@ ranger_cache::range_of_def (irange &r, tree name, basic_block bb)
>        if (gimple_get_lhs (s) == name)
>         fold_range (r, s, get_global_range_query ());
>        else
> -       r = gimple_range_global (name);
> +       gimple_range_global (r, name);
>      }
>  }
>
> @@ -903,12 +912,12 @@ ranger_cache::range_of_def (irange &r, tree name, basic_block bb)
>  // lookups.
>
>  void
> -ranger_cache::entry_range (irange &r, tree name, basic_block bb,
> +ranger_cache::entry_range (vrange &r, tree name, basic_block bb,
>                            enum rfd_mode mode)
>  {
>    if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun))
>      {
> -      r = gimple_range_global (name);
> +      gimple_range_global (r, name);
>        return;
>      }
>
> @@ -923,12 +932,12 @@ ranger_cache::entry_range (irange &r, tree name, basic_block bb,
>  // lookups.
>
>  void
> -ranger_cache::exit_range (irange &r, tree name, basic_block bb,
> +ranger_cache::exit_range (vrange &r, tree name, basic_block bb,
>                           enum rfd_mode mode)
>  {
>    if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun))
>      {
> -      r = gimple_range_global (name);
> +      gimple_range_global (r, name);
>        return;
>      }
>
> @@ -944,7 +953,7 @@ ranger_cache::exit_range (irange &r, tree name, basic_block bb,
>  // Always returns a range and true.
>
>  bool
> -ranger_cache::edge_range (irange &r, edge e, tree name, enum rfd_mode mode)
> +ranger_cache::edge_range (vrange &r, edge e, tree name, enum rfd_mode mode)
>  {
>    exit_range (r, name, e->src, mode);
>    // If this is not an abnormal edge, check for side effects on exit.
> @@ -961,7 +970,7 @@ ranger_cache::edge_range (irange &r, edge e, tree name, enum rfd_mode mode)
>  // Implement range_of_expr.
>
>  bool
> -ranger_cache::range_of_expr (irange &r, tree name, gimple *stmt)
> +ranger_cache::range_of_expr (vrange &r, tree name, gimple *stmt)
>  {
>    if (!gimple_range_ssa_p (name))
>      {
> @@ -985,7 +994,7 @@ ranger_cache::range_of_expr (irange &r, tree name, gimple *stmt)
>  // the current cache values.
>
>  bool
> -ranger_cache::range_on_edge (irange &r, edge e, tree expr)
> +ranger_cache::range_on_edge (vrange &r, edge e, tree expr)
>  {
>    if (gimple_range_ssa_p (expr))
>      return edge_range (r, e, expr, RFD_NONE);
> @@ -997,7 +1006,7 @@ ranger_cache::range_on_edge (irange &r, edge e, tree expr)
>  // def block for NAME.  Otherwise, return false if the cache is empty.
>
>  bool
> -ranger_cache::block_range (irange &r, basic_block bb, tree name, bool calc)
> +ranger_cache::block_range (vrange &r, basic_block bb, tree name, bool calc)
>  {
>    gcc_checking_assert (gimple_range_ssa_p (name));
>
> @@ -1041,9 +1050,10 @@ ranger_cache::propagate_cache (tree name)
>    basic_block bb;
>    edge_iterator ei;
>    edge e;
> -  int_range_max new_range;
> -  int_range_max current_range;
> -  int_range_max e_range;
> +  tree type = TREE_TYPE (name);
> +  tmp_range new_range (type);
> +  tmp_range current_range (type);
> +  tmp_range e_range (type);
>
>    // Process each block by seeing if its calculated range on entry is
>    // the same as its cached value. If there is a difference, update
> @@ -1178,8 +1188,8 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
>  {
>    edge_iterator ei;
>    edge e;
> -  int_range_max block_result;
> -  int_range_max undefined;
> +  tmp_range block_result (TREE_TYPE (name));
> +  tmp_range undefined (TREE_TYPE (name));
>
>    // At this point we shouldn't be looking at the def, entry or exit block.
>    gcc_checking_assert (bb != def_bb && bb != ENTRY_BLOCK_PTR_FOR_FN (cfun) &&
> @@ -1232,7 +1242,7 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
>        FOR_EACH_EDGE (e, ei, node->preds)
>         {
>           basic_block pred = e->src;
> -         int_range_max r;
> +         tmp_range r (TREE_TYPE (name));
>
>           if (DEBUG_RANGE_CACHE)
>             fprintf (dump_file, "  %d->%d ",e->src->index, e->dest->index);
> @@ -1306,7 +1316,7 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
>  // dominator tree based on MODE.
>
>  bool
> -ranger_cache::range_from_dom (irange &r, tree name, basic_block start_bb,
> +ranger_cache::range_from_dom (vrange &r, tree name, basic_block start_bb,
>                               enum rfd_mode mode)
>  {
>    if (mode == RFD_NONE || !dom_info_available_p (CDI_DOMINATORS))
> diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h
> index 2472cd04f47..d17950c7154 100644
> --- a/gcc/gimple-range-cache.h
> +++ b/gcc/gimple-range-cache.h
> @@ -34,8 +34,8 @@ public:
>    block_range_cache ();
>    ~block_range_cache ();
>
> -  bool set_bb_range (tree name, const_basic_block bb, const irange &r);
> -  bool get_bb_range (irange &r, tree name, const_basic_block bb);
> +  bool set_bb_range (tree name, const_basic_block bb, const vrange &v);
> +  bool get_bb_range (vrange &v, tree name, const_basic_block bb);
>    bool bb_range_p (tree name, const_basic_block bb);
>
>    void dump (FILE *f);
> @@ -57,13 +57,13 @@ class ssa_global_cache
>  public:
>    ssa_global_cache ();
>    ~ssa_global_cache ();
> -  bool get_global_range (irange &r, tree name) const;
> -  bool set_global_range (tree name, const irange &r);
> +  bool get_global_range (vrange &r, tree name) const;
> +  bool set_global_range (tree name, const vrange &r);
>    void clear_global_range (tree name);
>    void clear ();
>    void dump (FILE *f = stderr);
>  private:
> -  vec<irange *> m_tab;
> +  vec<vrange *> m_tab;
>    vrange_allocator *m_range_allocator;
>  };
>
> @@ -77,13 +77,13 @@ public:
>    ranger_cache (int not_executable_flag, bool use_imm_uses);
>    ~ranger_cache ();
>
> -  virtual bool range_of_expr (irange &r, tree name, gimple *stmt);
> -  virtual bool range_on_edge (irange &r, edge e, tree expr);
> -  bool block_range (irange &r, basic_block bb, tree name, bool calc = true);
> +  virtual bool range_of_expr (vrange &r, tree name, gimple *stmt);
> +  virtual bool range_on_edge (vrange &r, edge e, tree expr);
> +  bool block_range (vrange &r, basic_block bb, tree name, bool calc = true);
>
> -  bool get_global_range (irange &r, tree name) const;
> -  bool get_global_range (irange &r, tree name, bool &current_p);
> -  void set_global_range (tree name, const irange &r);
> +  bool get_global_range (vrange &r, tree name) const;
> +  bool get_global_range (vrange &r, tree name, bool &current_p);
> +  void set_global_range (tree name, const vrange &r);
>
>    void propagate_updated_value (tree name, basic_block bb);
>
> @@ -106,11 +106,11 @@ private:
>        RFD_READ_ONLY,   // Scan DOM tree, do not write to cache.
>        RFD_FILL         // Scan DOM tree, updating important nodes.
>      };
> -  bool range_from_dom (irange &r, tree name, basic_block bb, enum rfd_mode);
> -  void range_of_def (irange &r, tree name, basic_block bb = NULL);
> -  void entry_range (irange &r, tree expr, basic_block bb, enum rfd_mode);
> -  void exit_range (irange &r, tree expr, basic_block bb, enum rfd_mode);
> -  bool edge_range (irange &r, edge e, tree name, enum rfd_mode);
> +  bool range_from_dom (vrange &r, tree name, basic_block bb, enum rfd_mode);
> +  void range_of_def (vrange &r, tree name, basic_block bb = NULL);
> +  void entry_range (vrange &r, tree expr, basic_block bb, enum rfd_mode);
> +  void exit_range (vrange &r, tree expr, basic_block bb, enum rfd_mode);
> +  bool edge_range (vrange &r, edge e, tree name, enum rfd_mode);
>
>    vec<basic_block> m_workback;
>    class update_list *m_update;
> diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc
> index 5264e627c9a..6fe33408f7e 100644
> --- a/gcc/gimple-range-edge.cc
> +++ b/gcc/gimple-range-edge.cc
> @@ -83,11 +83,8 @@ gimple_outgoing_range::~gimple_outgoing_range ()
>  // Use a cached value if it exists, or calculate it if not.
>
>  bool
> -gimple_outgoing_range::get_edge_range (irange &r, gimple *s, edge e)
> +gimple_outgoing_range::switch_edge_range (irange &r, gswitch *sw, edge e)
>  {
> -  gcc_checking_assert (is_a<gswitch *> (s));
> -  gswitch *sw = as_a<gswitch *> (s);
> -
>    // ADA currently has cases where the index is 64 bits and the case
>    // arguments are 32 bit, causing a trap when we create a case_range.
>    // Until this is resolved (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87798)
> @@ -204,12 +201,9 @@ gimple_outgoing_range::edge_range_p (irange &r, edge e)
>
>    gcc_checking_assert (is_a<gswitch *> (s));
>    gswitch *sw = as_a<gswitch *> (s);
> -  tree type = TREE_TYPE (gimple_switch_index (sw));
> -
> -  if (!irange::supports_type_p (type))
> -    return NULL;
>
> -  if (get_edge_range (r, sw, e))
> +  // Switches can only be integers.
> +  if (switch_edge_range (as_a <irange> (r), sw, e))
>      return s;
>
>    return NULL;
> diff --git a/gcc/gimple-range-edge.h b/gcc/gimple-range-edge.h
> index ce383b0aa6f..a9c4af8715b 100644
> --- a/gcc/gimple-range-edge.h
> +++ b/gcc/gimple-range-edge.h
> @@ -43,7 +43,7 @@ public:
>    gimple *edge_range_p (irange &r, edge e);
>  private:
>    void calc_switch_ranges (gswitch *sw);
> -  bool get_edge_range (irange &r, gimple *s, edge e);
> +  bool switch_edge_range (irange &r, gswitch *sw, edge e);
>
>    int m_max_edges;
>    hash_map<edge, irange *> *m_edge_table;
> diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
> index c53d2863d5e..7fed5a99513 100644
> --- a/gcc/gimple-range-fold.cc
> +++ b/gcc/gimple-range-fold.cc
> @@ -60,7 +60,7 @@ fur_source::fur_source (range_query *q)
>  // Invoke range_of_expr on EXPR.
>
>  bool
> -fur_source::get_operand (irange &r, tree expr)
> +fur_source::get_operand (vrange &r, tree expr)
>  {
>    return m_query->range_of_expr (r, expr);
>  }
> @@ -69,7 +69,7 @@ fur_source::get_operand (irange &r, tree expr)
>  // range_query to get the range on the edge.
>
>  bool
> -fur_source::get_phi_operand (irange &r, tree expr, edge e)
> +fur_source::get_phi_operand (vrange &r, tree expr, edge e)
>  {
>    return m_query->range_on_edge (r, e, expr);
>  }
> @@ -109,8 +109,8 @@ class fur_edge : public fur_source
>  {
>  public:
>    fur_edge (edge e, range_query *q = NULL);
> -  virtual bool get_operand (irange &r, tree expr) override;
> -  virtual bool get_phi_operand (irange &r, tree expr, edge e) override;
> +  virtual bool get_operand (vrange &r, tree expr) override;
> +  virtual bool get_phi_operand (vrange &r, tree expr, edge e) override;
>  private:
>    edge m_edge;
>  };
> @@ -126,7 +126,7 @@ fur_edge::fur_edge (edge e, range_query *q) : fur_source (q)
>  // Get the value of EXPR on edge m_edge.
>
>  bool
> -fur_edge::get_operand (irange &r, tree expr)
> +fur_edge::get_operand (vrange &r, tree expr)
>  {
>    return m_query->range_on_edge (r, m_edge, expr);
>  }
> @@ -135,7 +135,7 @@ fur_edge::get_operand (irange &r, tree expr)
>  // range_query to get the range on the edge.
>
>  bool
> -fur_edge::get_phi_operand (irange &r, tree expr, edge e)
> +fur_edge::get_phi_operand (vrange &r, tree expr, edge e)
>  {
>    // Edge to edge recalculations not supoprted yet, until we sort it out.
>    gcc_checking_assert (e == m_edge);
> @@ -152,7 +152,7 @@ fur_stmt::fur_stmt (gimple *s, range_query *q) : fur_source (q)
>  // Retreive range of EXPR as it occurs as a use on stmt M_STMT.
>
>  bool
> -fur_stmt::get_operand (irange &r, tree expr)
> +fur_stmt::get_operand (vrange &r, tree expr)
>  {
>    return m_query->range_of_expr (r, expr, m_stmt);
>  }
> @@ -161,7 +161,7 @@ fur_stmt::get_operand (irange &r, tree expr)
>  // range_query to get the range on the edge.
>
>  bool
> -fur_stmt::get_phi_operand (irange &r, tree expr, edge e)
> +fur_stmt::get_phi_operand (vrange &r, tree expr, edge e)
>  {
>    // Pick up the range of expr from edge E.
>    fur_edge e_src (e, m_query);
> @@ -214,42 +214,42 @@ fur_depend::register_relation (edge e, relation_kind k, tree op1, tree op2)
>  class fur_list : public fur_source
>  {
>  public:
> -  fur_list (irange &r1);
> -  fur_list (irange &r1, irange &r2);
> -  fur_list (unsigned num, irange *list);
> -  virtual bool get_operand (irange &r, tree expr) override;
> -  virtual bool get_phi_operand (irange &r, tree expr, edge e) override;
> +  fur_list (vrange &r1);
> +  fur_list (vrange &r1, vrange &r2);
> +  fur_list (unsigned num, vrange **list);
> +  virtual bool get_operand (vrange &r, tree expr) override;
> +  virtual bool get_phi_operand (vrange &r, tree expr, edge e) override;
>  private:
> -  int_range_max m_local[2];
> -  irange *m_list;
> +  vrange *m_local[2];
> +  vrange **m_list;
>    unsigned m_index;
>    unsigned m_limit;
>  };
>
>  // One range supplied for unary operations.
>
> -fur_list::fur_list (irange &r1) : fur_source (NULL)
> +fur_list::fur_list (vrange &r1) : fur_source (NULL)
>  {
>    m_list = m_local;
>    m_index = 0;
>    m_limit = 1;
> -  m_local[0] = r1;
> +  m_local[0] = &r1;
>  }
>
>  // Two ranges supplied for binary operations.
>
> -fur_list::fur_list (irange &r1, irange &r2) : fur_source (NULL)
> +fur_list::fur_list (vrange &r1, vrange &r2) : fur_source (NULL)
>  {
>    m_list = m_local;
>    m_index = 0;
>    m_limit = 2;
> -  m_local[0] = r1;
> -  m_local[1] = r2;
> +  m_local[0] = &r1;
> +  m_local[1] = &r2;
>  }
>
>  // Arbitrary number of ranges in a vector.
>
> -fur_list::fur_list (unsigned num, irange *list) : fur_source (NULL)
> +fur_list::fur_list (unsigned num, vrange **list) : fur_source (NULL)
>  {
>    m_list = list;
>    m_index = 0;
> @@ -259,18 +259,18 @@ fur_list::fur_list (unsigned num, irange *list) : fur_source (NULL)
>  // Get the next operand from the vector, ensure types are compatible.
>
>  bool
> -fur_list::get_operand (irange &r, tree expr)
> +fur_list::get_operand (vrange &r, tree expr)
>  {
>    if (m_index >= m_limit)
>      return m_query->range_of_expr (r, expr);
> -  r = m_list[m_index++];
> +  r = *m_list[m_index++];
>    gcc_checking_assert (range_compatible_p (TREE_TYPE (expr), r.type ()));
>    return true;
>  }
>
>  // This will simply pick the next operand from the vector.
>  bool
> -fur_list::get_phi_operand (irange &r, tree expr, edge e ATTRIBUTE_UNUSED)
> +fur_list::get_phi_operand (vrange &r, tree expr, edge e ATTRIBUTE_UNUSED)
>  {
>    return get_operand (r, expr);
>  }
> @@ -278,7 +278,7 @@ fur_list::get_phi_operand (irange &r, tree expr, edge e ATTRIBUTE_UNUSED)
>  // Fold stmt S into range R using R1 as the first operand.
>
>  bool
> -fold_range (irange &r, gimple *s, irange &r1)
> +fold_range (vrange &r, gimple *s, vrange &r1)
>  {
>    fold_using_range f;
>    fur_list src (r1);
> @@ -288,7 +288,7 @@ fold_range (irange &r, gimple *s, irange &r1)
>  // Fold stmt S into range R using R1  and R2 as the first two operands.
>
>  bool
> -fold_range (irange &r, gimple *s, irange &r1, irange &r2)
> +fold_range (vrange &r, gimple *s, vrange &r1, vrange &r2)
>  {
>    fold_using_range f;
>    fur_list src (r1, r2);
> @@ -299,7 +299,7 @@ fold_range (irange &r, gimple *s, irange &r1, irange &r2)
>  // operands encountered.
>
>  bool
> -fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector)
> +fold_range (vrange &r, gimple *s, unsigned num_elements, vrange **vector)
>  {
>    fold_using_range f;
>    fur_list src (num_elements, vector);
> @@ -309,7 +309,7 @@ fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector)
>  // Fold stmt S into range R using range query Q.
>
>  bool
> -fold_range (irange &r, gimple *s, range_query *q)
> +fold_range (vrange &r, gimple *s, range_query *q)
>  {
>    fold_using_range f;
>    fur_stmt src (s, q);
> @@ -319,7 +319,7 @@ fold_range (irange &r, gimple *s, range_query *q)
>  // Recalculate stmt S into R using range query Q as if it were on edge ON_EDGE.
>
>  bool
> -fold_range (irange &r, gimple *s, edge on_edge, range_query *q)
> +fold_range (vrange &r, gimple *s, edge on_edge, range_query *q)
>  {
>    fold_using_range f;
>    fur_edge src (on_edge, q);
> @@ -370,7 +370,7 @@ adjust_pointer_diff_expr (irange &res, const gimple *diff_stmt)
>  // Adjust the range for an IMAGPART_EXPR.
>
>  static void
> -adjust_imagpart_expr (irange &res, const gimple *stmt)
> +adjust_imagpart_expr (vrange &res, const gimple *stmt)
>  {
>    tree name = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
>
> @@ -413,7 +413,7 @@ adjust_imagpart_expr (irange &res, const gimple *stmt)
>  // Adjust the range for a REALPART_EXPR.
>
>  static void
> -adjust_realpart_expr (irange &res, const gimple *stmt)
> +adjust_realpart_expr (vrange &res, const gimple *stmt)
>  {
>    tree name = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
>
> @@ -442,12 +442,12 @@ adjust_realpart_expr (irange &res, const gimple *stmt)
>  // this statement.
>
>  static void
> -gimple_range_adjustment (irange &res, const gimple *stmt)
> +gimple_range_adjustment (vrange &res, const gimple *stmt)
>  {
>    switch (gimple_expr_code (stmt))
>      {
>      case POINTER_DIFF_EXPR:
> -      adjust_pointer_diff_expr (res, stmt);
> +      adjust_pointer_diff_expr (as_a <irange> (res), stmt);
>        return;
>
>      case IMAGPART_EXPR:
> @@ -536,7 +536,7 @@ gimple_range_operand2 (const gimple *stmt)
>  // be calculated, return false.
>
>  bool
> -fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name)
> +fold_using_range::fold_stmt (vrange &r, gimple *s, fur_source &src, tree name)
>  {
>    bool res = false;
>    // If name and S are specified, make sure it is an LHS of S.
> @@ -549,7 +549,7 @@ fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name)
>    // Process addresses.
>    if (gimple_code (s) == GIMPLE_ASSIGN
>        && gimple_assign_rhs_code (s) == ADDR_EXPR)
> -    return range_of_address (r, s, src);
> +    return range_of_address (as_a <irange> (r), s, src);
>
>    if (range_op_handler (s))
>      res = range_of_range_op (r, s, src);
> @@ -566,7 +566,7 @@ fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name)
>        if (!name || !gimple_range_ssa_p (name))
>         return false;
>        // We don't understand the stmt, so return the global range.
> -      r = gimple_range_global (name);
> +      gimple_range_global (r, name);
>        return true;
>      }
>
> @@ -587,9 +587,8 @@ fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name)
>  // If a range cannot be calculated, return false.
>
>  bool
> -fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
> +fold_using_range::range_of_range_op (vrange &r, gimple *s, fur_source &src)
>  {
> -  int_range_max range1, range2;
>    tree type = gimple_range_type (s);
>    if (!type)
>      return false;
> @@ -599,13 +598,16 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
>    tree lhs = gimple_get_lhs (s);
>    tree op1 = gimple_range_operand1 (s);
>    tree op2 = gimple_range_operand2 (s);
> +  tmp_range range1 (TREE_TYPE (op1));
> +  tmp_range range2;
>
>    if (src.get_operand (range1, op1))
>      {
>        if (!op2)
>         {
>           // Fold range, and register any dependency if available.
> -         int_range<2> r2 (type);
> +         tmp_range r2 (type);
> +         r2.set_varying (type);
>           handler.fold_range (r, type, range1, r2);
>           if (lhs && gimple_range_ssa_p (op1))
>             {
> @@ -617,7 +619,8 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
>                 src.register_relation (s, rel, lhs, op1);
>             }
>         }
> -      else if (src.get_operand (range2, op2))
> +      else if (range2.init (TREE_TYPE (op2))
> +              && src.get_operand (range2, op2))
>         {
>           relation_kind rel = src.query_relation (op1, op2);
>           if (dump_file && (dump_flags & TDF_DETAILS) && rel != VREL_VARYING)
> @@ -630,7 +633,8 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
>             }
>           // Fold range, and register any dependency if available.
>           handler.fold_range (r, type, range1, range2, rel);
> -         relation_fold_and_or (r, s, src);
> +         if (irange::supports_type_p (type))
> +           relation_fold_and_or (as_a <irange> (r), s, src);
>           if (lhs)
>             {
>               if (src.gori ())
> @@ -663,7 +667,8 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
>                 e0 = NULL;
>               if (!single_pred_p (e1->dest))
>                 e1 = NULL;
> -             src.register_outgoing_edges (as_a<gcond *> (s), r, e0, e1);
> +             src.register_outgoing_edges (as_a<gcond *> (s),
> +                                          as_a <irange> (r), e0, e1);
>             }
>         }
>        else
> @@ -729,12 +734,12 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src)
>         {
>           /* For -fdelete-null-pointer-checks -fno-wrapv-pointer we don't
>              allow going from non-NULL pointer to NULL.  */
> -         if (!range_includes_zero_p (&r))
> +         if (r.undefined_p () || !r.contains_p (build_zero_cst (r.type ())))
>             {
>               /* We could here instead adjust r by off >> LOG2_BITS_PER_UNIT
>                  using POINTER_PLUS_EXPR if off_cst and just fall back to
>                  this.  */
> -             r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
> +             r.set_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
>               return true;
>             }
>         }
> @@ -746,22 +751,22 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src)
>           && known_ne (off, 0)
>           && (flag_delete_null_pointer_checks || known_gt (off, 0)))
>         {
> -         r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
> +         r.set_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
>           return true;
>         }
> -      r = int_range<2> (TREE_TYPE (gimple_assign_rhs1 (stmt)));
> +      r.set_varying (TREE_TYPE (gimple_assign_rhs1 (stmt)));
>        return true;
>      }
>
>    // Handle "= &a".
>    if (tree_single_nonzero_warnv_p (expr, &strict_overflow_p))
>      {
> -      r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
> +      r.set_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
>        return true;
>      }
>
>    // Otherwise return varying.
> -  r = int_range<2> (TREE_TYPE (gimple_assign_rhs1 (stmt)));
> +  r.set_varying (TREE_TYPE (gimple_assign_rhs1 (stmt)));
>    return true;
>  }
>
> @@ -769,12 +774,12 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src)
>  // If a range cannot be calculated, return false.
>
>  bool
> -fold_using_range::range_of_phi (irange &r, gphi *phi, fur_source &src)
> +fold_using_range::range_of_phi (vrange &r, gphi *phi, fur_source &src)
>  {
>    tree phi_def = gimple_phi_result (phi);
>    tree type = gimple_range_type (phi);
> -  int_range_max arg_range;
> -  int_range_max equiv_range;
> +  tmp_range arg_range (type);
> +  tmp_range equiv_range (type);
>    unsigned x;
>
>    if (!type)
> @@ -881,7 +886,7 @@ fold_using_range::range_of_phi (irange &r, gphi *phi, fur_source &src)
>  // If a range cannot be calculated, return false.
>
>  bool
> -fold_using_range::range_of_call (irange &r, gcall *call, fur_source &src)
> +fold_using_range::range_of_call (vrange &r, gcall *call, fur_source &src)
>  {
>    tree type = gimple_range_type (call);
>    if (!type)
> @@ -893,18 +898,18 @@ fold_using_range::range_of_call (irange &r, gcall *call, fur_source &src)
>    if (range_of_builtin_call (r, call, src))
>      ;
>    else if (gimple_stmt_nonnegative_warnv_p (call, &strict_overflow_p))
> -    r.set (build_int_cst (type, 0), TYPE_MAX_VALUE (type));
> +    r.set_nonnegative (type);
>    else if (gimple_call_nonnull_result_p (call)
>            || gimple_call_nonnull_arg (call))
> -    r = range_nonzero (type);
> +    r.set_nonzero (type);
>    else
>      r.set_varying (type);
>
>    // If there is an LHS, intersect that with what is known.
>    if (lhs)
>      {
> -      value_range def;
> -      def = gimple_range_global (lhs);
> +      tmp_range def (TREE_TYPE (lhs));
> +      gimple_range_global (def, lhs);
>        r.intersect (def);
>      }
>    return true;
> @@ -971,13 +976,30 @@ get_letter_range (tree type, irange &lowers, irange &uppers)
>  // TRUE.  Otherwise return FALSE.
>
>  bool
> -fold_using_range::range_of_builtin_call (irange &r, gcall *call,
> +fold_using_range::range_of_builtin_call (vrange &r, gcall *call,
>                                          fur_source &src)
>  {
>    combined_fn func = gimple_call_combined_fn (call);
>    if (func == CFN_LAST)
>      return false;
>
> +  tree type = gimple_range_type (call);
> +  gcc_checking_assert (type);
> +
> +  if (irange::supports_type_p (type))
> +    return range_of_builtin_int_call (as_a <irange> (r), call, src);
> +
> +  return false;
> +}
> +
> +bool
> +fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
> +                                            fur_source &src)
> +{
> +  combined_fn func = gimple_call_combined_fn (call);
> +  if (func == CFN_LAST)
> +    return false;
> +
>    tree type = gimple_range_type (call);
>    tree arg;
>    int mini, maxi, zerov = 0, prec;
> @@ -1256,9 +1278,8 @@ fold_using_range::range_of_builtin_call (irange &r, gcall *call,
>  // If a range cannot be calculated, return false.
>
>  bool
> -fold_using_range::range_of_cond_expr  (irange &r, gassign *s, fur_source &src)
> +fold_using_range::range_of_cond_expr  (vrange &r, gassign *s, fur_source &src)
>  {
> -  int_range_max cond_range, range1, range2;
>    tree cond = gimple_assign_rhs1 (s);
>    tree op1 = gimple_assign_rhs2 (s);
>    tree op2 = gimple_assign_rhs3 (s);
> @@ -1267,6 +1288,9 @@ fold_using_range::range_of_cond_expr  (irange &r, gassign *s, fur_source &src)
>    if (!type)
>      return false;
>
> +  tmp_range range1 (TREE_TYPE (op1));
> +  tmp_range range2 (TREE_TYPE (op2));
> +  tmp_range cond_range (TREE_TYPE (cond));
>    gcc_checking_assert (gimple_assign_rhs_code (s) == COND_EXPR);
>    gcc_checking_assert (range_compatible_p (TREE_TYPE (op1), TREE_TYPE (op2)));
>    src.get_operand (cond_range, cond);
> @@ -1438,7 +1462,6 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
>  void
>  fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge e1)
>  {
> -  int_range_max r;
>    int_range<2> e0_range, e1_range;
>    tree name;
>    basic_block bb = gimple_bb (s);
> @@ -1505,6 +1528,7 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
>         continue;
>        tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
>        tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (stmt));
> +      tmp_range r (TREE_TYPE (name));
>        if (ssa1 && ssa2)
>         {
>           if (e0 && gori ()->outgoing_edge_range_p (r, e0, name, *m_query)
> diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h
> index 4b5d4b6e0b8..df24280ee40 100644
> --- a/gcc/gimple-range-fold.h
> +++ b/gcc/gimple-range-fold.h
> @@ -23,7 +23,7 @@ along with GCC; see the file COPYING3.  If not see
>  #define GCC_GIMPLE_RANGE_FOLD_H
>
>  // This file is the main include point for gimple range folding.
> -// These routines will fold stmt S into the result irange R.
> +// These routines will fold stmt S into the result range R.
>  // Any ssa_names on the stmt will be calculated using the range_query
>  // parameter via a call to range_of_expr.
>  // If no range_query is provided, current global range info will be used.
> @@ -31,15 +31,15 @@ along with GCC; see the file COPYING3.  If not see
>  // it appeared on that edge.
>
>  // Fold stmt S into range R using range query Q.
> -bool fold_range (irange &r, gimple *s, range_query *q = NULL);
> +bool fold_range (vrange &r, gimple *s, range_query *q = NULL);
>  // Recalculate stmt S into R using range query Q as if it were on edge ON_EDGE.
> -bool fold_range (irange &r, gimple *s, edge on_edge, range_query *q = NULL);
> +bool fold_range (vrange &v, gimple *s, edge on_edge, range_query *q = NULL);
>
>  // These routines the operands to be specified when manually folding.
>  // Any excess queries will be drawn from the current range_query.
> -bool fold_range (irange &r, gimple *s, irange &r1);
> -bool fold_range (irange &r, gimple *s, irange &r1, irange &r2);
> -bool fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector);
> +bool fold_range (vrange &r, gimple *s, vrange &r1);
> +bool fold_range (vrange &r, gimple *s, vrange &r1, vrange &r2);
> +bool fold_range (vrange &r, gimple *s, unsigned num_elements, vrange **vector);
>
>  // Return the type of range which statement S calculates.  If the type is
>  // unsupported or no type can be determined, return NULL_TREE.
> @@ -66,7 +66,7 @@ gimple_range_type (const gimple *s)
>             type = TREE_TYPE (type);
>         }
>      }
> -  if (type && irange::supports_type_p (type))
> +  if (type && vrange::supports_type_p (type))
>      return type;
>    return NULL_TREE;
>  }
> @@ -79,7 +79,7 @@ gimple_range_ssa_p (tree exp)
>    if (exp && TREE_CODE (exp) == SSA_NAME &&
>        !SSA_NAME_IS_VIRTUAL_OPERAND (exp) &&
>        !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp) &&
> -      irange::supports_type_p (TREE_TYPE (exp)))
> +      vrange::supports_type_p (TREE_TYPE (exp)))
>      return exp;
>    return NULL_TREE;
>  }
> @@ -108,8 +108,8 @@ public:
>    fur_source (range_query *q = NULL);
>    inline range_query *query () { return m_query; }
>    inline class gori_compute *gori () { return m_gori; };
> -  virtual bool get_operand (irange &r, tree expr);
> -  virtual bool get_phi_operand (irange &r, tree expr, edge e);
> +  virtual bool get_operand (vrange &r, tree expr);
> +  virtual bool get_phi_operand (vrange &r, tree expr, edge e);
>    virtual relation_kind query_relation (tree op1, tree op2);
>    virtual void register_relation (gimple *stmt, relation_kind k, tree op1,
>                                   tree op2);
> @@ -128,8 +128,8 @@ class fur_stmt : public fur_source
>  {
>  public:
>    fur_stmt (gimple *s, range_query *q = NULL);
> -  virtual bool get_operand (irange &r, tree expr) override;
> -  virtual bool get_phi_operand (irange &r, tree expr, edge e) override;
> +  virtual bool get_operand (vrange &r, tree expr) override;
> +  virtual bool get_phi_operand (vrange &r, tree expr, edge e) override;
>    virtual relation_kind query_relation (tree op1, tree op2) override;
>  private:
>    gimple *m_stmt;
> @@ -161,17 +161,18 @@ extern tree gimple_range_operand2 (const gimple *s);
>  class fold_using_range
>  {
>  public:
> -  bool fold_stmt (irange &r, gimple *s, class fur_source &src,
> +  bool fold_stmt (vrange &r, gimple *s, class fur_source &src,
>                   tree name = NULL_TREE);
>  protected:
> -  bool range_of_range_op (irange &r, gimple *s, fur_source &src);
> -  bool range_of_call (irange &r, gcall *call, fur_source &src);
> -  bool range_of_cond_expr (irange &r, gassign* cond, fur_source &src);
> +  bool range_of_range_op (vrange &r, gimple *s, fur_source &src);
> +  bool range_of_call (vrange &r, gcall *call, fur_source &src);
> +  bool range_of_cond_expr (vrange &r, gassign* cond, fur_source &src);
>    bool range_of_address (irange &r, gimple *s, fur_source &src);
> -  bool range_of_builtin_call (irange &r, gcall *call, fur_source &src);
> +  bool range_of_builtin_call (vrange &r, gcall *call, fur_source &src);
> +  bool range_of_builtin_int_call (irange &r, gcall *call, fur_source &src);
>    void range_of_builtin_ubsan_call (irange &r, gcall *call, tree_code code,
>                                     fur_source &src);
> -  bool range_of_phi (irange &r, gphi *phi, fur_source &src);
> +  bool range_of_phi (vrange &r, gphi *phi, fur_source &src);
>    void range_of_ssa_name_with_loop_info (irange &, tree, class loop *, gphi *,
>                                          fur_source &src);
>    void relation_fold_and_or (irange& lhs_range, gimple *s, fur_source &src);
> diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
> index 0e0cf2128e7..47d0dab8cb9 100644
> --- a/gcc/gimple-range-gori.cc
> +++ b/gcc/gimple-range-gori.cc
> @@ -34,7 +34,7 @@ along with GCC; see the file COPYING3.  If not see
>  // LHS_RANGE.  Return false if nothing can be determined.
>
>  bool
> -gimple_range_calc_op1 (irange &r, const gimple *stmt, const irange &lhs_range)
> +gimple_range_calc_op1 (vrange &r, const gimple *stmt, const vrange &lhs_range)
>  {
>    gcc_checking_assert (gimple_num_ops (stmt) < 3);
>    // Give up on empty ranges.
> @@ -55,8 +55,8 @@ gimple_range_calc_op1 (irange &r, const gimple *stmt, const irange &lhs_range)
>  // nothing can be determined.
>
>  bool
> -gimple_range_calc_op1 (irange &r, const gimple *stmt,
> -                      const irange &lhs_range, const irange &op2_range)
> +gimple_range_calc_op1 (vrange &r, const gimple *stmt,
> +                      const vrange &lhs_range, const vrange &op2_range)
>  {
>    // Give up on empty ranges.
>    if (lhs_range.undefined_p ())
> @@ -86,8 +86,8 @@ gimple_range_calc_op1 (irange &r, const gimple *stmt,
>  // nothing can be determined.
>
>  bool
> -gimple_range_calc_op2 (irange &r, const gimple *stmt,
> -                      const irange &lhs_range, const irange &op1_range)
> +gimple_range_calc_op2 (vrange &r, const gimple *stmt,
> +                      const vrange &lhs_range, const vrange &op1_range)
>  {
>    // Give up on empty ranges.
>    if (lhs_range.undefined_p ())
> @@ -663,8 +663,8 @@ gori_compute::gori_compute (int not_executable_flag)
>  // was not resolvable.
>
>  bool
> -gori_compute::compute_operand_range_switch (irange &r, gswitch *s,
> -                                           const irange &lhs,
> +gori_compute::compute_operand_range_switch (vrange &r, gswitch *s,
> +                                           const vrange &lhs,
>                                             tree name, fur_source &src)
>  {
>    tree op1 = gimple_switch_index (s);
> @@ -691,8 +691,8 @@ gori_compute::compute_operand_range_switch (irange &r, gswitch *s,
>  // store the evaluation in R, otherwise return FALSE.
>
>  bool
> -gori_compute::compute_operand_range (irange &r, gimple *stmt,
> -                                    const irange &lhs, tree name,
> +gori_compute::compute_operand_range (vrange &r, gimple *stmt,
> +                                    const vrange &lhs, tree name,
>                                      fur_source &src)
>  {
>    // If the lhs doesn't tell us anything, neither will unwinding further.
> @@ -743,13 +743,18 @@ gori_compute::compute_operand_range (irange &r, gimple *stmt,
>           print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
>         }
>
> -      int_range_max op1_trange, op1_frange;
> -      int_range_max op2_trange, op2_frange;
> -      compute_logical_operands (op1_trange, op1_frange, stmt, lhs,
> +      tree type = TREE_TYPE (name);
> +      tmp_range op1_trange (type), op1_frange (type);
> +      tmp_range op2_trange (type), op2_frange (type);
> +      compute_logical_operands (op1_trange, op1_frange, stmt,
> +                               as_a <irange> (lhs),
>                                 name, src, op1, op1_in_chain);
> -      compute_logical_operands (op2_trange, op2_frange, stmt, lhs,
> +      compute_logical_operands (op2_trange, op2_frange, stmt,
> +                               as_a <irange> (lhs),
>                                 name, src, op2, op2_in_chain);
> -      res = logical_combine (r, gimple_expr_code (stmt), lhs,
> +      res = logical_combine (r,
> +                            gimple_expr_code (stmt),
> +                            as_a <irange> (lhs),
>                              op1_trange, op1_frange, op2_trange, op2_frange);
>        if (idx)
>         tracer.trailer (idx, "compute_operand", res, name, r);
> @@ -789,10 +794,10 @@ range_is_either_true_or_false (const irange &r)
>  // the LHS.
>
>  bool
> -gori_compute::logical_combine (irange &r, enum tree_code code,
> +gori_compute::logical_combine (vrange &r, enum tree_code code,
>                                const irange &lhs,
> -                              const irange &op1_true, const irange &op1_false,
> -                              const irange &op2_true, const irange &op2_false)
> +                              const vrange &op1_true, const vrange &op1_false,
> +                              const vrange &op2_true, const vrange &op2_false)
>  {
>    if (op1_true.varying_p () && op1_false.varying_p ()
>        && op2_true.varying_p () && op2_false.varying_p ())
> @@ -868,7 +873,7 @@ gori_compute::logical_combine (irange &r, enum tree_code code,
>    if (!range_is_either_true_or_false (lhs))
>      {
>        bool res;
> -      int_range_max r1;
> +      tmp_range r1 (r);
>        if (logical_combine (r1, code, m_bool_zero, op1_true, op1_false,
>                            op2_true, op2_false)
>           && logical_combine (r, code, m_bool_one, op1_true, op1_false,
> @@ -898,11 +903,11 @@ gori_compute::logical_combine (irange &r, enum tree_code code,
>         else
>           {
>             // The FALSE side is the union of the other 3 cases.
> -           int_range_max ff (op1_false);
> +           tmp_range ff (op1_false);
>             ff.intersect (op2_false);
> -           int_range_max tf (op1_true);
> +           tmp_range tf (op1_true);
>             tf.intersect (op2_false);
> -           int_range_max ft (op1_false);
> +           tmp_range ft (op1_false);
>             ft.intersect (op2_true);
>             r = ff;
>             r.union_ (tf);
> @@ -925,11 +930,11 @@ gori_compute::logical_combine (irange &r, enum tree_code code,
>           {
>             // The TRUE side of an OR operation will be the union of
>             // the other three combinations.
> -           int_range_max tt (op1_true);
> +           tmp_range tt (op1_true);
>             tt.intersect (op2_true);
> -           int_range_max tf (op1_true);
> +           tmp_range tf (op1_true);
>             tf.intersect (op2_false);
> -           int_range_max ft (op1_false);
> +           tmp_range ft (op1_false);
>             ft.intersect (op2_true);
>             r = tt;
>             r.union_ (tf);
> @@ -951,7 +956,7 @@ gori_compute::logical_combine (irange &r, enum tree_code code,
>  // OP_IN_CHAIN is true.
>
>  void
> -gori_compute::compute_logical_operands (irange &true_range, irange &false_range,
> +gori_compute::compute_logical_operands (vrange &true_range, vrange &false_range,
>                                         gimple *stmt,
>                                         const irange &lhs,
>                                         tree name, fur_source &src,
> @@ -1007,13 +1012,15 @@ gori_compute::compute_logical_operands (irange &true_range, irange &false_range,
>  // R, or false if no range could be calculated.
>
>  bool
> -gori_compute::compute_operand1_range (irange &r, gimple *stmt,
> -                                     const irange &lhs, tree name,
> +gori_compute::compute_operand1_range (vrange &r, gimple *stmt,
> +                                     const vrange &lhs, tree name,
>                                       fur_source &src)
>  {
> -  int_range_max op1_range, op2_range;
>    tree op1 = gimple_range_operand1 (stmt);
>    tree op2 = gimple_range_operand2 (stmt);
> +  tmp_range op1_range (TREE_TYPE (op1));
> +  tmp_range tmp (TREE_TYPE (op1));
> +  tmp_range op2_range;
>
>    // Fetch the known range for op1 in this block.
>    src.get_operand (op1_range, op1);
> @@ -1021,8 +1028,9 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt,
>    // Now range-op calcuate and put that result in r.
>    if (op2)
>      {
> +      op2_range.init (TREE_TYPE (op2));
>        src.get_operand (op2_range, op2);
> -      if (!gimple_range_calc_op1 (r, stmt, lhs, op2_range))
> +      if (!gimple_range_calc_op1 (tmp, stmt, lhs, op2_range))
>         return false;
>      }
>    else
> @@ -1030,7 +1038,7 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt,
>        // We pass op1_range to the unary operation.  Nomally it's a
>        // hidden range_for_type parameter, but sometimes having the
>        // actual range can result in better information.
> -      if (!gimple_range_calc_op1 (r, stmt, lhs, op1_range))
> +      if (!gimple_range_calc_op1 (tmp, stmt, lhs, op1_range))
>         return false;
>      }
>
> @@ -1053,7 +1061,7 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt,
>        tracer.print (idx, "Computes ");
>        print_generic_expr (dump_file, op1, TDF_SLIM);
>        fprintf (dump_file, " = ");
> -      r.dump (dump_file);
> +      tmp.dump (dump_file);
>        fprintf (dump_file, " intersect Known range : ");
>        op1_range.dump (dump_file);
>        fputc ('\n', dump_file);
> @@ -1061,13 +1069,14 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt,
>    // Intersect the calculated result with the known result and return if done.
>    if (op1 == name)
>      {
> -      r.intersect (op1_range);
> +      tmp.intersect (op1_range);
> +      r = tmp;
>        if (idx)
>         tracer.trailer (idx, "produces ", true, name, r);
>        return true;
>      }
>    // If the calculation continues, we're using op1_range as the new LHS.
> -  op1_range.intersect (r);
> +  op1_range.intersect (tmp);
>
>    if (idx)
>      tracer.trailer (idx, "produces ", true, op1, op1_range);
> @@ -1084,19 +1093,21 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt,
>  // R, or false if no range could be calculated.
>
>  bool
> -gori_compute::compute_operand2_range (irange &r, gimple *stmt,
> -                                     const irange &lhs, tree name,
> +gori_compute::compute_operand2_range (vrange &r, gimple *stmt,
> +                                     const vrange &lhs, tree name,
>                                       fur_source &src)
>  {
> -  int_range_max op1_range, op2_range;
>    tree op1 = gimple_range_operand1 (stmt);
>    tree op2 = gimple_range_operand2 (stmt);
> +  tmp_range op1_range (TREE_TYPE (op1));
> +  tmp_range op2_range (TREE_TYPE (op2));
> +  tmp_range tmp (TREE_TYPE (op2));
>
>    src.get_operand (op1_range, op1);
>    src.get_operand (op2_range, op2);
>
>    // Intersect with range for op2 based on lhs and op1.
> -  if (!gimple_range_calc_op2 (r, stmt, lhs, op1_range))
> +  if (!gimple_range_calc_op2 (tmp, stmt, lhs, op1_range))
>      return false;
>
>    unsigned idx;
> @@ -1118,7 +1129,7 @@ gori_compute::compute_operand2_range (irange &r, gimple *stmt,
>        tracer.print (idx, "Computes ");
>        print_generic_expr (dump_file, op2, TDF_SLIM);
>        fprintf (dump_file, " = ");
> -      r.dump (dump_file);
> +      tmp.dump (dump_file);
>        fprintf (dump_file, " intersect Known range : ");
>        op2_range.dump (dump_file);
>        fputc ('\n', dump_file);
> @@ -1126,13 +1137,14 @@ gori_compute::compute_operand2_range (irange &r, gimple *stmt,
>    // Intersect the calculated result with the known result and return if done.
>    if (op2 == name)
>      {
> -      r.intersect (op2_range);
> +      tmp.intersect (op2_range);
> +      r = tmp;
>        if (idx)
>         tracer.trailer (idx, " produces ", true, NULL_TREE, r);
>        return true;
>      }
>    // If the calculation continues, we're using op2_range as the new LHS.
> -  op2_range.intersect (r);
> +  op2_range.intersect (tmp);
>
>    if (idx)
>      tracer.trailer (idx, " produces ", true, op2, op2_range);
> @@ -1149,13 +1161,13 @@ gori_compute::compute_operand2_range (irange &r, gimple *stmt,
>  // R, or false if no range could be calculated.
>
>  bool
> -gori_compute::compute_operand1_and_operand2_range (irange &r,
> +gori_compute::compute_operand1_and_operand2_range (vrange &r,
>                                                    gimple *stmt,
> -                                                  const irange &lhs,
> +                                                  const vrange &lhs,
>                                                    tree name,
>                                                    fur_source &src)
>  {
> -  int_range_max op_range;
> +  tmp_range op_range (TREE_TYPE (name));
>
>    // Calculate a good a range for op2.  Since op1 == op2, this will
>    // have already included whatever the actual range of name is.
> @@ -1236,10 +1248,9 @@ gori_compute::has_edge_range_p (tree name, edge e)
>  // control edge or NAME is not defined by this edge.
>
>  bool
> -gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name,
> +gori_compute::outgoing_edge_range_p (vrange &r, edge e, tree name,
>                                      range_query &q)
>  {
> -  int_range_max lhs;
>    unsigned idx;
>
>    if ((e->flags & m_not_executable_flag))
> @@ -1252,6 +1263,7 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name,
>      }
>
>    gcc_checking_assert (gimple_range_ssa_p (name));
> +  int_range_max lhs;
>    // Determine if there is an outgoing edge.
>    gimple *stmt = outgoing.edge_range_p (lhs, e);
>    if (!stmt)
> @@ -1312,10 +1324,9 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name,
>  // edge and OP2 on the false edge.
>
>  bool
> -gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond,
> +gori_compute::condexpr_adjust (vrange &r1, vrange &r2, gimple *, tree cond,
>                                tree op1, tree op2, fur_source &src)
>  {
> -  int_range_max tmp, cond_true, cond_false;
>    tree ssa1 = gimple_range_ssa_p (op1);
>    tree ssa2 = gimple_range_ssa_p (op2);
>    if (!ssa1 && !ssa2)
> @@ -1341,15 +1352,19 @@ gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond,
>      return false;
>
>    // Pick up the current values of each part of the condition.
> -  int_range_max cl, cr;
> -  src.get_operand (cl, gimple_assign_rhs1 (cond_def));
> -  src.get_operand (cr, gimple_assign_rhs2 (cond_def));
> +  tree rhs1 = gimple_assign_rhs1 (cond_def);
> +  tree rhs2 = gimple_assign_rhs2 (cond_def);
> +  tmp_range cl (TREE_TYPE (rhs1));
> +  tmp_range cr (TREE_TYPE (rhs2));
> +  src.get_operand (cl, rhs1);
> +  src.get_operand (cr, rhs2);
>
>    tree cond_name = c1 ? c1 : c2;
>    gimple *def_stmt = SSA_NAME_DEF_STMT (cond_name);
>
>    // Evaluate the value of COND_NAME on the true and false edges, using either
>    // the op1 or op2 routines based on its location.
> +  tmp_range cond_true (type), cond_false (type);
>    if (c1)
>      {
>        if (!hand.op1_range (cond_false, type, m_bool_zero, cr))
> @@ -1380,6 +1395,7 @@ gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond,
>      }
>
>     // Now solve for SSA1 or SSA2 if they are in the dependency chain.
> +  tmp_range tmp (type);
>     if (ssa1 && in_chain_p (ssa1, cond_name))
>      {
>        if (compute_operand_range (tmp, def_stmt, cond_true, ssa1, src))
> diff --git a/gcc/gimple-range-gori.h b/gcc/gimple-range-gori.h
> index 605884e2e53..f5f691fe424 100644
> --- a/gcc/gimple-range-gori.h
> +++ b/gcc/gimple-range-gori.h
> @@ -121,7 +121,7 @@ private:
>  //   on *ANY* edge that has been seen.  FALSE indicates that the global value
>  //   is applicable everywhere that has been processed.
>  //
> -// outgoing_edge_range_p (irange &range, edge e, tree name)
> +// outgoing_edge_range_p (vrange &range, edge e, tree name)
>  //   Actually does the calculation of RANGE for name on E
>  //   This represents application of whatever static range effect edge E
>  //   may have on NAME, not any cumulative effect.
> @@ -157,8 +157,8 @@ class gori_compute : public gori_map
>  {
>  public:
>    gori_compute (int not_executable_flag = 0);
> -  bool outgoing_edge_range_p (irange &r, edge e, tree name, range_query &q);
> -  bool condexpr_adjust (irange &r1, irange &r2, gimple *s, tree cond, tree op1,
> +  bool outgoing_edge_range_p (vrange &r, edge e, tree name, range_query &q);
> +  bool condexpr_adjust (vrange &r1, vrange &r2, gimple *s, tree cond, tree op1,
>                         tree op2, fur_source &src);
>    bool has_edge_range_p (tree name, basic_block bb = NULL);
>    bool has_edge_range_p (tree name, edge e);
> @@ -166,24 +166,24 @@ public:
>  private:
>    bool may_recompute_p (tree name, edge e);
>    bool may_recompute_p (tree name, basic_block bb = NULL);
> -  bool compute_operand_range (irange &r, gimple *stmt, const irange &lhs,
> +  bool compute_operand_range (vrange &r, gimple *stmt, const vrange &lhs,
>                               tree name, class fur_source &src);
> -  bool compute_operand_range_switch (irange &r, gswitch *s, const irange &lhs,
> +  bool compute_operand_range_switch (vrange &r, gswitch *s, const vrange &lhs,
>                                      tree name, fur_source &src);
> -  bool compute_operand1_range (irange &r, gimple *stmt, const irange &lhs,
> +  bool compute_operand1_range (vrange &r, gimple *stmt, const vrange &lhs,
>                                tree name, fur_source &src);
> -  bool compute_operand2_range (irange &r, gimple *stmt, const irange &lhs,
> +  bool compute_operand2_range (vrange &r, gimple *stmt, const vrange &lhs,
>                                tree name, fur_source &src);
> -  bool compute_operand1_and_operand2_range (irange &r, gimple *stmt,
> -                                           const irange &lhs, tree name,
> +  bool compute_operand1_and_operand2_range (vrange &r, gimple *stmt,
> +                                           const vrange &lhs, tree name,
>                                             fur_source &src);
> -  void compute_logical_operands (irange &true_range, irange &false_range,
> +  void compute_logical_operands (vrange &true_range, vrange &false_range,
>                                  gimple *stmt, const irange &lhs,
>                                  tree name, fur_source &src, tree op,
>                                  bool op_in_chain);
> -  bool logical_combine (irange &r, enum tree_code code, const irange &lhs,
> -                       const irange &op1_true, const irange &op1_false,
> -                       const irange &op2_true, const irange &op2_false);
> +  bool logical_combine (vrange &r, enum tree_code code, const irange &lhs,
> +                       const vrange &op1_true, const vrange &op1_false,
> +                       const vrange &op2_true, const vrange &op2_false);
>    int_range<2> m_bool_zero;    // Boolean false cached.
>    int_range<2> m_bool_one;     // Boolean true cached.
>
> @@ -193,14 +193,14 @@ private:
>  };
>
>  // These routines provide a GIMPLE interface to the range-ops code.
> -extern bool gimple_range_calc_op1 (irange &r, const gimple *s,
> -                                  const irange &lhs_range);
> -extern bool gimple_range_calc_op1 (irange &r, const gimple *s,
> -                                  const irange &lhs_range,
> -                                  const irange &op2_range);
> -extern bool gimple_range_calc_op2 (irange &r, const gimple *s,
> -                                  const irange &lhs_range,
> -                                  const irange &op1_range);
> +extern bool gimple_range_calc_op1 (vrange &r, const gimple *s,
> +                                  const vrange &lhs_range);
> +extern bool gimple_range_calc_op1 (vrange &r, const gimple *s,
> +                                  const vrange &lhs_range,
> +                                  const vrange &op2_range);
> +extern bool gimple_range_calc_op2 (vrange &r, const gimple *s,
> +                                  const vrange &lhs_range,
> +                                  const vrange &op1_range);
>
>  // For each name that is an import into BB's exports..
>  #define FOR_EACH_GORI_IMPORT_NAME(gori, bb, name)                      \
> diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc
> index 66f433dd1d5..4819332f358 100644
> --- a/gcc/gimple-range-path.cc
> +++ b/gcc/gimple-range-path.cc
> @@ -83,7 +83,7 @@ path_range_query::clear_cache (tree name)
>  // If NAME has a cache entry, return it in R, and return TRUE.
>
>  inline bool
> -path_range_query::get_cache (irange &r, tree name)
> +path_range_query::get_cache (vrange &r, tree name)
>  {
>    if (!gimple_range_ssa_p (name))
>      return get_global_range_query ()->range_of_expr (r, name);
> @@ -98,7 +98,7 @@ path_range_query::get_cache (irange &r, tree name)
>  // Set the cache entry for NAME to R.
>
>  void
> -path_range_query::set_cache (const irange &r, tree name)
> +path_range_query::set_cache (const vrange &r, tree name)
>  {
>    unsigned v = SSA_NAME_VERSION (name);
>    bitmap_set_bit (m_has_cache_entry, v);
> @@ -149,7 +149,7 @@ path_range_query::defined_outside_path (tree name)
>  // Return the range of NAME on entry to the path.
>
>  void
> -path_range_query::range_on_path_entry (irange &r, tree name)
> +path_range_query::range_on_path_entry (vrange &r, tree name)
>  {
>    gcc_checking_assert (defined_outside_path (name));
>    basic_block entry = entry_bb ();
> @@ -168,7 +168,7 @@ path_range_query::range_on_path_entry (irange &r, tree name)
>    // block.  This can happen when we're querying a block with only an
>    // outgoing edge (no statement but the fall through edge), but for
>    // which we can determine a range on entry to the block.
> -  int_range_max tmp;
> +  tmp_range tmp (TREE_TYPE (name));
>    bool changed = false;
>    r.set_undefined ();
>    for (unsigned i = 0; i < EDGE_COUNT (entry->preds); ++i)
> @@ -190,9 +190,9 @@ path_range_query::range_on_path_entry (irange &r, tree name)
>  // Return the range of NAME at the end of the path being analyzed.
>
>  bool
> -path_range_query::internal_range_of_expr (irange &r, tree name, gimple *stmt)
> +path_range_query::internal_range_of_expr (vrange &r, tree name, gimple *stmt)
>  {
> -  if (!irange::supports_type_p (TREE_TYPE (name)))
> +  if (!vrange::supports_type_p (TREE_TYPE (name)))
>      return false;
>
>    if (get_cache (r, name))
> @@ -209,18 +209,22 @@ path_range_query::internal_range_of_expr (irange &r, tree name, gimple *stmt)
>        && range_defined_in_block (r, name, gimple_bb (stmt)))
>      {
>        if (TREE_CODE (name) == SSA_NAME)
> -       r.intersect (gimple_range_global (name));
> +       {
> +         tmp_range glob (TREE_TYPE (name));
> +         gimple_range_global (glob, name);
> +         r.intersect (glob);
> +       }
>
>        set_cache (r, name);
>        return true;
>      }
>
> -  r = gimple_range_global (name);
> +  gimple_range_global (r, name);
>    return true;
>  }
>
>  bool
> -path_range_query::range_of_expr (irange &r, tree name, gimple *stmt)
> +path_range_query::range_of_expr (vrange &r, tree name, gimple *stmt)
>  {
>    if (internal_range_of_expr (r, name, stmt))
>      {
> @@ -269,7 +273,7 @@ path_range_query::ssa_defined_in_bb (tree name, basic_block bb)
>  // calculating the PHI's range must not trigger additional lookups.
>
>  void
> -path_range_query::ssa_range_in_phi (irange &r, gphi *phi)
> +path_range_query::ssa_range_in_phi (vrange &r, gphi *phi)
>  {
>    tree name = gimple_phi_result (phi);
>    basic_block bb = gimple_bb (phi);
> @@ -283,7 +287,7 @@ path_range_query::ssa_range_in_phi (irange &r, gphi *phi)
>        // Try to fold the phi exclusively with global or cached values.
>        // This will get things like PHI <5(99), 6(88)>.  We do this by
>        // calling range_of_expr with no context.
> -      int_range_max arg_range;
> +      tmp_range arg_range (TREE_TYPE (name));
>        r.set_undefined ();
>        for (size_t i = 0; i < nargs; ++i)
>         {
> @@ -312,7 +316,7 @@ path_range_query::ssa_range_in_phi (irange &r, gphi *phi)
>           {
>             if (m_resolve)
>               {
> -               int_range_max tmp;
> +               tmp_range tmp (TREE_TYPE (name));
>                 // Using both the range on entry to the path, and the
>                 // range on this edge yields significantly better
>                 // results.
> @@ -335,7 +339,7 @@ path_range_query::ssa_range_in_phi (irange &r, gphi *phi)
>  // TRUE.  Otherwise, return FALSE.
>
>  bool
> -path_range_query::range_defined_in_block (irange &r, tree name, basic_block bb)
> +path_range_query::range_defined_in_block (vrange &r, tree name, basic_block bb)
>  {
>    gimple *def_stmt = SSA_NAME_DEF_STMT (name);
>    basic_block def_bb = gimple_bb (def_stmt);
> @@ -377,7 +381,6 @@ path_range_query::range_defined_in_block (irange &r, tree name, basic_block bb)
>  void
>  path_range_query::compute_ranges_in_phis (basic_block bb)
>  {
> -  int_range_max r;
>    auto_bitmap phi_set;
>
>    // PHIs must be resolved simultaneously on entry to the block
> @@ -390,7 +393,11 @@ path_range_query::compute_ranges_in_phis (basic_block bb)
>        gphi *phi = iter.phi ();
>        tree name = gimple_phi_result (phi);
>
> -      if (import_p (name) && range_defined_in_block (r, name, bb))
> +      if (!import_p (name))
> +       continue;
> +
> +      tmp_range r (TREE_TYPE (name));
> +      if (range_defined_in_block (r, name, bb))
>         {
>           unsigned v = SSA_NAME_VERSION (name);
>           set_cache (r, name);
> @@ -423,7 +430,6 @@ void
>  path_range_query::compute_ranges_in_block (basic_block bb)
>  {
>    bitmap_iterator bi;
> -  int_range_max r, cached_range;
>    unsigned i;
>
>    if (m_resolve && !at_entry ())
> @@ -444,6 +450,7 @@ path_range_query::compute_ranges_in_block (basic_block bb)
>    EXECUTE_IF_SET_IN_BITMAP (m_imports, 0, i, bi)
>      {
>        tree name = ssa_name (i);
> +      tmp_range r (TREE_TYPE (name));
>
>        if (gimple_code (SSA_NAME_DEF_STMT (name)) != GIMPLE_PHI
>           && range_defined_in_block (r, name, bb))
> @@ -480,8 +487,10 @@ path_range_query::compute_ranges_in_block (basic_block bb)
>
>        if (bitmap_bit_p (exports, i))
>         {
> +         tmp_range r (TREE_TYPE (name));
>           if (g.outgoing_edge_range_p (r, e, name, *this))
>             {
> +             tmp_range cached_range (TREE_TYPE (name));
>               if (get_cache (cached_range, name))
>                 r.intersect (cached_range);
>
> @@ -539,7 +548,7 @@ bool
>  path_range_query::add_to_imports (tree name, bitmap imports)
>  {
>    if (TREE_CODE (name) == SSA_NAME
> -      && irange::supports_type_p (TREE_TYPE (name)))
> +      && vrange::supports_type_p (TREE_TYPE (name)))
>      return bitmap_set_bit (imports, SSA_NAME_VERSION (name));
>    return false;
>  }
> @@ -751,11 +760,11 @@ jt_fur_source::query_relation (tree op1, tree op2)
>  // Return the range of STMT at the end of the path being analyzed.
>
>  bool
> -path_range_query::range_of_stmt (irange &r, gimple *stmt, tree)
> +path_range_query::range_of_stmt (vrange &r, gimple *stmt, tree)
>  {
>    tree type = gimple_range_type (stmt);
>
> -  if (!type || !irange::supports_type_p (type))
> +  if (!type || !vrange::supports_type_p (type))
>      return false;
>
>    // If resolving unknowns, fold the statement making use of any
> diff --git a/gcc/gimple-range-path.h b/gcc/gimple-range-path.h
> index 914983bb0aa..2c4624e4cef 100644
> --- a/gcc/gimple-range-path.h
> +++ b/gcc/gimple-range-path.h
> @@ -38,29 +38,29 @@ public:
>                        const bitmap_head *imports = NULL);
>    void compute_ranges (edge e);
>    void compute_imports (bitmap imports, basic_block exit);
> -  bool range_of_expr (irange &r, tree name, gimple * = NULL) override;
> -  bool range_of_stmt (irange &r, gimple *, tree name = NULL) override;
> +  bool range_of_expr (vrange &r, tree name, gimple * = NULL) override;
> +  bool range_of_stmt (vrange &r, gimple *, tree name = NULL) override;
>    bool unreachable_path_p ();
>    void dump (FILE *) override;
>    void debug ();
>
>  private:
> -  bool internal_range_of_expr (irange &r, tree name, gimple *);
> +  bool internal_range_of_expr (vrange &r, tree name, gimple *);
>    bool defined_outside_path (tree name);
> -  void range_on_path_entry (irange &r, tree name);
> +  void range_on_path_entry (vrange &r, tree name);
>    path_oracle *get_path_oracle () { return (path_oracle *)m_oracle; }
>
>    // Cache manipulation.
> -  void set_cache (const irange &r, tree name);
> -  bool get_cache (irange &r, tree name);
> +  void set_cache (const vrange &r, tree name);
> +  bool get_cache (vrange &r, tree name);
>    void clear_cache (tree name);
>
>    // Methods to compute ranges for the given path.
> -  bool range_defined_in_block (irange &, tree name, basic_block bb);
> +  bool range_defined_in_block (vrange &, tree name, basic_block bb);
>    void compute_ranges_in_block (basic_block bb);
>    void compute_ranges_in_phis (basic_block bb);
>    void adjust_for_non_null_uses (basic_block bb);
> -  void ssa_range_in_phi (irange &r, gphi *phi);
> +  void ssa_range_in_phi (vrange &r, gphi *phi);
>    void compute_outgoing_relations (basic_block bb, basic_block next);
>    void compute_phi_relations (basic_block bb, basic_block prev);
>    void maybe_register_phi_relation (gphi *, edge e);
> diff --git a/gcc/gimple-range-side-effect.cc b/gcc/gimple-range-side-effect.cc
> index 8d2ac35bc8d..aae087b7227 100644
> --- a/gcc/gimple-range-side-effect.cc
> +++ b/gcc/gimple-range-side-effect.cc
> @@ -58,7 +58,7 @@ non_null_loadstore (gimple *, tree op, tree, void *data)
>  // Add NAME and RANGE to the the side effect summary.
>
>  void
> -stmt_side_effects::add_range (tree name, irange &range)
> +stmt_side_effects::add_range (tree name, vrange &range)
>  {
>    m_names[num_args] = name;
>    m_ranges[num_args] = range;
> @@ -126,7 +126,7 @@ class exit_range
>  {
>  public:
>    tree name;
> -  irange *range;
> +  vrange *range;
>    exit_range *next;
>  };
>
> @@ -181,7 +181,7 @@ side_effect_manager::~side_effect_manager ()
>  // Return a non-zero range value of the appropriate type for NAME from
>  // the cache, creating it if necessary.
>
> -const irange&
> +const vrange&
>  side_effect_manager::get_nonzero (tree name)
>  {
>    unsigned v = SSA_NAME_VERSION (name);
> @@ -189,10 +189,8 @@ side_effect_manager::get_nonzero (tree name)
>      m_nonzero.safe_grow_cleared (num_ssa_names + 20);
>    if (!m_nonzero[v])
>      {
> -      tree type = TREE_TYPE (name);
> -      m_nonzero[v]
> -       = static_cast <irange *> (m_range_allocator.alloc_vrange (type));
> -      m_nonzero[v]->set_nonzero (type);
> +      m_nonzero[v] = m_range_allocator.alloc_vrange (TREE_TYPE (name));
> +      m_nonzero[v]->set_nonzero (TREE_TYPE (name));
>      }
>    return *(m_nonzero[v]);
>  }
> @@ -219,7 +217,7 @@ side_effect_manager::has_range_p (tree name, basic_block bb)
>  // to include it.
>
>  bool
> -side_effect_manager::maybe_adjust_range (irange &r, tree name, basic_block bb)
> +side_effect_manager::maybe_adjust_range (vrange &r, tree name, basic_block bb)
>  {
>    if (!has_range_p (name, bb))
>      return false;
> @@ -232,7 +230,7 @@ side_effect_manager::maybe_adjust_range (irange &r, tree name, basic_block bb)
>  // Add range R as a side effect for NAME in block BB.
>
>  void
> -side_effect_manager::add_range (tree name, basic_block bb, const irange &r)
> +side_effect_manager::add_range (tree name, basic_block bb, const vrange &r)
>  {
>    if (bb->index >= (int)m_on_exit.length ())
>      m_on_exit.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1);
> @@ -254,7 +252,7 @@ side_effect_manager::add_range (tree name, basic_block bb, const irange &r)
>    exit_range *ptr = m_on_exit[bb->index].find_ptr (name);
>    if (ptr)
>      {
> -      int_range_max cur = r;
> +      tmp_range cur (r);
>        // If no new info is added, just return.
>        if (!cur.intersect (*(ptr->range)))
>         return;
> @@ -263,7 +261,7 @@ side_effect_manager::add_range (tree name, basic_block bb, const irange &r)
>        else
>         {
>           vrange &v = cur;
> -         ptr->range = static_cast <irange *> (m_range_allocator.clone (v));
> +         ptr->range = m_range_allocator.clone (v);
>         }
>        return;
>      }
> diff --git a/gcc/gimple-range-side-effect.h b/gcc/gimple-range-side-effect.h
> index d76d6eb34f2..a7625646ed1 100644
> --- a/gcc/gimple-range-side-effect.h
> +++ b/gcc/gimple-range-side-effect.h
> @@ -33,15 +33,15 @@ public:
>    inline unsigned num () const { return num_args; }
>    inline tree name (unsigned index) const
>      { gcc_checking_assert (index < num_args); return m_names[index]; }
> -  inline const irange& range (unsigned index) const
> +  inline const vrange& range (unsigned index) const
>      { gcc_checking_assert (index < num_args); return m_ranges[index]; }
> -  void add_range (tree name, irange &range);
> +  void add_range (tree name, vrange &range);
>    void add_nonzero (tree name);
>  private:
>    unsigned num_args;
>    static const int size_limit = 10;
>    tree m_names[size_limit];
> -  int_range<3> m_ranges[size_limit];
> +  tmp_range m_ranges[size_limit];
>    inline void bump_index () { if (num_args < size_limit - 1) num_args++; }
>  };
>
> @@ -56,10 +56,10 @@ class side_effect_manager
>  public:
>    side_effect_manager (bool do_search);
>    ~side_effect_manager ();
> -  void add_range (tree name, basic_block bb, const irange &r);
> +  void add_range (tree name, basic_block bb, const vrange &r);
>    void add_nonzero (tree name, basic_block bb);
>    bool has_range_p (tree name, basic_block bb);
> -  bool maybe_adjust_range (irange &r, tree name, basic_block bb);
> +  bool maybe_adjust_range (vrange &r, tree name, basic_block bb);
>  private:
>    class exit_range_head
>    {
> @@ -71,8 +71,8 @@ private:
>    };
>    void register_all_uses (tree name);
>    vec <exit_range_head> m_on_exit;
> -  const irange &get_nonzero (tree name);
> -  vec <irange *> m_nonzero;
> +  const vrange &get_nonzero (tree name);
> +  vec <vrange *> m_nonzero;
>    bitmap m_seen;
>    bitmap_obstack m_bitmaps;
>    struct obstack m_list_obstack;
> diff --git a/gcc/gimple-range-tests.cc b/gcc/gimple-range-tests.cc
> index 572acd33d7f..84ecc486889 100644
> --- a/gcc/gimple-range-tests.cc
> +++ b/gcc/gimple-range-tests.cc
> @@ -42,8 +42,9 @@ public:
>      ASSERT_TRUE (r == expect);
>    }
>
> -  virtual bool range_of_expr (irange &r, tree expr, gimple * = NULL) override
> +  virtual bool range_of_expr (vrange &v, tree expr, gimple * = NULL) override
>    {
> +    irange &r = as_a <irange> (v);
>      if (expr == op0)
>        {
>         r.set (build_int_cst (type, 5), build_int_cst (type, 10));
> diff --git a/gcc/gimple-range-trace.cc b/gcc/gimple-range-trace.cc
> index 39971093e6d..37cf37ca885 100644
> --- a/gcc/gimple-range-trace.cc
> +++ b/gcc/gimple-range-trace.cc
> @@ -102,7 +102,7 @@ range_tracer::print (unsigned counter, const char *str)
>
>  void
>  range_tracer::trailer (unsigned counter, const char *caller, bool result,
> -                     tree name, const irange &r)
> +                     tree name, const vrange &r)
>  {
>    gcc_checking_assert (tracing && counter != 0);
>
> @@ -141,7 +141,6 @@ debug_seed_ranger (gimple_ranger &ranger)
>      }
>
>    basic_block bb;
> -  int_range_max r;
>    gimple_stmt_iterator gsi;
>    FOR_EACH_BB_FN (bb, cfun)
>      for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
> @@ -151,7 +150,11 @@ debug_seed_ranger (gimple_ranger &ranger)
>         if (is_gimple_debug (stmt))
>           continue;
>
> -       ranger.range_of_stmt (r, stmt);
> +       if (tree type = gimple_range_type (stmt))
> +         {
> +           tmp_range r (type);
> +           ranger.range_of_stmt (r, stmt);
> +         }
>        }
>  }
>
> diff --git a/gcc/gimple-range-trace.h b/gcc/gimple-range-trace.h
> index 302afda3104..3f92e51803b 100644
> --- a/gcc/gimple-range-trace.h
> +++ b/gcc/gimple-range-trace.h
> @@ -32,7 +32,7 @@ public:
>    range_tracer (const char *name = "");
>    unsigned header (const char *str);
>    void trailer (unsigned counter, const char *caller, bool result, tree name,
> -               const irange &r);
> +               const vrange &r);
>    void print (unsigned counter, const char *str);
>    inline void enable_trace () { tracing = true; }
>    inline void disable_trace () { tracing = false; }
> diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
> index 32d57c9e3db..1118feb41a5 100644
> --- a/gcc/gimple-range.cc
> +++ b/gcc/gimple-range.cc
> @@ -71,7 +71,7 @@ gimple_ranger::~gimple_ranger ()
>  }
>
>  bool
> -gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt)
> +gimple_ranger::range_of_expr (vrange &r, tree expr, gimple *stmt)
>  {
>    unsigned idx;
>    if (!gimple_range_ssa_p (expr))
> @@ -93,7 +93,7 @@ gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt)
>    // If there is no statement, just get the global value.
>    if (!stmt)
>      {
> -      int_range_max tmp;
> +      tmp_range tmp (TREE_TYPE (expr));
>        m_cache.get_global_range (r, expr);
>        // Pick up implied context information from the on-entry cache
>        // if current_bb is set.  Do not attempt any new calculations.
> @@ -137,9 +137,9 @@ gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt)
>  // Return the range of NAME on entry to block BB in R.
>
>  void
> -gimple_ranger::range_on_entry (irange &r, basic_block bb, tree name)
> +gimple_ranger::range_on_entry (vrange &r, basic_block bb, tree name)
>  {
> -  int_range_max entry_range;
> +  tmp_range entry_range (TREE_TYPE (name));
>    gcc_checking_assert (gimple_range_ssa_p (name));
>
>    unsigned idx;
> @@ -164,7 +164,7 @@ gimple_ranger::range_on_entry (irange &r, basic_block bb, tree name)
>  // Return false if no range can be calculated.
>
>  void
> -gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name)
> +gimple_ranger::range_on_exit (vrange &r, basic_block bb, tree name)
>  {
>    // on-exit from the exit block?
>    gcc_checking_assert (bb != EXIT_BLOCK_PTR_FOR_FN (cfun));
> @@ -198,10 +198,10 @@ gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name)
>  // Calculate a range for NAME on edge E and return it in R.
>
>  bool
> -gimple_ranger::range_on_edge (irange &r, edge e, tree name)
> +gimple_ranger::range_on_edge (vrange &r, edge e, tree name)
>  {
> -  int_range_max edge_range;
> -  gcc_checking_assert (irange::supports_type_p (TREE_TYPE (name)));
> +  tmp_range edge_range (TREE_TYPE (name));
> +  gcc_checking_assert (vrange::supports_type_p (TREE_TYPE (name)));
>
>    // Do not process values along abnormal edges.
>    if (e->flags & EDGE_ABNORMAL)
> @@ -249,7 +249,7 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name)
>  // fold_range wrapper for range_of_stmt to use as an internal client.
>
>  bool
> -gimple_ranger::fold_range_internal (irange &r, gimple *s, tree name)
> +gimple_ranger::fold_range_internal (vrange &r, gimple *s, tree name)
>  {
>    fold_using_range f;
>    fur_depend src (s, &(gori ()), this);
> @@ -263,7 +263,7 @@ gimple_ranger::fold_range_internal (irange &r, gimple *s, tree name)
>  // avoided.  If a range cannot be calculated, return false and UNDEFINED.
>
>  bool
> -gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name)
> +gimple_ranger::range_of_stmt (vrange &r, gimple *s, tree name)
>  {
>    bool res;
>    r.set_undefined ();
> @@ -313,7 +313,7 @@ gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name)
>         prefill_stmt_dependencies (name);
>
>        // Calculate a new value.
> -      int_range_max tmp;
> +      tmp_range tmp (TREE_TYPE (name));
>        fold_range_internal (tmp, s, name);
>
>        // Combine the new value with the old value.  This is required because
> @@ -334,7 +334,7 @@ gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name)
>  // stack if so.  R is a scratch range.
>
>  inline void
> -gimple_ranger::prefill_name (irange &r, tree name)
> +gimple_ranger::prefill_name (tmp_range &r, tree name)
>  {
>    if (!gimple_range_ssa_p (name))
>      return;
> @@ -343,6 +343,7 @@ gimple_ranger::prefill_name (irange &r, tree name)
>      return;
>
>    bool current;
> +  r.init (TREE_TYPE (name));
>    // If this op has not been processed yet, then push it on the stack
>    if (!m_cache.get_global_range (r, name, current))
>      m_stmt_list.safe_push (name);
> @@ -357,7 +358,7 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
>    if (SSA_NAME_IS_DEFAULT_DEF (ssa))
>      return;
>
> -  int_range_max r;
> +  tmp_range r;
>    unsigned idx;
>    gimple *stmt = SSA_NAME_DEF_STMT (ssa);
>    gcc_checking_assert (stmt && gimple_bb (stmt));
> @@ -388,6 +389,7 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
>             {
>               // Fold and save the value for NAME.
>               stmt = SSA_NAME_DEF_STMT (name);
> +             r.init (TREE_TYPE (name));
>               fold_range_internal (r, stmt, name);
>               // Make sure we don't lose any current global info.
>               int_range_max tmp;
> @@ -488,10 +490,11 @@ gimple_ranger::export_global_ranges ()
>    bool print_header = true;
>    for (unsigned x = 1; x < num_ssa_names; x++)
>      {
> -      int_range_max r;
> +      tmp_range r;
>        tree name = ssa_name (x);
>        if (name && !SSA_NAME_IN_FREE_LIST (name)
>           && gimple_range_ssa_p (name)
> +         && r.init (TREE_TYPE (name))
>           && m_cache.get_global_range (r, name)
>           && !r.varying_p())
>         {
> @@ -508,13 +511,17 @@ gimple_ranger::export_global_ranges ()
>               print_header = false;
>             }
>
> -         value_range vr = r;
> +         if (!irange::supports_type_p (TREE_TYPE (name)))
> +           continue;
> +
> +         vrange &v = r;
> +         value_range vr = as_a <irange> (v);
>           print_generic_expr (dump_file, name , TDF_SLIM);
>           fprintf (dump_file, "  : ");
>           vr.dump (dump_file);
>           fprintf (dump_file, "\n");
>           int_range_max same = vr;
> -         if (same != r)
> +         if (same != as_a <irange> (v))
>             {
>               fprintf (dump_file, "         irange : ");
>               r.dump (dump_file);
> @@ -532,7 +539,7 @@ gimple_ranger::dump_bb (FILE *f, basic_block bb)
>    unsigned x;
>    edge_iterator ei;
>    edge e;
> -  int_range_max range, tmp_range;
> +  tmp_range range, tmp_range;
>    fprintf (f, "\n=========== BB %d ============\n", bb->index);
>    m_cache.dump_bb (f, bb);
>
> @@ -543,6 +550,7 @@ gimple_ranger::dump_bb (FILE *f, basic_block bb)
>      {
>        tree name = ssa_name (x);
>        if (gimple_range_ssa_p (name) && SSA_NAME_DEF_STMT (name) &&
> +         range.init (TREE_TYPE (name)) &&
>           gimple_bb (SSA_NAME_DEF_STMT (name)) == bb &&
>           m_cache.get_global_range (range, name))
>         {
> @@ -564,9 +572,11 @@ gimple_ranger::dump_bb (FILE *f, basic_block bb)
>         {
>           tree name = gimple_range_ssa_p (ssa_name (x));
>           if (name && gori ().has_edge_range_p (name, e)
> +             && range.init (TREE_TYPE (name))
>               && m_cache.range_on_edge (range, e, name))
>             {
>               gimple *s = SSA_NAME_DEF_STMT (name);
> +             tmp_range.init (TREE_TYPE (name));
>               // Only print the range if this is the def block, or
>               // the on entry cache for either end of the edge is
>               // set.
> diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
> index 13d4c77883e..ca5a33e65c6 100644
> --- a/gcc/gimple-range.h
> +++ b/gcc/gimple-range.h
> @@ -48,11 +48,11 @@ class gimple_ranger : public range_query
>  public:
>    gimple_ranger (bool use_imm_uses = true);
>    ~gimple_ranger ();
> -  virtual bool range_of_stmt (irange &r, gimple *, tree name = NULL) override;
> -  virtual bool range_of_expr (irange &r, tree name, gimple * = NULL) override;
> -  virtual bool range_on_edge (irange &r, edge e, tree name) override;
> -  void range_on_entry (irange &r, basic_block bb, tree name);
> -  void range_on_exit (irange &r, basic_block bb, tree name);
> +  virtual bool range_of_stmt (vrange &r, gimple *, tree name = NULL) override;
> +  virtual bool range_of_expr (vrange &r, tree name, gimple * = NULL) override;
> +  virtual bool range_on_edge (vrange &r, edge e, tree name) override;
> +  void range_on_entry (vrange &r, basic_block bb, tree name);
> +  void range_on_exit (vrange &r, basic_block bb, tree name);
>    void export_global_ranges ();
>    inline gori_compute &gori ()  { return m_cache.m_gori; }
>    virtual void dump (FILE *f) override;
> @@ -62,8 +62,8 @@ public:
>    bool fold_stmt (gimple_stmt_iterator *gsi, tree (*) (tree));
>    void register_side_effects (gimple *s);
>  protected:
> -  bool fold_range_internal (irange &r, gimple *s, tree name);
> -  void prefill_name (irange &r, tree name);
> +  bool fold_range_internal (vrange &r, gimple *s, tree name);
> +  void prefill_name (tmp_range &r, tree name);
>    void prefill_stmt_dependencies (tree ssa);
>    ranger_cache m_cache;
>    range_tracer tracer;
> diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
> index 9357a4e576a..132d82a5240 100644
> --- a/gcc/gimple-ssa-warn-access.cc
> +++ b/gcc/gimple-ssa-warn-access.cc
> @@ -328,11 +328,11 @@ check_nul_terminated_array (GimpleOrTree expr, tree src, tree bound)
>    wide_int bndrng[2];
>    if (bound)
>      {
> -      value_range r;
> +      tmp_range r (TREE_TYPE (bound));
>
>        get_global_range_query ()->range_of_expr (r, bound);
>
> -      if (r.kind () != VR_RANGE)
> +      if (r.undefined_p () || r.varying_p ())
>         return true;
>
>        bndrng[0] = r.lower_bound ();
> @@ -2790,9 +2790,8 @@ memmodel_to_uhwi (tree ord, gimple *stmt, unsigned HOST_WIDE_INT *cstval)
>      {
>        /* Use the range query to determine constant values in the absence
>          of constant propagation (such as at -O0).  */
> -      value_range rng;
> +      tmp_range rng (TREE_TYPE (ord));
>        if (!get_range_query (cfun)->range_of_expr (rng, ord, stmt)
> -         || !rng.constant_p ()
>           || !rng.singleton_p (&ord))
>         return false;
>
> diff --git a/gcc/tree-ssa-loop-niter.cc b/gcc/tree-ssa-loop-niter.cc
> index afa51064953..8907e310c19 100644
> --- a/gcc/tree-ssa-loop-niter.cc
> +++ b/gcc/tree-ssa-loop-niter.cc
> @@ -221,7 +221,7 @@ refine_value_range_using_guard (tree type, tree var,
>    get_type_static_bounds (type, mint, maxt);
>    mpz_init (minc1);
>    mpz_init (maxc1);
> -  value_range r;
> +  tmp_range r (TREE_TYPE (varc1));
>    /* Setup range information for varc1.  */
>    if (integer_zerop (varc1))
>      {
> @@ -374,7 +374,7 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off,
>        gphi_iterator gsi;
>
>        /* Either for VAR itself...  */
> -      value_range var_range;
> +      tmp_range var_range (TREE_TYPE (var));
>        get_range_query (cfun)->range_of_expr (var_range, var);
>        rtype = var_range.kind ();
>        if (!var_range.undefined_p ())
> @@ -385,10 +385,10 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off,
>
>        /* Or for PHI results in loop->header where VAR is used as
>          PHI argument from the loop preheader edge.  */
> +      tmp_range phi_range (TREE_TYPE (var));
>        for (gsi = gsi_start_phis (loop->header); !gsi_end_p (gsi); gsi_next (&gsi))
>         {
>           gphi *phi = gsi.phi ();
> -         value_range phi_range;
>           if (PHI_ARG_DEF_FROM_EDGE (phi, e) == var
>               && get_range_query (cfun)->range_of_expr (phi_range,
>                                                     gimple_phi_result (phi))
> @@ -410,7 +410,7 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off,
>                      involved.  */
>                   if (wi::gt_p (minv, maxv, sgn))
>                     {
> -                     value_range vr;
> +                     tmp_range vr (TREE_TYPE (var));
>                       get_range_query (cfun)->range_of_expr (vr, var);
>                       rtype = vr.kind ();
>                       if (!vr.undefined_p ())
> @@ -3650,7 +3650,7 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt,
>    if (tree_int_cst_sign_bit (step))
>      {
>        wide_int max;
> -      value_range base_range;
> +      tmp_range base_range (TREE_TYPE (orig_base));
>        if (get_range_query (cfun)->range_of_expr (base_range, orig_base)
>           && !base_range.undefined_p ())
>         max = base_range.upper_bound ();
> @@ -3672,7 +3672,7 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt,
>    else
>      {
>        wide_int min;
> -      value_range base_range;
> +      tmp_range base_range (TREE_TYPE (orig_base));
>        if (get_range_query (cfun)->range_of_expr (base_range, orig_base)
>           && !base_range.undefined_p ())
>         min = base_range.lower_bound ();
> @@ -3947,7 +3947,7 @@ infer_loop_bounds_from_signedness (class loop *loop, gimple *stmt)
>
>    low = lower_bound_in_type (type, type);
>    high = upper_bound_in_type (type, type);
> -  value_range r;
> +  tmp_range r (TREE_TYPE (def));
>    get_range_query (cfun)->range_of_expr (r, def);
>    if (r.kind () == VR_RANGE)
>      {
> @@ -4997,7 +4997,7 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop)
>    if (!def_bb || !dominated_by_p (CDI_DOMINATORS, loop->latch, def_bb))
>      return false;
>
> -  value_range r;
> +  tmp_range r (TREE_TYPE (var));
>    get_range_query (cfun)->range_of_expr (r, var);
>    if (r.kind () != VR_RANGE)
>      return false;
> diff --git a/gcc/tree-ssa-threadedge.cc b/gcc/tree-ssa-threadedge.cc
> index 4eb65ca7cac..d5e285d5d4d 100644
> --- a/gcc/tree-ssa-threadedge.cc
> +++ b/gcc/tree-ssa-threadedge.cc
> @@ -1409,19 +1409,19 @@ tree
>  hybrid_jt_simplifier::simplify (gimple *stmt, gimple *, basic_block,
>                                 jt_state *state)
>  {
> -  int_range_max r;
> -
>    compute_ranges_from_state (stmt, state);
>
>    if (gimple_code (stmt) == GIMPLE_COND
>        || gimple_code (stmt) == GIMPLE_ASSIGN)
>      {
> +      tmp_range r (gimple_range_type (stmt));
>        tree ret;
>        if (m_query->range_of_stmt (r, stmt) && r.singleton_p (&ret))
>         return ret;
>      }
>    else if (gimple_code (stmt) == GIMPLE_SWITCH)
>      {
> +      int_range_max r;
>        gswitch *switch_stmt = dyn_cast <gswitch *> (stmt);
>        tree index = gimple_switch_index (switch_stmt);
>        if (m_query->range_of_expr (r, index, stmt))
> diff --git a/gcc/value-query.cc b/gcc/value-query.cc
> index 31e56eeae53..463ac179a00 100644
> --- a/gcc/value-query.cc
> +++ b/gcc/value-query.cc
> @@ -57,13 +57,13 @@ value_query::value_of_stmt (gimple *stmt, tree name)
>  // range_query default methods.
>
>  bool
> -range_query::range_on_edge (irange &r, edge, tree expr)
> +range_query::range_on_edge (vrange &r, edge, tree expr)
>  {
>    return range_of_expr (r, expr);
>  }
>
>  bool
> -range_query::range_of_stmt (irange &r, gimple *stmt, tree name)
> +range_query::range_of_stmt (vrange &r, gimple *stmt, tree name)
>  {
>    if (!name)
>      name = gimple_get_lhs (stmt);
> @@ -79,11 +79,12 @@ tree
>  range_query::value_of_expr (tree expr, gimple *stmt)
>  {
>    tree t;
> -  int_range_max r;
>
> -  if (!irange::supports_type_p (TREE_TYPE (expr)))
> +  if (!vrange::supports_type_p (TREE_TYPE (expr)))
>      return NULL_TREE;
>
> +  tmp_range r (TREE_TYPE (expr));
> +
>    if (range_of_expr (r, expr, stmt))
>      {
>        // A constant used in an unreachable block oftens returns as UNDEFINED.
> @@ -100,10 +101,10 @@ tree
>  range_query::value_on_edge (edge e, tree expr)
>  {
>    tree t;
> -  int_range_max r;
>
> -  if (!irange::supports_type_p (TREE_TYPE (expr)))
> +  if (!vrange::supports_type_p (TREE_TYPE (expr)))
>      return NULL_TREE;
> +  tmp_range r (TREE_TYPE (expr));
>    if (range_on_edge (r, e, expr))
>      {
>        // A constant used in an unreachable block oftens returns as UNDEFINED.
> @@ -121,15 +122,15 @@ tree
>  range_query::value_of_stmt (gimple *stmt, tree name)
>  {
>    tree t;
> -  int_range_max r;
>
>    if (!name)
>      name = gimple_get_lhs (stmt);
>
>    gcc_checking_assert (!name || name == gimple_get_lhs (stmt));
>
> -  if (!name || !irange::supports_type_p (TREE_TYPE (name)))
> +  if (!name || !vrange::supports_type_p (TREE_TYPE (name)))
>      return NULL_TREE;
> +  tmp_range r (TREE_TYPE (name));
>    if (range_of_stmt (r, stmt, name) && r.singleton_p (&t))
>      return t;
>    return NULL_TREE;
> @@ -187,7 +188,7 @@ range_query::~range_query ()
>  // representable, and UNDEFINED/false if not.
>
>  bool
> -range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
> +range_query::get_tree_range (vrange &r, tree expr, gimple *stmt)
>  {
>    tree type;
>    if (TYPE_P (expr))
> @@ -195,7 +196,7 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
>    else
>      type = TREE_TYPE (expr);
>
> -  if (!irange::supports_type_p (type))
> +  if (!vrange::supports_type_p (type))
>      {
>        r.set_undefined ();
>        return false;
> @@ -214,7 +215,7 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
>        return true;
>
>      case SSA_NAME:
> -      r = gimple_range_global (expr);
> +      gimple_range_global (r, expr);
>        return true;
>
>      case ADDR_EXPR:
> @@ -223,7 +224,7 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
>         bool ov;
>         if (tree_single_nonzero_warnv_p (expr, &ov))
>           {
> -           r = range_nonzero (type);
> +           r.set_nonzero (type);
>             return true;
>           }
>         break;
> @@ -237,7 +238,8 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
>        range_op_handler op (TREE_CODE (expr), type);
>        if (op)
>         {
> -         int_range_max r0, r1;
> +         tmp_range r0 (TREE_TYPE (TREE_OPERAND (expr, 0)));
> +         tmp_range r1 (TREE_TYPE (TREE_OPERAND (expr, 1)));
>           range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
>           range_of_expr (r1, TREE_OPERAND (expr, 1), stmt);
>           op.fold_range (r, type, r0, r1);
> @@ -250,11 +252,13 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
>      {
>        range_op_handler op (TREE_CODE (expr), type);
>        tree op0_type = TREE_TYPE (TREE_OPERAND (expr, 0));
> -      if (op && irange::supports_type_p (op0_type))
> +      if (op && vrange::supports_type_p (op0_type))
>         {
> -         int_range_max r0;
> +         tmp_range r0 (TREE_TYPE (TREE_OPERAND (expr, 0)));
> +         tmp_range r1 (type);
> +         r1.set_varying (type);
>           range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
> -         op.fold_range (r, type, r0, int_range<1> (type));
> +         op.fold_range (r, type, r0, r1);
>         }
>        else
>         r.set_varying (type);
> @@ -311,7 +315,7 @@ get_ssa_name_ptr_info_nonnull (const_tree name)
>  // updated.
>
>  bool
> -update_global_range (irange &r, tree name)
> +update_global_range (vrange &r, tree name)
>  {
>    tree type = TREE_TYPE (name);
>
> @@ -330,8 +334,7 @@ update_global_range (irange &r, tree name)
>        if (r.undefined_p ())
>         return false;
>
> -      value_range vr = r;
> -      set_range_info (name, vr);
> +      set_range_info (name, as_a <irange> (r));
>        return true;
>      }
>    else if (POINTER_TYPE_P (type))
> @@ -349,7 +352,7 @@ update_global_range (irange &r, tree name)
>  // return VARYING.
>
>  static void
> -get_range_global (irange &r, tree name)
> +get_range_global (vrange &r, tree name)
>  {
>    tree type = TREE_TYPE (name);
>
> @@ -369,7 +372,7 @@ get_range_global (irange &r, tree name)
>             r.set_nonzero (type);
>           else if (INTEGRAL_TYPE_P (type))
>             {
> -             get_ssa_name_range_info (r, name);
> +             get_ssa_name_range_info (as_a <irange> (r), name);
>               if (r.undefined_p ())
>                 r.set_varying (type);
>             }
> @@ -384,7 +387,8 @@ get_range_global (irange &r, tree name)
>     }
>    else if (!POINTER_TYPE_P (type) && SSA_NAME_RANGE_INFO (name))
>      {
> -      get_ssa_name_range_info (r, name);
> +      gcc_checking_assert (irange::supports_type_p (TREE_TYPE (name)));
> +      get_ssa_name_range_info (as_a <irange> (r), name);
>        if (r.undefined_p ())
>         r.set_varying (type);
>      }
> @@ -414,21 +418,19 @@ get_range_global (irange &r, tree name)
>  // See discussion here:
>  // https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571709.html
>
> -value_range
> -gimple_range_global (tree name)
> +void
> +gimple_range_global (vrange &r, tree name)
>  {
>    tree type = TREE_TYPE (name);
> -  gcc_checking_assert (TREE_CODE (name) == SSA_NAME
> -                      && irange::supports_type_p (type));
> +  gcc_checking_assert (TREE_CODE (name) == SSA_NAME);
>
>    if (SSA_NAME_IS_DEFAULT_DEF (name) || (cfun && cfun->after_inlining)
>        || is_a<gphi *> (SSA_NAME_DEF_STMT (name)))
>      {
> -      value_range vr;
> -      get_range_global (vr, name);
> -      return vr;
> +      get_range_global (r, name);
> +      return;
>      }
> -  return value_range (type);
> +  r.set_varying (type);
>  }
>
>  // ----------------------------------------------
> @@ -437,7 +439,7 @@ gimple_range_global (tree name)
>  global_range_query global_ranges;
>
>  bool
> -global_range_query::range_of_expr (irange &r, tree expr, gimple *stmt)
> +global_range_query::range_of_expr (vrange &r, tree expr, gimple *stmt)
>  {
>    tree type = TREE_TYPE (expr);
>
> @@ -456,15 +458,16 @@ global_range_query::range_of_expr (irange &r, tree expr, gimple *stmt)
>  relation_kind
>  range_query::query_relation (gimple *s, tree ssa1, tree ssa2, bool get_range)
>  {
> -  int_range_max tmp;
>    if (!m_oracle || TREE_CODE (ssa1) != SSA_NAME || TREE_CODE (ssa2) != SSA_NAME)
>      return VREL_VARYING;
>
>    // Ensure ssa1 and ssa2 have both been evaluated.
>    if (get_range)
>      {
> -      range_of_expr (tmp, ssa1, s);
> -      range_of_expr (tmp, ssa2, s);
> +      tmp_range tmp1 (TREE_TYPE (ssa1));
> +      tmp_range tmp2 (TREE_TYPE (ssa2));
> +      range_of_expr (tmp1, ssa1, s);
> +      range_of_expr (tmp2, ssa2, s);
>      }
>    return m_oracle->query_relation (gimple_bb (s), ssa1, ssa2);
>  }
> @@ -477,7 +480,6 @@ relation_kind
>  range_query::query_relation (edge e, tree ssa1, tree ssa2, bool get_range)
>  {
>    basic_block bb;
> -  int_range_max tmp;
>    if (!m_oracle || TREE_CODE (ssa1) != SSA_NAME || TREE_CODE (ssa2) != SSA_NAME)
>      return VREL_VARYING;
>
> @@ -492,6 +494,7 @@ range_query::query_relation (edge e, tree ssa1, tree ssa2, bool get_range)
>    // Ensure ssa1 and ssa2 have both been evaluated.
>    if (get_range)
>      {
> +      tmp_range tmp (TREE_TYPE (ssa1));
>        range_on_edge (tmp, e, ssa1);
>        range_on_edge (tmp, e, ssa2);
>      }
> diff --git a/gcc/value-query.h b/gcc/value-query.h
> index cf1a1d74de3..280e47e3f6b 100644
> --- a/gcc/value-query.h
> +++ b/gcc/value-query.h
> @@ -89,9 +89,9 @@ public:
>    //
>    // Note that range_of_expr must always return TRUE unless ranges are
>    // unsupported for EXPR's type (supports_type_p is false).
> -  virtual bool range_of_expr (irange &r, tree expr, gimple * = NULL) = 0;
> -  virtual bool range_on_edge (irange &r, edge, tree expr);
> -  virtual bool range_of_stmt (irange &r, gimple *, tree name = NULL);
> +  virtual bool range_of_expr (vrange &r, tree expr, gimple * = NULL) = 0;
> +  virtual bool range_on_edge (vrange &r, edge, tree expr);
> +  virtual bool range_of_stmt (vrange &r, gimple *, tree name = NULL);
>
>    // Query if there is any relation between SSA1 and SSA2.
>    relation_kind query_relation (gimple *s, tree ssa1, tree ssa2,
> @@ -110,8 +110,8 @@ public:
>  protected:
>    class value_range_equiv *allocate_value_range_equiv ();
>    void free_value_range_equiv (class value_range_equiv *);
> -  bool get_tree_range (irange &r, tree expr, gimple *stmt);
> -  bool get_arith_expr_range (irange &r, tree expr, gimple *stmt);
> +  bool get_tree_range (vrange &v, tree expr, gimple *stmt);
> +  bool get_arith_expr_range (vrange &r, tree expr, gimple *stmt);
>    relation_oracle *m_oracle;
>
>  private:
> @@ -123,7 +123,7 @@ private:
>  class global_range_query : public range_query
>  {
>  public:
> -  bool range_of_expr (irange &r, tree expr, gimple * = NULL) override;
> +  bool range_of_expr (vrange &r, tree expr, gimple * = NULL) override;
>  };
>
>  extern global_range_query global_ranges;
> @@ -143,7 +143,7 @@ get_range_query (const struct function *fun)
>    return fun->x_range_query ? fun->x_range_query : &global_ranges;
>  }
>
> -extern value_range gimple_range_global (tree name);
> -extern bool update_global_range (irange &r, tree name);
> +extern void gimple_range_global (vrange &v, tree name);
> +extern bool update_global_range (vrange &v, tree name);
>
>  #endif // GCC_QUERY_H
> diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc
> index 6f8583c8d01..9b681a46905 100644
> --- a/gcc/vr-values.cc
> +++ b/gcc/vr-values.cc
> @@ -177,7 +177,7 @@ vr_values::get_value_range (const_tree var,
>  }
>
>  bool
> -vr_values::range_of_expr (irange &r, tree expr, gimple *stmt)
> +vr_values::range_of_expr (vrange &r, tree expr, gimple *stmt)
>  {
>    if (!gimple_range_ssa_p (expr))
>      return get_tree_range (r, expr, stmt);
> @@ -1640,6 +1640,8 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
>  {
>    tree init, step, chrec, tmin, tmax, type = TREE_TYPE (var);
>    enum ev_direction dir;
> +  tmp_range trange;
> +  int_range<2> r;
>
>    chrec = instantiate_parameters (loop, analyze_scalar_evolution (loop, var));
>
> @@ -1661,11 +1663,15 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
>
>    /* If INIT is an SSA with a singleton range, set INIT to said
>       singleton, otherwise leave INIT alone.  */
> -  if (TREE_CODE (init) == SSA_NAME)
> -    query->get_value_range (init, stmt)->singleton_p (&init);
> +  if (TREE_CODE (init) == SSA_NAME
> +      && trange.init (TREE_TYPE (init))
> +      && query->range_of_expr (trange, init, stmt))
> +    trange.singleton_p (&init);
>    /* Likewise for step.  */
> -  if (TREE_CODE (step) == SSA_NAME)
> -    query->get_value_range (step, stmt)->singleton_p (&step);
> +  if (TREE_CODE (step) == SSA_NAME
> +      && trange.init (TREE_TYPE (step))
> +      && query->range_of_expr (trange, step, stmt))
> +    trange.singleton_p (&step);
>
>    /* If STEP is symbolic, we can't know whether INIT will be the
>       minimum or maximum value in the range.  Also, unless INIT is
> @@ -1699,7 +1705,8 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
>    if (TREE_CODE (step) == INTEGER_CST
>        && is_gimple_val (init)
>        && (TREE_CODE (init) != SSA_NAME
> -         || query->get_value_range (init, stmt)->kind () == VR_RANGE))
> +         || (query->range_of_expr (r, init, stmt)
> +             && r.kind () == VR_RANGE)))
>      {
>        widest_int nit;
>
> @@ -1724,7 +1731,7 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
>             {
>               value_range maxvr, vr0, vr1;
>               if (TREE_CODE (init) == SSA_NAME)
> -               vr0 = *(query->get_value_range (init, stmt));
> +               query->range_of_expr (vr0, init, stmt);
>               else if (is_gimple_min_invariant (init))
>                 vr0.set (init);
>               else
> @@ -1737,10 +1744,10 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
>               /* Likewise if the addition did.  */
>               if (maxvr.kind () == VR_RANGE)
>                 {
> -                 value_range initvr;
> +                 int_range<2> initvr;
>
>                   if (TREE_CODE (init) == SSA_NAME)
> -                   initvr = *(query->get_value_range (init, stmt));
> +                   query->range_of_expr (initvr, init, stmt);
>                   else if (is_gimple_min_invariant (init))
>                     initvr.set (init);
>                   else
> @@ -2446,7 +2453,9 @@ simplify_using_ranges::vrp_visit_cond_stmt (gcond *stmt, edge *taken_edge_p)
>           fprintf (dump_file, "\t");
>           print_generic_expr (dump_file, use);
>           fprintf (dump_file, ": ");
> -         dump_value_range (dump_file, query->get_value_range (use, stmt));
> +         tmp_range r (TREE_TYPE (use));
> +         query->range_of_expr (r, use, stmt);
> +         r.dump (dump_file);
>         }
>
>        fprintf (dump_file, "\n");
> diff --git a/gcc/vr-values.h b/gcc/vr-values.h
> index 7a377cebd01..f018d0dfc4b 100644
> --- a/gcc/vr-values.h
> +++ b/gcc/vr-values.h
> @@ -109,7 +109,7 @@ class vr_values : public range_query
>    vr_values (void);
>    ~vr_values (void);
>
> -  virtual bool range_of_expr (irange &r, tree expr, gimple *stmt) override;
> +  virtual bool range_of_expr (vrange &r, tree expr, gimple *stmt) override;
>    virtual tree value_of_expr (tree, gimple * = NULL) override;
>    virtual tree value_on_edge (edge, tree) override;
>    virtual tree value_of_stmt (gimple *, tree = NULL_TREE) override;
> --
> 2.36.1
>

[-- Attachment #2: 0005-Convert-ranger-and-clients-to-vrange.patch --]
[-- Type: text/x-patch, Size: 110765 bytes --]

From 61a1c8622a1bc65bc31d454c926428cb201e4352 Mon Sep 17 00:00:00 2001
From: Aldy Hernandez <aldyh@redhat.com>
Date: Sun, 22 May 2022 20:17:40 +0200
Subject: [PATCH] Convert ranger and clients to vrange.

Finally, the meat of the work.  Convert ranger and associated clients
to vrange.

Everything's relatively mechanical given the previous patches.  I did
include a minor cleanup in the edge code.  There's no need to check
that the type of the switch is an integer as non-integer switches are
invalid.  I verified this with an appropriately coded assert.

Tested on x86-64 & ppc64le Linux.

gcc/ChangeLog:

	* gimple-range-cache.cc (ssa_block_ranges::dump): Convert to vrange.
	(sbr_vector::sbr_vector): Same.
	(sbr_vector::grow): Same.
	(sbr_vector::set_bb_range): Same.
	(sbr_vector::get_bb_range): Same.
	(sbr_sparse_bitmap::sbr_sparse_bitmap): Same.
	(sbr_sparse_bitmap::set_bb_range): Same.
	(sbr_sparse_bitmap::get_bb_range): Same.
	(block_range_cache::set_bb_range): Same.
	(block_range_cache::get_bb_range): Same.
	(block_range_cache::dump): Same.
	(ssa_global_cache::get_global_range): Same.
	(ssa_global_cache::set_global_range): Same.
	(ssa_global_cache::clear): Same.
	(ssa_global_cache::dump): Same.
	(ranger_cache::get_global_range): Same.
	(ranger_cache::set_global_range): Same.
	(ranger_cache::range_of_def): Same.
	(ranger_cache::entry_range): Same.
	(ranger_cache::exit_range): Same.
	(ranger_cache::edge_range): Same.
	(ranger_cache::range_of_expr): Same.
	(ranger_cache::range_on_edge): Same.
	(ranger_cache::block_range): Same.
	(ranger_cache::propagate_cache): Same.
	(ranger_cache::fill_block_cache): Same.
	(ranger_cache::range_from_dom): Same.
	* gimple-range-cache.h: Same.
	* gimple-range-edge.cc (gimple_outgoing_range::get_edge_range):
	Same.
	(gimple_outgoing_range::switch_edge_range): Same.
	(gimple_outgoing_range::edge_range_p): Same.
	* gimple-range-edge.h: Same.
	* gimple-range-fold.cc (fur_source::get_operand): Same.
	(fur_source::get_phi_operand): Same.
	(fur_edge::get_operand): Same.
	(fur_edge::get_phi_operand): Same.
	(fur_stmt::get_operand): Same.
	(fur_stmt::get_phi_operand): Same.
	(fur_list::fur_list): Same.
	(fur_list::get_operand): Same.
	(fur_list::get_phi_operand): Same.
	(fold_range): Same.
	(adjust_imagpart_expr): Same.
	(adjust_realpart_expr): Same.
	(gimple_range_adjustment): Same.
	(fold_using_range::fold_stmt): Same.
	(fold_using_range::range_of_range_op): Same.
	(fold_using_range::range_of_address): Same.
	(fold_using_range::range_of_phi): Same.
	(fold_using_range::range_of_call): Same.
	(fold_using_range::range_of_builtin_call): Same.
	(fold_using_range::range_of_builtin_int_call): Same.
	(fold_using_range::range_of_cond_expr): Same.
	(fur_source::register_outgoing_edges): Same.
	* gimple-range-fold.h (fold_range): Same.
	(gimple_range_type): Same.
	(gimple_range_ssa_p): Same.
	* gimple-range-gori.cc (gimple_range_calc_op1): Same.
	(gimple_range_calc_op2): Same.
	(gori_compute::compute_operand_range_switch): Same.
	(gori_compute::compute_operand_range): Same.
	(gori_compute::logical_combine): Same.
	(gori_compute::compute_logical_operands): Same.
	(gori_compute::compute_operand1_range): Same.
	(gori_compute::compute_operand2_range): Same.
	(gori_compute::compute_operand1_and_operand2_range): Same.
	(gori_compute::outgoing_edge_range_p): Same.
	(gori_compute::condexpr_adjust): Same.
	* gimple-range-gori.h (gimple_range_calc_op1): Same.
	(gimple_range_calc_op2): Same.
	* gimple-range-path.cc (path_range_query::get_cache): Same.
	(path_range_query::set_cache): Same.
	(path_range_query::range_on_path_entry): Same.
	(path_range_query::internal_range_of_expr): Same.
	(path_range_query::range_of_expr): Same.
	(path_range_query::ssa_range_in_phi): Same.
	(path_range_query::range_defined_in_block): Same.
	(path_range_query::compute_ranges_in_phis): Same.
	(path_range_query::compute_ranges_in_block): Same.
	(path_range_query::add_to_imports): Same.
	(path_range_query::range_of_stmt): Same.
	* gimple-range-path.h: Same.
	* gimple-range-side-effect.cc (gimple_infer_range::add_range): Same.
	(gimple_infer_range::~side_effect_manager): Same.
	(gimple_infer_range::get_nonzero): Same.
	(gimple_infer_range::maybe_adjust_range): Same.
	(gimple_infer_range::add_range): Same.
	* gimple-range-infer.h: Same.
	* gimple-range-tests.cc: Same.
	* gimple-range-trace.cc (range_tracer::trailer): Same.
	(debug_seed_ranger): Same.
	* gimple-range-trace.h: Same.
	* gimple-range.cc (gimple_ranger::range_of_expr): Same.
	(gimple_ranger::range_on_entry): Same.
	(gimple_ranger::range_on_exit): Same.
	(gimple_ranger::range_on_edge): Same.
	(gimple_ranger::fold_range_internal): Same.
	(gimple_ranger::range_of_stmt): Same.
	(gimple_ranger::prefill_name): Same.
	(gimple_ranger::prefill_stmt_dependencies): Same.
	(gimple_ranger::export_global_ranges): Same.
	(gimple_ranger::dump_bb): Same.
	* gimple-range.h: Same.
	* gimple-ssa-warn-access.cc (check_nul_terminated_array): Same.
	(memmodel_to_uhwi): Same.
	* tree-ssa-loop-niter.cc (refine_value_range_using_guard): Same.
	(determine_value_range): Same.
	(record_nonwrapping_iv): Same.
	(infer_loop_bounds_from_signedness): Same.
	(scev_var_range_cant_overflow): Same.
	* tree-ssa-threadedge.cc (hybrid_jt_simplifier::simplify): Same.
	* value-query.cc (range_query::range_on_edge): Same.
	(range_query::range_of_stmt): Same.
	(range_query::value_of_expr): Same.
	(range_query::value_on_edge): Same.
	(range_query::value_of_stmt): Same.
	(range_query::get_tree_range): Same.
	(update_global_range): Same.
	(get_range_global): Same.
	(gimple_range_global): Same.
	(global_range_query::range_of_expr): Same.
	(range_query::query_relation): Same.
	* value-query.h (gimple_range_global): Same.
	(update_global_range): Same.
	* vr-values.cc (vr_values::range_of_expr): Same.
	(bounds_of_var_in_loop): Same.
	(simplify_using_ranges::vrp_visit_cond_stmt): Same.
	* vr-values.h (class vr_values): Same.
	* tree-ssa-loop-unswitch.cc (unswitch_predicate): Same.
---
 gcc/gimple-range-cache.cc     | 140 +++++++++++++++++----------------
 gcc/gimple-range-cache.h      |  32 ++++----
 gcc/gimple-range-edge.cc      |  12 +--
 gcc/gimple-range-edge.h       |   2 +-
 gcc/gimple-range-fold.cc      | 141 ++++++++++++++++++++--------------
 gcc/gimple-range-fold.h       |  37 ++++-----
 gcc/gimple-range-gori.cc      | 115 +++++++++++++++------------
 gcc/gimple-range-gori.h       |  42 +++++-----
 gcc/gimple-range-infer.cc     |  20 +++--
 gcc/gimple-range-infer.h      |  14 ++--
 gcc/gimple-range-path.cc      |  47 +++++++-----
 gcc/gimple-range-path.h       |  16 ++--
 gcc/gimple-range-tests.cc     |   3 +-
 gcc/gimple-range-trace.cc     |   9 ++-
 gcc/gimple-range-trace.h      |   2 +-
 gcc/gimple-range.cc           |  64 +++++++++------
 gcc/gimple-range.h            |  14 ++--
 gcc/gimple-ssa-warn-access.cc |   7 +-
 gcc/tree-ssa-loop-niter.cc    |  16 ++--
 gcc/tree-ssa-loop-unswitch.cc |  14 ++--
 gcc/tree-ssa-threadedge.cc    |   4 +-
 gcc/value-query.cc            |  73 +++++++++---------
 gcc/value-query.h             |  16 ++--
 gcc/vr-values.cc              |  56 +++++++++-----
 gcc/vr-values.h               |   2 +-
 25 files changed, 492 insertions(+), 406 deletions(-)

diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 25ade1300af..85eed4421f4 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -44,11 +44,14 @@ along with GCC; see the file COPYING3.  If not see
 class ssa_block_ranges
 {
 public:
-  virtual bool set_bb_range (const_basic_block bb, const irange &r) = 0;
-  virtual bool get_bb_range (irange &r, const_basic_block bb) = 0;
+  ssa_block_ranges (tree t) : m_type (t) { }
+  virtual bool set_bb_range (const_basic_block bb, const vrange &r) = 0;
+  virtual bool get_bb_range (vrange &r, const_basic_block bb) = 0;
   virtual bool bb_range_p (const_basic_block bb) = 0;
 
   void dump(FILE *f);
+private:
+  tree m_type;
 };
 
 // Print the list of known ranges for file F in a nice format.
@@ -57,7 +60,7 @@ void
 ssa_block_ranges::dump (FILE *f)
 {
   basic_block bb;
-  int_range_max r;
+  Value_Range r (m_type);
 
   FOR_EACH_BB_FN (bb, cfun)
     if (get_bb_range (r, bb))
@@ -77,14 +80,14 @@ class sbr_vector : public ssa_block_ranges
 public:
   sbr_vector (tree t, vrange_allocator *allocator);
 
-  virtual bool set_bb_range (const_basic_block bb, const irange &r) override;
-  virtual bool get_bb_range (irange &r, const_basic_block bb) override;
+  virtual bool set_bb_range (const_basic_block bb, const vrange &r) override;
+  virtual bool get_bb_range (vrange &r, const_basic_block bb) override;
   virtual bool bb_range_p (const_basic_block bb) override;
 protected:
-  irange **m_tab;	// Non growing vector.
+  vrange **m_tab;	// Non growing vector.
   int m_tab_size;
-  int_range<2> m_varying;
-  int_range<2> m_undefined;
+  vrange *m_varying;
+  vrange *m_undefined;
   tree m_type;
   vrange_allocator *m_range_allocator;
   void grow ();
@@ -94,18 +97,21 @@ protected:
 // Initialize a block cache for an ssa_name of type T.
 
 sbr_vector::sbr_vector (tree t, vrange_allocator *allocator)
+  : ssa_block_ranges (t)
 {
   gcc_checking_assert (TYPE_P (t));
   m_type = t;
   m_range_allocator = allocator;
   m_tab_size = last_basic_block_for_fn (cfun) + 1;
-  m_tab = static_cast <irange **>
-    (allocator->alloc (m_tab_size * sizeof (irange *)));
-  memset (m_tab, 0, m_tab_size * sizeof (irange *));
+  m_tab = static_cast <vrange **>
+    (allocator->alloc (m_tab_size * sizeof (vrange *)));
+  memset (m_tab, 0, m_tab_size * sizeof (vrange *));
 
   // Create the cached type range.
-  m_varying.set_varying (t);
-  m_undefined.set_undefined ();
+  m_varying = m_range_allocator->alloc_vrange (t);
+  m_undefined = m_range_allocator->alloc_vrange (t);
+  m_varying->set_varying (t);
+  m_undefined->set_undefined ();
 }
 
 // Grow the vector when the CFG has increased in size.
@@ -122,10 +128,10 @@ sbr_vector::grow ()
   int new_size = inc + curr_bb_size;
 
   // Allocate new memory, copy the old vector and clear the new space.
-  irange **t = static_cast <irange **>
-    (m_range_allocator->alloc (new_size * sizeof (irange *)));
-  memcpy (t, m_tab, m_tab_size * sizeof (irange *));
-  memset (t + m_tab_size, 0, (new_size - m_tab_size) * sizeof (irange *));
+  vrange **t = static_cast <vrange **>
+    (m_range_allocator->alloc (new_size * sizeof (vrange *)));
+  memcpy (t, m_tab, m_tab_size * sizeof (vrange *));
+  memset (t + m_tab_size, 0, (new_size - m_tab_size) * sizeof (vrange *));
 
   m_tab = t;
   m_tab_size = new_size;
@@ -134,15 +140,15 @@ sbr_vector::grow ()
 // Set the range for block BB to be R.
 
 bool
-sbr_vector::set_bb_range (const_basic_block bb, const irange &r)
+sbr_vector::set_bb_range (const_basic_block bb, const vrange &r)
 {
-  irange *m;
+  vrange *m;
   if (bb->index >= m_tab_size)
     grow ();
   if (r.varying_p ())
-    m = &m_varying;
+    m = m_varying;
   else if (r.undefined_p ())
-    m = &m_undefined;
+    m = m_undefined;
   else
     m = m_range_allocator->clone (r);
   m_tab[bb->index] = m;
@@ -153,11 +159,11 @@ sbr_vector::set_bb_range (const_basic_block bb, const irange &r)
 // there is no range.
 
 bool
-sbr_vector::get_bb_range (irange &r, const_basic_block bb)
+sbr_vector::get_bb_range (vrange &r, const_basic_block bb)
 {
   if (bb->index >= m_tab_size)
     return false;
-  irange *m = m_tab[bb->index];
+  vrange *m = m_tab[bb->index];
   if (m)
     {
       r = *m;
@@ -193,14 +199,14 @@ class sbr_sparse_bitmap : public ssa_block_ranges
 {
 public:
   sbr_sparse_bitmap (tree t, vrange_allocator *allocator, bitmap_obstack *bm);
-  virtual bool set_bb_range (const_basic_block bb, const irange &r) override;
-  virtual bool get_bb_range (irange &r, const_basic_block bb) override;
+  virtual bool set_bb_range (const_basic_block bb, const vrange &r) override;
+  virtual bool get_bb_range (vrange &r, const_basic_block bb) override;
   virtual bool bb_range_p (const_basic_block bb) override;
 private:
   void bitmap_set_quad (bitmap head, int quad, int quad_value);
   int bitmap_get_quad (const_bitmap head, int quad);
   vrange_allocator *m_range_allocator;
-  irange *m_range[SBR_NUM];
+  vrange *m_range[SBR_NUM];
   bitmap_head bitvec;
   tree m_type;
 };
@@ -209,6 +215,7 @@ private:
 
 sbr_sparse_bitmap::sbr_sparse_bitmap (tree t, vrange_allocator *allocator,
 				      bitmap_obstack *bm)
+  : ssa_block_ranges (t)
 {
   gcc_checking_assert (TYPE_P (t));
   m_type = t;
@@ -216,16 +223,14 @@ sbr_sparse_bitmap::sbr_sparse_bitmap (tree t, vrange_allocator *allocator,
   bitmap_tree_view (&bitvec);
   m_range_allocator = allocator;
   // Pre-cache varying.
-  m_range[0] = static_cast <irange *> (m_range_allocator->alloc_vrange (t));
+  m_range[0] = m_range_allocator->alloc_vrange (t);
   m_range[0]->set_varying (t);
   // Pre-cache zero and non-zero values for pointers.
   if (POINTER_TYPE_P (t))
     {
-      m_range[1]
-	= static_cast <irange *> (m_range_allocator->alloc_vrange (t));
+      m_range[1] = m_range_allocator->alloc_vrange (t);
       m_range[1]->set_nonzero (t);
-      m_range[2]
-	= static_cast <irange *> (m_range_allocator->alloc_vrange (t));
+      m_range[2] = m_range_allocator->alloc_vrange (t);
       m_range[2]->set_zero (t);
     }
   else
@@ -257,7 +262,7 @@ sbr_sparse_bitmap::bitmap_get_quad (const_bitmap head, int quad)
 // Set the range on entry to basic block BB to R.
 
 bool
-sbr_sparse_bitmap::set_bb_range (const_basic_block bb, const irange &r)
+sbr_sparse_bitmap::set_bb_range (const_basic_block bb, const vrange &r)
 {
   if (r.undefined_p ())
     {
@@ -283,7 +288,7 @@ sbr_sparse_bitmap::set_bb_range (const_basic_block bb, const irange &r)
 // there is no range.
 
 bool
-sbr_sparse_bitmap::get_bb_range (irange &r, const_basic_block bb)
+sbr_sparse_bitmap::get_bb_range (vrange &r, const_basic_block bb)
 {
   int value = bitmap_get_quad (&bitvec, bb->index);
 
@@ -333,7 +338,7 @@ block_range_cache::~block_range_cache ()
 
 bool
 block_range_cache::set_bb_range (tree name, const_basic_block bb,
-				 const irange &r)
+				 const vrange &r)
 {
   unsigned v = SSA_NAME_VERSION (name);
   if (v >= m_ssa_ranges.length ())
@@ -379,7 +384,7 @@ block_range_cache::query_block_ranges (tree name)
 // is one.
 
 bool
-block_range_cache::get_bb_range (irange &r, tree name, const_basic_block bb)
+block_range_cache::get_bb_range (vrange &r, tree name, const_basic_block bb)
 {
   ssa_block_ranges *ptr = query_block_ranges (name);
   if (ptr)
@@ -423,12 +428,13 @@ void
 block_range_cache::dump (FILE *f, basic_block bb, bool print_varying)
 {
   unsigned x;
-  int_range_max r;
   bool summarize_varying = false;
   for (x = 1; x < m_ssa_ranges.length (); ++x)
     {
       if (!gimple_range_ssa_p (ssa_name (x)))
 	continue;
+
+      Value_Range r (TREE_TYPE (ssa_name (x)));
       if (m_ssa_ranges[x] && m_ssa_ranges[x]->get_bb_range (r, bb))
 	{
 	  if (!print_varying && r.varying_p ())
@@ -450,6 +456,8 @@ block_range_cache::dump (FILE *f, basic_block bb, bool print_varying)
 	{
 	  if (!gimple_range_ssa_p (ssa_name (x)))
 	    continue;
+
+	  Value_Range r (TREE_TYPE (ssa_name (x)));
 	  if (m_ssa_ranges[x] && m_ssa_ranges[x]->get_bb_range (r, bb))
 	    {
 	      if (r.varying_p ())
@@ -485,13 +493,13 @@ ssa_global_cache::~ssa_global_cache ()
 // Return the value in R.
 
 bool
-ssa_global_cache::get_global_range (irange &r, tree name) const
+ssa_global_cache::get_global_range (vrange &r, tree name) const
 {
   unsigned v = SSA_NAME_VERSION (name);
   if (v >= m_tab.length ())
     return false;
 
-  irange *stow = m_tab[v];
+  vrange *stow = m_tab[v];
   if (!stow)
     return false;
   r = *stow;
@@ -502,13 +510,13 @@ ssa_global_cache::get_global_range (irange &r, tree name) const
 // Return TRUE if there was already a range set, otherwise false.
 
 bool
-ssa_global_cache::set_global_range (tree name, const irange &r)
+ssa_global_cache::set_global_range (tree name, const vrange &r)
 {
   unsigned v = SSA_NAME_VERSION (name);
   if (v >= m_tab.length ())
     m_tab.safe_grow_cleared (num_ssa_names + 1);
 
-  irange *m = m_tab[v];
+  vrange *m = m_tab[v];
   if (m && m->fits_p (r))
     *m = r;
   else
@@ -533,7 +541,7 @@ void
 ssa_global_cache::clear ()
 {
   if (m_tab.address ())
-    memset (m_tab.address(), 0, m_tab.length () * sizeof (irange *));
+    memset (m_tab.address(), 0, m_tab.length () * sizeof (vrange *));
 }
 
 // Dump the contents of the global cache to F.
@@ -545,9 +553,10 @@ ssa_global_cache::dump (FILE *f)
   bool print_header = true;
   for (unsigned x = 1; x < num_ssa_names; x++)
     {
-      int_range_max r;
-      if (gimple_range_ssa_p (ssa_name (x)) &&
-	  get_global_range (r, ssa_name (x))  && !r.varying_p ())
+      if (!gimple_range_ssa_p (ssa_name (x)))
+	continue;
+      Value_Range r (TREE_TYPE (ssa_name (x)));
+      if (get_global_range (r, ssa_name (x)) && !r.varying_p ())
 	{
 	  if (print_header)
 	    {
@@ -809,11 +818,11 @@ ranger_cache::dump_bb (FILE *f, basic_block bb)
 // global range is not set, and return the legacy global value in R.
 
 bool
-ranger_cache::get_global_range (irange &r, tree name) const
+ranger_cache::get_global_range (vrange &r, tree name) const
 {
   if (m_globals.get_global_range (r, name))
     return true;
-  r = gimple_range_global (name);
+  gimple_range_global (r, name);
   return false;
 }
 
@@ -825,7 +834,7 @@ ranger_cache::get_global_range (irange &r, tree name) const
 // After this call, the global cache will have a value.
 
 bool
-ranger_cache::get_global_range (irange &r, tree name, bool &current_p)
+ranger_cache::get_global_range (vrange &r, tree name, bool &current_p)
 {
   bool had_global = get_global_range (r, name);
 
@@ -847,7 +856,7 @@ ranger_cache::get_global_range (irange &r, tree name, bool &current_p)
 //  Set the global range of NAME to R and give it a timestamp.
 
 void
-ranger_cache::set_global_range (tree name, const irange &r)
+ranger_cache::set_global_range (tree name, const vrange &r)
 {
   if (m_globals.set_global_range (name, r))
     {
@@ -882,7 +891,7 @@ ranger_cache::set_global_range (tree name, const irange &r)
 // get the best global value available.
 
 void
-ranger_cache::range_of_def (irange &r, tree name, basic_block bb)
+ranger_cache::range_of_def (vrange &r, tree name, basic_block bb)
 {
   gcc_checking_assert (gimple_range_ssa_p (name));
   gcc_checking_assert (!bb || bb == gimple_bb (SSA_NAME_DEF_STMT (name)));
@@ -895,7 +904,7 @@ ranger_cache::range_of_def (irange &r, tree name, basic_block bb)
       if (gimple_get_lhs (s) == name)
 	fold_range (r, s, get_global_range_query ());
       else
-	r = gimple_range_global (name);
+	gimple_range_global (r, name);
     }
 }
 
@@ -903,12 +912,12 @@ ranger_cache::range_of_def (irange &r, tree name, basic_block bb)
 // lookups.
 
 void
-ranger_cache::entry_range (irange &r, tree name, basic_block bb,
+ranger_cache::entry_range (vrange &r, tree name, basic_block bb,
 			   enum rfd_mode mode)
 {
   if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun))
     {
-      r = gimple_range_global (name);
+      gimple_range_global (r, name);
       return;
     }
 
@@ -923,12 +932,12 @@ ranger_cache::entry_range (irange &r, tree name, basic_block bb,
 // lookups.
 
 void
-ranger_cache::exit_range (irange &r, tree name, basic_block bb,
+ranger_cache::exit_range (vrange &r, tree name, basic_block bb,
 			  enum rfd_mode mode)
 {
   if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun))
     {
-      r = gimple_range_global (name);
+      gimple_range_global (r, name);
       return;
     }
 
@@ -944,7 +953,7 @@ ranger_cache::exit_range (irange &r, tree name, basic_block bb,
 // Always returns a range and true.
 
 bool
-ranger_cache::edge_range (irange &r, edge e, tree name, enum rfd_mode mode)
+ranger_cache::edge_range (vrange &r, edge e, tree name, enum rfd_mode mode)
 {
   exit_range (r, name, e->src, mode);
   // If this is not an abnormal edge, check for inferred ranges on exit.
@@ -961,7 +970,7 @@ ranger_cache::edge_range (irange &r, edge e, tree name, enum rfd_mode mode)
 // Implement range_of_expr.
 
 bool
-ranger_cache::range_of_expr (irange &r, tree name, gimple *stmt)
+ranger_cache::range_of_expr (vrange &r, tree name, gimple *stmt)
 {
   if (!gimple_range_ssa_p (name))
     {
@@ -985,7 +994,7 @@ ranger_cache::range_of_expr (irange &r, tree name, gimple *stmt)
 // the current cache values.
 
 bool
-ranger_cache::range_on_edge (irange &r, edge e, tree expr)
+ranger_cache::range_on_edge (vrange &r, edge e, tree expr)
 {
   if (gimple_range_ssa_p (expr))
     return edge_range (r, e, expr, RFD_NONE);
@@ -997,7 +1006,7 @@ ranger_cache::range_on_edge (irange &r, edge e, tree expr)
 // def block for NAME.  Otherwise, return false if the cache is empty.
 
 bool
-ranger_cache::block_range (irange &r, basic_block bb, tree name, bool calc)
+ranger_cache::block_range (vrange &r, basic_block bb, tree name, bool calc)
 {
   gcc_checking_assert (gimple_range_ssa_p (name));
 
@@ -1041,9 +1050,10 @@ ranger_cache::propagate_cache (tree name)
   basic_block bb;
   edge_iterator ei;
   edge e;
-  int_range_max new_range;
-  int_range_max current_range;
-  int_range_max e_range;
+  tree type = TREE_TYPE (name);
+  Value_Range new_range (type);
+  Value_Range current_range (type);
+  Value_Range e_range (type);
 
   // Process each block by seeing if its calculated range on entry is
   // the same as its cached value. If there is a difference, update
@@ -1178,8 +1188,8 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
 {
   edge_iterator ei;
   edge e;
-  int_range_max block_result;
-  int_range_max undefined;
+  Value_Range block_result (TREE_TYPE (name));
+  Value_Range undefined (TREE_TYPE (name));
 
   // At this point we shouldn't be looking at the def, entry or exit block.
   gcc_checking_assert (bb != def_bb && bb != ENTRY_BLOCK_PTR_FOR_FN (cfun) &&
@@ -1232,7 +1242,7 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
       FOR_EACH_EDGE (e, ei, node->preds)
 	{
 	  basic_block pred = e->src;
-	  int_range_max r;
+	  Value_Range r (TREE_TYPE (name));
 
 	  if (DEBUG_RANGE_CACHE)
 	    fprintf (dump_file, "  %d->%d ",e->src->index, e->dest->index);
@@ -1306,7 +1316,7 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
 // dominator tree based on MODE.
 
 bool
-ranger_cache::range_from_dom (irange &r, tree name, basic_block start_bb,
+ranger_cache::range_from_dom (vrange &r, tree name, basic_block start_bb,
 			      enum rfd_mode mode)
 {
   if (mode == RFD_NONE || !dom_info_available_p (CDI_DOMINATORS))
diff --git a/gcc/gimple-range-cache.h b/gcc/gimple-range-cache.h
index 73d12f35abe..1e4b5b30565 100644
--- a/gcc/gimple-range-cache.h
+++ b/gcc/gimple-range-cache.h
@@ -34,8 +34,8 @@ public:
   block_range_cache ();
   ~block_range_cache ();
 
-  bool set_bb_range (tree name, const_basic_block bb, const irange &r);
-  bool get_bb_range (irange &r, tree name, const_basic_block bb);
+  bool set_bb_range (tree name, const_basic_block bb, const vrange &v);
+  bool get_bb_range (vrange &v, tree name, const_basic_block bb);
   bool bb_range_p (tree name, const_basic_block bb);
 
   void dump (FILE *f);
@@ -57,13 +57,13 @@ class ssa_global_cache
 public:
   ssa_global_cache ();
   ~ssa_global_cache ();
-  bool get_global_range (irange &r, tree name) const;
-  bool set_global_range (tree name, const irange &r);
+  bool get_global_range (vrange &r, tree name) const;
+  bool set_global_range (tree name, const vrange &r);
   void clear_global_range (tree name);
   void clear ();
   void dump (FILE *f = stderr);
 private:
-  vec<irange *> m_tab;
+  vec<vrange *> m_tab;
   vrange_allocator *m_range_allocator;
 };
 
@@ -77,13 +77,13 @@ public:
   ranger_cache (int not_executable_flag, bool use_imm_uses);
   ~ranger_cache ();
 
-  virtual bool range_of_expr (irange &r, tree name, gimple *stmt);
-  virtual bool range_on_edge (irange &r, edge e, tree expr);
-  bool block_range (irange &r, basic_block bb, tree name, bool calc = true);
+  virtual bool range_of_expr (vrange &r, tree name, gimple *stmt);
+  virtual bool range_on_edge (vrange &r, edge e, tree expr);
+  bool block_range (vrange &r, basic_block bb, tree name, bool calc = true);
 
-  bool get_global_range (irange &r, tree name) const;
-  bool get_global_range (irange &r, tree name, bool &current_p);
-  void set_global_range (tree name, const irange &r);
+  bool get_global_range (vrange &r, tree name) const;
+  bool get_global_range (vrange &r, tree name, bool &current_p);
+  void set_global_range (tree name, const vrange &r);
 
   void propagate_updated_value (tree name, basic_block bb);
 
@@ -106,11 +106,11 @@ private:
       RFD_READ_ONLY,	// Scan DOM tree, do not write to cache.
       RFD_FILL		// Scan DOM tree, updating important nodes.
     };
-  bool range_from_dom (irange &r, tree name, basic_block bb, enum rfd_mode);
-  void range_of_def (irange &r, tree name, basic_block bb = NULL);
-  void entry_range (irange &r, tree expr, basic_block bb, enum rfd_mode);
-  void exit_range (irange &r, tree expr, basic_block bb, enum rfd_mode);
-  bool edge_range (irange &r, edge e, tree name, enum rfd_mode);
+  bool range_from_dom (vrange &r, tree name, basic_block bb, enum rfd_mode);
+  void range_of_def (vrange &r, tree name, basic_block bb = NULL);
+  void entry_range (vrange &r, tree expr, basic_block bb, enum rfd_mode);
+  void exit_range (vrange &r, tree expr, basic_block bb, enum rfd_mode);
+  bool edge_range (vrange &r, edge e, tree name, enum rfd_mode);
 
   vec<basic_block> m_workback;
   class update_list *m_update;
diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc
index 5264e627c9a..6fe33408f7e 100644
--- a/gcc/gimple-range-edge.cc
+++ b/gcc/gimple-range-edge.cc
@@ -83,11 +83,8 @@ gimple_outgoing_range::~gimple_outgoing_range ()
 // Use a cached value if it exists, or calculate it if not.
 
 bool
-gimple_outgoing_range::get_edge_range (irange &r, gimple *s, edge e)
+gimple_outgoing_range::switch_edge_range (irange &r, gswitch *sw, edge e)
 {
-  gcc_checking_assert (is_a<gswitch *> (s));
-  gswitch *sw = as_a<gswitch *> (s);
-
   // ADA currently has cases where the index is 64 bits and the case
   // arguments are 32 bit, causing a trap when we create a case_range.
   // Until this is resolved (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87798)
@@ -204,12 +201,9 @@ gimple_outgoing_range::edge_range_p (irange &r, edge e)
 
   gcc_checking_assert (is_a<gswitch *> (s));
   gswitch *sw = as_a<gswitch *> (s);
-  tree type = TREE_TYPE (gimple_switch_index (sw));
-
-  if (!irange::supports_type_p (type))
-    return NULL;
 
-  if (get_edge_range (r, sw, e))
+  // Switches can only be integers.
+  if (switch_edge_range (as_a <irange> (r), sw, e))
     return s;
 
   return NULL;
diff --git a/gcc/gimple-range-edge.h b/gcc/gimple-range-edge.h
index ce383b0aa6f..a9c4af8715b 100644
--- a/gcc/gimple-range-edge.h
+++ b/gcc/gimple-range-edge.h
@@ -43,7 +43,7 @@ public:
   gimple *edge_range_p (irange &r, edge e);
 private:
   void calc_switch_ranges (gswitch *sw);
-  bool get_edge_range (irange &r, gimple *s, edge e);
+  bool switch_edge_range (irange &r, gswitch *sw, edge e);
 
   int m_max_edges;
   hash_map<edge, irange *> *m_edge_table;
diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index c53d2863d5e..c1a801668c4 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -60,7 +60,7 @@ fur_source::fur_source (range_query *q)
 // Invoke range_of_expr on EXPR.
 
 bool
-fur_source::get_operand (irange &r, tree expr)
+fur_source::get_operand (vrange &r, tree expr)
 {
   return m_query->range_of_expr (r, expr);
 }
@@ -69,7 +69,7 @@ fur_source::get_operand (irange &r, tree expr)
 // range_query to get the range on the edge.
 
 bool
-fur_source::get_phi_operand (irange &r, tree expr, edge e)
+fur_source::get_phi_operand (vrange &r, tree expr, edge e)
 {
   return m_query->range_on_edge (r, e, expr);
 }
@@ -109,8 +109,8 @@ class fur_edge : public fur_source
 {
 public:
   fur_edge (edge e, range_query *q = NULL);
-  virtual bool get_operand (irange &r, tree expr) override;
-  virtual bool get_phi_operand (irange &r, tree expr, edge e) override;
+  virtual bool get_operand (vrange &r, tree expr) override;
+  virtual bool get_phi_operand (vrange &r, tree expr, edge e) override;
 private:
   edge m_edge;
 };
@@ -126,7 +126,7 @@ fur_edge::fur_edge (edge e, range_query *q) : fur_source (q)
 // Get the value of EXPR on edge m_edge.
 
 bool
-fur_edge::get_operand (irange &r, tree expr)
+fur_edge::get_operand (vrange &r, tree expr)
 {
   return m_query->range_on_edge (r, m_edge, expr);
 }
@@ -135,7 +135,7 @@ fur_edge::get_operand (irange &r, tree expr)
 // range_query to get the range on the edge.
 
 bool
-fur_edge::get_phi_operand (irange &r, tree expr, edge e)
+fur_edge::get_phi_operand (vrange &r, tree expr, edge e)
 {
   // Edge to edge recalculations not supoprted yet, until we sort it out.
   gcc_checking_assert (e == m_edge);
@@ -152,7 +152,7 @@ fur_stmt::fur_stmt (gimple *s, range_query *q) : fur_source (q)
 // Retreive range of EXPR as it occurs as a use on stmt M_STMT.
 
 bool
-fur_stmt::get_operand (irange &r, tree expr)
+fur_stmt::get_operand (vrange &r, tree expr)
 {
   return m_query->range_of_expr (r, expr, m_stmt);
 }
@@ -161,7 +161,7 @@ fur_stmt::get_operand (irange &r, tree expr)
 // range_query to get the range on the edge.
 
 bool
-fur_stmt::get_phi_operand (irange &r, tree expr, edge e)
+fur_stmt::get_phi_operand (vrange &r, tree expr, edge e)
 {
   // Pick up the range of expr from edge E.
   fur_edge e_src (e, m_query);
@@ -214,42 +214,42 @@ fur_depend::register_relation (edge e, relation_kind k, tree op1, tree op2)
 class fur_list : public fur_source
 {
 public:
-  fur_list (irange &r1);
-  fur_list (irange &r1, irange &r2);
-  fur_list (unsigned num, irange *list);
-  virtual bool get_operand (irange &r, tree expr) override;
-  virtual bool get_phi_operand (irange &r, tree expr, edge e) override;
+  fur_list (vrange &r1);
+  fur_list (vrange &r1, vrange &r2);
+  fur_list (unsigned num, vrange **list);
+  virtual bool get_operand (vrange &r, tree expr) override;
+  virtual bool get_phi_operand (vrange &r, tree expr, edge e) override;
 private:
-  int_range_max m_local[2];
-  irange *m_list;
+  vrange *m_local[2];
+  vrange **m_list;
   unsigned m_index;
   unsigned m_limit;
 };
 
 // One range supplied for unary operations.
 
-fur_list::fur_list (irange &r1) : fur_source (NULL)
+fur_list::fur_list (vrange &r1) : fur_source (NULL)
 {
   m_list = m_local;
   m_index = 0;
   m_limit = 1;
-  m_local[0] = r1;
+  m_local[0] = &r1;
 }
 
 // Two ranges supplied for binary operations.
 
-fur_list::fur_list (irange &r1, irange &r2) : fur_source (NULL)
+fur_list::fur_list (vrange &r1, vrange &r2) : fur_source (NULL)
 {
   m_list = m_local;
   m_index = 0;
   m_limit = 2;
-  m_local[0] = r1;
-  m_local[1] = r2;
+  m_local[0] = &r1;
+  m_local[1] = &r2;
 }
 
 // Arbitrary number of ranges in a vector.
 
-fur_list::fur_list (unsigned num, irange *list) : fur_source (NULL)
+fur_list::fur_list (unsigned num, vrange **list) : fur_source (NULL)
 {
   m_list = list;
   m_index = 0;
@@ -259,18 +259,18 @@ fur_list::fur_list (unsigned num, irange *list) : fur_source (NULL)
 // Get the next operand from the vector, ensure types are compatible.
 
 bool
-fur_list::get_operand (irange &r, tree expr)
+fur_list::get_operand (vrange &r, tree expr)
 {
   if (m_index >= m_limit)
     return m_query->range_of_expr (r, expr);
-  r = m_list[m_index++];
+  r = *m_list[m_index++];
   gcc_checking_assert (range_compatible_p (TREE_TYPE (expr), r.type ()));
   return true;
 }
 
 // This will simply pick the next operand from the vector.
 bool
-fur_list::get_phi_operand (irange &r, tree expr, edge e ATTRIBUTE_UNUSED)
+fur_list::get_phi_operand (vrange &r, tree expr, edge e ATTRIBUTE_UNUSED)
 {
   return get_operand (r, expr);
 }
@@ -278,7 +278,7 @@ fur_list::get_phi_operand (irange &r, tree expr, edge e ATTRIBUTE_UNUSED)
 // Fold stmt S into range R using R1 as the first operand.
 
 bool
-fold_range (irange &r, gimple *s, irange &r1)
+fold_range (vrange &r, gimple *s, vrange &r1)
 {
   fold_using_range f;
   fur_list src (r1);
@@ -288,7 +288,7 @@ fold_range (irange &r, gimple *s, irange &r1)
 // Fold stmt S into range R using R1  and R2 as the first two operands.
 
 bool
-fold_range (irange &r, gimple *s, irange &r1, irange &r2)
+fold_range (vrange &r, gimple *s, vrange &r1, vrange &r2)
 {
   fold_using_range f;
   fur_list src (r1, r2);
@@ -299,7 +299,7 @@ fold_range (irange &r, gimple *s, irange &r1, irange &r2)
 // operands encountered.
 
 bool
-fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector)
+fold_range (vrange &r, gimple *s, unsigned num_elements, vrange **vector)
 {
   fold_using_range f;
   fur_list src (num_elements, vector);
@@ -309,7 +309,7 @@ fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector)
 // Fold stmt S into range R using range query Q.
 
 bool
-fold_range (irange &r, gimple *s, range_query *q)
+fold_range (vrange &r, gimple *s, range_query *q)
 {
   fold_using_range f;
   fur_stmt src (s, q);
@@ -319,7 +319,7 @@ fold_range (irange &r, gimple *s, range_query *q)
 // Recalculate stmt S into R using range query Q as if it were on edge ON_EDGE.
 
 bool
-fold_range (irange &r, gimple *s, edge on_edge, range_query *q)
+fold_range (vrange &r, gimple *s, edge on_edge, range_query *q)
 {
   fold_using_range f;
   fur_edge src (on_edge, q);
@@ -370,7 +370,7 @@ adjust_pointer_diff_expr (irange &res, const gimple *diff_stmt)
 // Adjust the range for an IMAGPART_EXPR.
 
 static void
-adjust_imagpart_expr (irange &res, const gimple *stmt)
+adjust_imagpart_expr (vrange &res, const gimple *stmt)
 {
   tree name = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
 
@@ -413,7 +413,7 @@ adjust_imagpart_expr (irange &res, const gimple *stmt)
 // Adjust the range for a REALPART_EXPR.
 
 static void
-adjust_realpart_expr (irange &res, const gimple *stmt)
+adjust_realpart_expr (vrange &res, const gimple *stmt)
 {
   tree name = TREE_OPERAND (gimple_assign_rhs1 (stmt), 0);
 
@@ -442,12 +442,12 @@ adjust_realpart_expr (irange &res, const gimple *stmt)
 // this statement.
 
 static void
-gimple_range_adjustment (irange &res, const gimple *stmt)
+gimple_range_adjustment (vrange &res, const gimple *stmt)
 {
   switch (gimple_expr_code (stmt))
     {
     case POINTER_DIFF_EXPR:
-      adjust_pointer_diff_expr (res, stmt);
+      adjust_pointer_diff_expr (as_a <irange> (res), stmt);
       return;
 
     case IMAGPART_EXPR:
@@ -536,7 +536,7 @@ gimple_range_operand2 (const gimple *stmt)
 // be calculated, return false.
 
 bool
-fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name)
+fold_using_range::fold_stmt (vrange &r, gimple *s, fur_source &src, tree name)
 {
   bool res = false;
   // If name and S are specified, make sure it is an LHS of S.
@@ -549,7 +549,7 @@ fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name)
   // Process addresses.
   if (gimple_code (s) == GIMPLE_ASSIGN
       && gimple_assign_rhs_code (s) == ADDR_EXPR)
-    return range_of_address (r, s, src);
+    return range_of_address (as_a <irange> (r), s, src);
 
   if (range_op_handler (s))
     res = range_of_range_op (r, s, src);
@@ -566,7 +566,7 @@ fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name)
       if (!name || !gimple_range_ssa_p (name))
 	return false;
       // We don't understand the stmt, so return the global range.
-      r = gimple_range_global (name);
+      gimple_range_global (r, name);
       return true;
     }
 
@@ -587,9 +587,8 @@ fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name)
 // If a range cannot be calculated, return false.
 
 bool
-fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
+fold_using_range::range_of_range_op (vrange &r, gimple *s, fur_source &src)
 {
-  int_range_max range1, range2;
   tree type = gimple_range_type (s);
   if (!type)
     return false;
@@ -599,13 +598,16 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
   tree lhs = gimple_get_lhs (s);
   tree op1 = gimple_range_operand1 (s);
   tree op2 = gimple_range_operand2 (s);
+  Value_Range range1 (TREE_TYPE (op1));
+  Value_Range range2 (op2 ? TREE_TYPE (op2) : TREE_TYPE (op1));
 
   if (src.get_operand (range1, op1))
     {
       if (!op2)
 	{
 	  // Fold range, and register any dependency if available.
-	  int_range<2> r2 (type);
+	  Value_Range r2 (type);
+	  r2.set_varying (type);
 	  handler.fold_range (r, type, range1, r2);
 	  if (lhs && gimple_range_ssa_p (op1))
 	    {
@@ -630,7 +632,8 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
 	    }
 	  // Fold range, and register any dependency if available.
 	  handler.fold_range (r, type, range1, range2, rel);
-	  relation_fold_and_or (r, s, src);
+	  if (irange::supports_type_p (type))
+	    relation_fold_and_or (as_a <irange> (r), s, src);
 	  if (lhs)
 	    {
 	      if (src.gori ())
@@ -663,7 +666,8 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
 		e0 = NULL;
 	      if (!single_pred_p (e1->dest))
 		e1 = NULL;
-	      src.register_outgoing_edges (as_a<gcond *> (s), r, e0, e1);
+	      src.register_outgoing_edges (as_a<gcond *> (s),
+					   as_a <irange> (r), e0, e1);
 	    }
 	}
       else
@@ -729,12 +733,12 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src)
 	{
 	  /* For -fdelete-null-pointer-checks -fno-wrapv-pointer we don't
 	     allow going from non-NULL pointer to NULL.  */
-	  if (!range_includes_zero_p (&r))
+	  if (r.undefined_p () || !r.contains_p (build_zero_cst (r.type ())))
 	    {
 	      /* We could here instead adjust r by off >> LOG2_BITS_PER_UNIT
 		 using POINTER_PLUS_EXPR if off_cst and just fall back to
 		 this.  */
-	      r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
+	      r.set_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
 	      return true;
 	    }
 	}
@@ -746,22 +750,22 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src)
 	  && known_ne (off, 0)
 	  && (flag_delete_null_pointer_checks || known_gt (off, 0)))
 	{
-	  r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
+	  r.set_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
 	  return true;
 	}
-      r = int_range<2> (TREE_TYPE (gimple_assign_rhs1 (stmt)));
+      r.set_varying (TREE_TYPE (gimple_assign_rhs1 (stmt)));
       return true;
     }
 
   // Handle "= &a".
   if (tree_single_nonzero_warnv_p (expr, &strict_overflow_p))
     {
-      r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
+      r.set_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt)));
       return true;
     }
 
   // Otherwise return varying.
-  r = int_range<2> (TREE_TYPE (gimple_assign_rhs1 (stmt)));
+  r.set_varying (TREE_TYPE (gimple_assign_rhs1 (stmt)));
   return true;
 }
 
@@ -769,12 +773,12 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src)
 // If a range cannot be calculated, return false.
 
 bool
-fold_using_range::range_of_phi (irange &r, gphi *phi, fur_source &src)
+fold_using_range::range_of_phi (vrange &r, gphi *phi, fur_source &src)
 {
   tree phi_def = gimple_phi_result (phi);
   tree type = gimple_range_type (phi);
-  int_range_max arg_range;
-  int_range_max equiv_range;
+  Value_Range arg_range (type);
+  Value_Range equiv_range (type);
   unsigned x;
 
   if (!type)
@@ -881,7 +885,7 @@ fold_using_range::range_of_phi (irange &r, gphi *phi, fur_source &src)
 // If a range cannot be calculated, return false.
 
 bool
-fold_using_range::range_of_call (irange &r, gcall *call, fur_source &src)
+fold_using_range::range_of_call (vrange &r, gcall *call, fur_source &src)
 {
   tree type = gimple_range_type (call);
   if (!type)
@@ -893,18 +897,18 @@ fold_using_range::range_of_call (irange &r, gcall *call, fur_source &src)
   if (range_of_builtin_call (r, call, src))
     ;
   else if (gimple_stmt_nonnegative_warnv_p (call, &strict_overflow_p))
-    r.set (build_int_cst (type, 0), TYPE_MAX_VALUE (type));
+    r.set_nonnegative (type);
   else if (gimple_call_nonnull_result_p (call)
 	   || gimple_call_nonnull_arg (call))
-    r = range_nonzero (type);
+    r.set_nonzero (type);
   else
     r.set_varying (type);
 
   // If there is an LHS, intersect that with what is known.
   if (lhs)
     {
-      value_range def;
-      def = gimple_range_global (lhs);
+      Value_Range def (TREE_TYPE (lhs));
+      gimple_range_global (def, lhs);
       r.intersect (def);
     }
   return true;
@@ -971,13 +975,30 @@ get_letter_range (tree type, irange &lowers, irange &uppers)
 // TRUE.  Otherwise return FALSE.
 
 bool
-fold_using_range::range_of_builtin_call (irange &r, gcall *call,
+fold_using_range::range_of_builtin_call (vrange &r, gcall *call,
 					 fur_source &src)
 {
   combined_fn func = gimple_call_combined_fn (call);
   if (func == CFN_LAST)
     return false;
 
+  tree type = gimple_range_type (call);
+  gcc_checking_assert (type);
+
+  if (irange::supports_type_p (type))
+    return range_of_builtin_int_call (as_a <irange> (r), call, src);
+
+  return false;
+}
+
+bool
+fold_using_range::range_of_builtin_int_call (irange &r, gcall *call,
+					     fur_source &src)
+{
+  combined_fn func = gimple_call_combined_fn (call);
+  if (func == CFN_LAST)
+    return false;
+
   tree type = gimple_range_type (call);
   tree arg;
   int mini, maxi, zerov = 0, prec;
@@ -1256,9 +1277,8 @@ fold_using_range::range_of_builtin_call (irange &r, gcall *call,
 // If a range cannot be calculated, return false.
 
 bool
-fold_using_range::range_of_cond_expr  (irange &r, gassign *s, fur_source &src)
+fold_using_range::range_of_cond_expr  (vrange &r, gassign *s, fur_source &src)
 {
-  int_range_max cond_range, range1, range2;
   tree cond = gimple_assign_rhs1 (s);
   tree op1 = gimple_assign_rhs2 (s);
   tree op2 = gimple_assign_rhs3 (s);
@@ -1267,6 +1287,9 @@ fold_using_range::range_of_cond_expr  (irange &r, gassign *s, fur_source &src)
   if (!type)
     return false;
 
+  Value_Range range1 (TREE_TYPE (op1));
+  Value_Range range2 (TREE_TYPE (op2));
+  Value_Range cond_range (TREE_TYPE (cond));
   gcc_checking_assert (gimple_assign_rhs_code (s) == COND_EXPR);
   gcc_checking_assert (range_compatible_p (TREE_TYPE (op1), TREE_TYPE (op2)));
   src.get_operand (cond_range, cond);
@@ -1438,7 +1461,6 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
 void
 fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge e1)
 {
-  int_range_max r;
   int_range<2> e0_range, e1_range;
   tree name;
   basic_block bb = gimple_bb (s);
@@ -1505,6 +1527,7 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
 	continue;
       tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
       tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (stmt));
+      Value_Range r (TREE_TYPE (name));
       if (ssa1 && ssa2)
 	{
 	  if (e0 && gori ()->outgoing_edge_range_p (r, e0, name, *m_query)
diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h
index 4b5d4b6e0b8..df24280ee40 100644
--- a/gcc/gimple-range-fold.h
+++ b/gcc/gimple-range-fold.h
@@ -23,7 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 #define GCC_GIMPLE_RANGE_FOLD_H
 
 // This file is the main include point for gimple range folding.
-// These routines will fold stmt S into the result irange R.
+// These routines will fold stmt S into the result range R.
 // Any ssa_names on the stmt will be calculated using the range_query
 // parameter via a call to range_of_expr.
 // If no range_query is provided, current global range info will be used.
@@ -31,15 +31,15 @@ along with GCC; see the file COPYING3.  If not see
 // it appeared on that edge.
 
 // Fold stmt S into range R using range query Q.
-bool fold_range (irange &r, gimple *s, range_query *q = NULL);
+bool fold_range (vrange &r, gimple *s, range_query *q = NULL);
 // Recalculate stmt S into R using range query Q as if it were on edge ON_EDGE.
-bool fold_range (irange &r, gimple *s, edge on_edge, range_query *q = NULL);
+bool fold_range (vrange &v, gimple *s, edge on_edge, range_query *q = NULL);
 
 // These routines the operands to be specified when manually folding.
 // Any excess queries will be drawn from the current range_query.
-bool fold_range (irange &r, gimple *s, irange &r1);
-bool fold_range (irange &r, gimple *s, irange &r1, irange &r2);
-bool fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector);
+bool fold_range (vrange &r, gimple *s, vrange &r1);
+bool fold_range (vrange &r, gimple *s, vrange &r1, vrange &r2);
+bool fold_range (vrange &r, gimple *s, unsigned num_elements, vrange **vector);
 
 // Return the type of range which statement S calculates.  If the type is
 // unsupported or no type can be determined, return NULL_TREE.
@@ -66,7 +66,7 @@ gimple_range_type (const gimple *s)
 	    type = TREE_TYPE (type);
 	}
     }
-  if (type && irange::supports_type_p (type))
+  if (type && vrange::supports_type_p (type))
     return type;
   return NULL_TREE;
 }
@@ -79,7 +79,7 @@ gimple_range_ssa_p (tree exp)
   if (exp && TREE_CODE (exp) == SSA_NAME &&
       !SSA_NAME_IS_VIRTUAL_OPERAND (exp) &&
       !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (exp) &&
-      irange::supports_type_p (TREE_TYPE (exp)))
+      vrange::supports_type_p (TREE_TYPE (exp)))
     return exp;
   return NULL_TREE;
 }
@@ -108,8 +108,8 @@ public:
   fur_source (range_query *q = NULL);
   inline range_query *query () { return m_query; }
   inline class gori_compute *gori () { return m_gori; };
-  virtual bool get_operand (irange &r, tree expr);
-  virtual bool get_phi_operand (irange &r, tree expr, edge e);
+  virtual bool get_operand (vrange &r, tree expr);
+  virtual bool get_phi_operand (vrange &r, tree expr, edge e);
   virtual relation_kind query_relation (tree op1, tree op2);
   virtual void register_relation (gimple *stmt, relation_kind k, tree op1,
 				  tree op2);
@@ -128,8 +128,8 @@ class fur_stmt : public fur_source
 {
 public:
   fur_stmt (gimple *s, range_query *q = NULL);
-  virtual bool get_operand (irange &r, tree expr) override;
-  virtual bool get_phi_operand (irange &r, tree expr, edge e) override;
+  virtual bool get_operand (vrange &r, tree expr) override;
+  virtual bool get_phi_operand (vrange &r, tree expr, edge e) override;
   virtual relation_kind query_relation (tree op1, tree op2) override;
 private:
   gimple *m_stmt;
@@ -161,17 +161,18 @@ extern tree gimple_range_operand2 (const gimple *s);
 class fold_using_range
 {
 public:
-  bool fold_stmt (irange &r, gimple *s, class fur_source &src,
+  bool fold_stmt (vrange &r, gimple *s, class fur_source &src,
 		  tree name = NULL_TREE);
 protected:
-  bool range_of_range_op (irange &r, gimple *s, fur_source &src);
-  bool range_of_call (irange &r, gcall *call, fur_source &src);
-  bool range_of_cond_expr (irange &r, gassign* cond, fur_source &src);
+  bool range_of_range_op (vrange &r, gimple *s, fur_source &src);
+  bool range_of_call (vrange &r, gcall *call, fur_source &src);
+  bool range_of_cond_expr (vrange &r, gassign* cond, fur_source &src);
   bool range_of_address (irange &r, gimple *s, fur_source &src);
-  bool range_of_builtin_call (irange &r, gcall *call, fur_source &src);
+  bool range_of_builtin_call (vrange &r, gcall *call, fur_source &src);
+  bool range_of_builtin_int_call (irange &r, gcall *call, fur_source &src);
   void range_of_builtin_ubsan_call (irange &r, gcall *call, tree_code code,
 				    fur_source &src);
-  bool range_of_phi (irange &r, gphi *phi, fur_source &src);
+  bool range_of_phi (vrange &r, gphi *phi, fur_source &src);
   void range_of_ssa_name_with_loop_info (irange &, tree, class loop *, gphi *,
 					 fur_source &src);
   void relation_fold_and_or (irange& lhs_range, gimple *s, fur_source &src);
diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index 72032132cac..0a3e54eae4e 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -34,7 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 // LHS_RANGE.  Return false if nothing can be determined.
 
 bool
-gimple_range_calc_op1 (irange &r, const gimple *stmt, const irange &lhs_range)
+gimple_range_calc_op1 (vrange &r, const gimple *stmt, const vrange &lhs_range)
 {
   gcc_checking_assert (gimple_num_ops (stmt) < 3);
   // Give up on empty ranges.
@@ -55,8 +55,8 @@ gimple_range_calc_op1 (irange &r, const gimple *stmt, const irange &lhs_range)
 // nothing can be determined.
 
 bool
-gimple_range_calc_op1 (irange &r, const gimple *stmt,
-		       const irange &lhs_range, const irange &op2_range)
+gimple_range_calc_op1 (vrange &r, const gimple *stmt,
+		       const vrange &lhs_range, const vrange &op2_range)
 {
   // Give up on empty ranges.
   if (lhs_range.undefined_p ())
@@ -86,8 +86,8 @@ gimple_range_calc_op1 (irange &r, const gimple *stmt,
 // nothing can be determined.
 
 bool
-gimple_range_calc_op2 (irange &r, const gimple *stmt,
-		       const irange &lhs_range, const irange &op1_range)
+gimple_range_calc_op2 (vrange &r, const gimple *stmt,
+		       const vrange &lhs_range, const vrange &op1_range)
 {
   // Give up on empty ranges.
   if (lhs_range.undefined_p ())
@@ -663,8 +663,8 @@ gori_compute::gori_compute (int not_executable_flag)
 // was not resolvable.
 
 bool
-gori_compute::compute_operand_range_switch (irange &r, gswitch *s,
-					    const irange &lhs,
+gori_compute::compute_operand_range_switch (vrange &r, gswitch *s,
+					    const vrange &lhs,
 					    tree name, fur_source &src)
 {
   tree op1 = gimple_switch_index (s);
@@ -691,8 +691,8 @@ gori_compute::compute_operand_range_switch (irange &r, gswitch *s,
 // store the evaluation in R, otherwise return FALSE.
 
 bool
-gori_compute::compute_operand_range (irange &r, gimple *stmt,
-				     const irange &lhs, tree name,
+gori_compute::compute_operand_range (vrange &r, gimple *stmt,
+				     const vrange &lhs, tree name,
 				     fur_source &src)
 {
   // If the lhs doesn't tell us anything, neither will unwinding further.
@@ -743,13 +743,18 @@ gori_compute::compute_operand_range (irange &r, gimple *stmt,
 	  print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
 	}
 
-      int_range_max op1_trange, op1_frange;
-      int_range_max op2_trange, op2_frange;
-      compute_logical_operands (op1_trange, op1_frange, stmt, lhs,
+      tree type = TREE_TYPE (name);
+      Value_Range op1_trange (type), op1_frange (type);
+      Value_Range op2_trange (type), op2_frange (type);
+      compute_logical_operands (op1_trange, op1_frange, stmt,
+				as_a <irange> (lhs),
 				name, src, op1, op1_in_chain);
-      compute_logical_operands (op2_trange, op2_frange, stmt, lhs,
+      compute_logical_operands (op2_trange, op2_frange, stmt,
+				as_a <irange> (lhs),
 				name, src, op2, op2_in_chain);
-      res = logical_combine (r, gimple_expr_code (stmt), lhs,
+      res = logical_combine (r,
+			     gimple_expr_code (stmt),
+			     as_a <irange> (lhs),
 			     op1_trange, op1_frange, op2_trange, op2_frange);
       if (idx)
 	tracer.trailer (idx, "compute_operand", res, name, r);
@@ -789,10 +794,10 @@ range_is_either_true_or_false (const irange &r)
 // the LHS.
 
 bool
-gori_compute::logical_combine (irange &r, enum tree_code code,
+gori_compute::logical_combine (vrange &r, enum tree_code code,
 			       const irange &lhs,
-			       const irange &op1_true, const irange &op1_false,
-			       const irange &op2_true, const irange &op2_false)
+			       const vrange &op1_true, const vrange &op1_false,
+			       const vrange &op2_true, const vrange &op2_false)
 {
   if (op1_true.varying_p () && op1_false.varying_p ()
       && op2_true.varying_p () && op2_false.varying_p ())
@@ -868,7 +873,7 @@ gori_compute::logical_combine (irange &r, enum tree_code code,
   if (!range_is_either_true_or_false (lhs))
     {
       bool res;
-      int_range_max r1;
+      Value_Range r1 (r);
       if (logical_combine (r1, code, m_bool_zero, op1_true, op1_false,
 			   op2_true, op2_false)
 	  && logical_combine (r, code, m_bool_one, op1_true, op1_false,
@@ -898,11 +903,11 @@ gori_compute::logical_combine (irange &r, enum tree_code code,
 	else
 	  {
 	    // The FALSE side is the union of the other 3 cases.
-	    int_range_max ff (op1_false);
+	    Value_Range ff (op1_false);
 	    ff.intersect (op2_false);
-	    int_range_max tf (op1_true);
+	    Value_Range tf (op1_true);
 	    tf.intersect (op2_false);
-	    int_range_max ft (op1_false);
+	    Value_Range ft (op1_false);
 	    ft.intersect (op2_true);
 	    r = ff;
 	    r.union_ (tf);
@@ -925,11 +930,11 @@ gori_compute::logical_combine (irange &r, enum tree_code code,
 	  {
 	    // The TRUE side of an OR operation will be the union of
 	    // the other three combinations.
-	    int_range_max tt (op1_true);
+	    Value_Range tt (op1_true);
 	    tt.intersect (op2_true);
-	    int_range_max tf (op1_true);
+	    Value_Range tf (op1_true);
 	    tf.intersect (op2_false);
-	    int_range_max ft (op1_false);
+	    Value_Range ft (op1_false);
 	    ft.intersect (op2_true);
 	    r = tt;
 	    r.union_ (tf);
@@ -951,7 +956,7 @@ gori_compute::logical_combine (irange &r, enum tree_code code,
 // OP_IN_CHAIN is true.
 
 void
-gori_compute::compute_logical_operands (irange &true_range, irange &false_range,
+gori_compute::compute_logical_operands (vrange &true_range, vrange &false_range,
 					gimple *stmt,
 					const irange &lhs,
 					tree name, fur_source &src,
@@ -1007,13 +1012,15 @@ gori_compute::compute_logical_operands (irange &true_range, irange &false_range,
 // R, or false if no range could be calculated.
 
 bool
-gori_compute::compute_operand1_range (irange &r, gimple *stmt,
-				      const irange &lhs, tree name,
+gori_compute::compute_operand1_range (vrange &r, gimple *stmt,
+				      const vrange &lhs, tree name,
 				      fur_source &src)
 {
-  int_range_max op1_range, op2_range;
   tree op1 = gimple_range_operand1 (stmt);
   tree op2 = gimple_range_operand2 (stmt);
+  Value_Range op1_range (TREE_TYPE (op1));
+  Value_Range tmp (TREE_TYPE (op1));
+  Value_Range op2_range (op2 ? TREE_TYPE (op2) : TREE_TYPE (op1));
 
   // Fetch the known range for op1 in this block.
   src.get_operand (op1_range, op1);
@@ -1022,7 +1029,7 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt,
   if (op2)
     {
       src.get_operand (op2_range, op2);
-      if (!gimple_range_calc_op1 (r, stmt, lhs, op2_range))
+      if (!gimple_range_calc_op1 (tmp, stmt, lhs, op2_range))
 	return false;
     }
   else
@@ -1030,7 +1037,7 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt,
       // We pass op1_range to the unary operation.  Nomally it's a
       // hidden range_for_type parameter, but sometimes having the
       // actual range can result in better information.
-      if (!gimple_range_calc_op1 (r, stmt, lhs, op1_range))
+      if (!gimple_range_calc_op1 (tmp, stmt, lhs, op1_range))
 	return false;
     }
 
@@ -1053,7 +1060,7 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt,
       tracer.print (idx, "Computes ");
       print_generic_expr (dump_file, op1, TDF_SLIM);
       fprintf (dump_file, " = ");
-      r.dump (dump_file);
+      tmp.dump (dump_file);
       fprintf (dump_file, " intersect Known range : ");
       op1_range.dump (dump_file);
       fputc ('\n', dump_file);
@@ -1061,13 +1068,14 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt,
   // Intersect the calculated result with the known result and return if done.
   if (op1 == name)
     {
-      r.intersect (op1_range);
+      tmp.intersect (op1_range);
+      r = tmp;
       if (idx)
 	tracer.trailer (idx, "produces ", true, name, r);
       return true;
     }
   // If the calculation continues, we're using op1_range as the new LHS.
-  op1_range.intersect (r);
+  op1_range.intersect (tmp);
 
   if (idx)
     tracer.trailer (idx, "produces ", true, op1, op1_range);
@@ -1084,19 +1092,21 @@ gori_compute::compute_operand1_range (irange &r, gimple *stmt,
 // R, or false if no range could be calculated.
 
 bool
-gori_compute::compute_operand2_range (irange &r, gimple *stmt,
-				      const irange &lhs, tree name,
+gori_compute::compute_operand2_range (vrange &r, gimple *stmt,
+				      const vrange &lhs, tree name,
 				      fur_source &src)
 {
-  int_range_max op1_range, op2_range;
   tree op1 = gimple_range_operand1 (stmt);
   tree op2 = gimple_range_operand2 (stmt);
+  Value_Range op1_range (TREE_TYPE (op1));
+  Value_Range op2_range (TREE_TYPE (op2));
+  Value_Range tmp (TREE_TYPE (op2));
 
   src.get_operand (op1_range, op1);
   src.get_operand (op2_range, op2);
 
   // Intersect with range for op2 based on lhs and op1.
-  if (!gimple_range_calc_op2 (r, stmt, lhs, op1_range))
+  if (!gimple_range_calc_op2 (tmp, stmt, lhs, op1_range))
     return false;
 
   unsigned idx;
@@ -1118,7 +1128,7 @@ gori_compute::compute_operand2_range (irange &r, gimple *stmt,
       tracer.print (idx, "Computes ");
       print_generic_expr (dump_file, op2, TDF_SLIM);
       fprintf (dump_file, " = ");
-      r.dump (dump_file);
+      tmp.dump (dump_file);
       fprintf (dump_file, " intersect Known range : ");
       op2_range.dump (dump_file);
       fputc ('\n', dump_file);
@@ -1126,13 +1136,14 @@ gori_compute::compute_operand2_range (irange &r, gimple *stmt,
   // Intersect the calculated result with the known result and return if done.
   if (op2 == name)
     {
-      r.intersect (op2_range);
+      tmp.intersect (op2_range);
+      r = tmp;
       if (idx)
 	tracer.trailer (idx, " produces ", true, NULL_TREE, r);
       return true;
     }
   // If the calculation continues, we're using op2_range as the new LHS.
-  op2_range.intersect (r);
+  op2_range.intersect (tmp);
 
   if (idx)
     tracer.trailer (idx, " produces ", true, op2, op2_range);
@@ -1149,13 +1160,13 @@ gori_compute::compute_operand2_range (irange &r, gimple *stmt,
 // R, or false if no range could be calculated.
 
 bool
-gori_compute::compute_operand1_and_operand2_range (irange &r,
+gori_compute::compute_operand1_and_operand2_range (vrange &r,
 						   gimple *stmt,
-						   const irange &lhs,
+						   const vrange &lhs,
 						   tree name,
 						   fur_source &src)
 {
-  int_range_max op_range;
+  Value_Range op_range (TREE_TYPE (name));
 
   // Calculate a good a range for op2.  Since op1 == op2, this will
   // have already included whatever the actual range of name is.
@@ -1236,10 +1247,9 @@ gori_compute::has_edge_range_p (tree name, edge e)
 // control edge or NAME is not defined by this edge.
 
 bool
-gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name,
+gori_compute::outgoing_edge_range_p (vrange &r, edge e, tree name,
 				     range_query &q)
 {
-  int_range_max lhs;
   unsigned idx;
 
   if ((e->flags & m_not_executable_flag))
@@ -1252,6 +1262,7 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name,
     }
 
   gcc_checking_assert (gimple_range_ssa_p (name));
+  int_range_max lhs;
   // Determine if there is an outgoing edge.
   gimple *stmt = outgoing.edge_range_p (lhs, e);
   if (!stmt)
@@ -1312,10 +1323,9 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name,
 // edge and OP2 on the false edge.
 
 bool
-gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond,
+gori_compute::condexpr_adjust (vrange &r1, vrange &r2, gimple *, tree cond,
 			       tree op1, tree op2, fur_source &src)
 {
-  int_range_max tmp, cond_true, cond_false;
   tree ssa1 = gimple_range_ssa_p (op1);
   tree ssa2 = gimple_range_ssa_p (op2);
   if (!ssa1 && !ssa2)
@@ -1341,15 +1351,19 @@ gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond,
     return false;
 
   // Pick up the current values of each part of the condition.
-  int_range_max cl, cr;
-  src.get_operand (cl, gimple_assign_rhs1 (cond_def));
-  src.get_operand (cr, gimple_assign_rhs2 (cond_def));
+  tree rhs1 = gimple_assign_rhs1 (cond_def);
+  tree rhs2 = gimple_assign_rhs2 (cond_def);
+  Value_Range cl (TREE_TYPE (rhs1));
+  Value_Range cr (TREE_TYPE (rhs2));
+  src.get_operand (cl, rhs1);
+  src.get_operand (cr, rhs2);
 
   tree cond_name = c1 ? c1 : c2;
   gimple *def_stmt = SSA_NAME_DEF_STMT (cond_name);
 
   // Evaluate the value of COND_NAME on the true and false edges, using either
   // the op1 or op2 routines based on its location.
+  Value_Range cond_true (type), cond_false (type);
   if (c1)
     {
       if (!hand.op1_range (cond_false, type, m_bool_zero, cr))
@@ -1380,6 +1394,7 @@ gori_compute::condexpr_adjust (irange &r1, irange &r2, gimple *, tree cond,
     }
 
    // Now solve for SSA1 or SSA2 if they are in the dependency chain.
+  Value_Range tmp (type);
    if (ssa1 && in_chain_p (ssa1, cond_name))
     {
       if (compute_operand_range (tmp, def_stmt, cond_true, ssa1, src))
diff --git a/gcc/gimple-range-gori.h b/gcc/gimple-range-gori.h
index 605884e2e53..f5f691fe424 100644
--- a/gcc/gimple-range-gori.h
+++ b/gcc/gimple-range-gori.h
@@ -121,7 +121,7 @@ private:
 //   on *ANY* edge that has been seen.  FALSE indicates that the global value
 //   is applicable everywhere that has been processed.
 //
-// outgoing_edge_range_p (irange &range, edge e, tree name)
+// outgoing_edge_range_p (vrange &range, edge e, tree name)
 //   Actually does the calculation of RANGE for name on E
 //   This represents application of whatever static range effect edge E
 //   may have on NAME, not any cumulative effect.
@@ -157,8 +157,8 @@ class gori_compute : public gori_map
 {
 public:
   gori_compute (int not_executable_flag = 0);
-  bool outgoing_edge_range_p (irange &r, edge e, tree name, range_query &q);
-  bool condexpr_adjust (irange &r1, irange &r2, gimple *s, tree cond, tree op1,
+  bool outgoing_edge_range_p (vrange &r, edge e, tree name, range_query &q);
+  bool condexpr_adjust (vrange &r1, vrange &r2, gimple *s, tree cond, tree op1,
 			tree op2, fur_source &src);
   bool has_edge_range_p (tree name, basic_block bb = NULL);
   bool has_edge_range_p (tree name, edge e);
@@ -166,24 +166,24 @@ public:
 private:
   bool may_recompute_p (tree name, edge e);
   bool may_recompute_p (tree name, basic_block bb = NULL);
-  bool compute_operand_range (irange &r, gimple *stmt, const irange &lhs,
+  bool compute_operand_range (vrange &r, gimple *stmt, const vrange &lhs,
 			      tree name, class fur_source &src);
-  bool compute_operand_range_switch (irange &r, gswitch *s, const irange &lhs,
+  bool compute_operand_range_switch (vrange &r, gswitch *s, const vrange &lhs,
 				     tree name, fur_source &src);
-  bool compute_operand1_range (irange &r, gimple *stmt, const irange &lhs,
+  bool compute_operand1_range (vrange &r, gimple *stmt, const vrange &lhs,
 			       tree name, fur_source &src);
-  bool compute_operand2_range (irange &r, gimple *stmt, const irange &lhs,
+  bool compute_operand2_range (vrange &r, gimple *stmt, const vrange &lhs,
 			       tree name, fur_source &src);
-  bool compute_operand1_and_operand2_range (irange &r, gimple *stmt,
-					    const irange &lhs, tree name,
+  bool compute_operand1_and_operand2_range (vrange &r, gimple *stmt,
+					    const vrange &lhs, tree name,
 					    fur_source &src);
-  void compute_logical_operands (irange &true_range, irange &false_range,
+  void compute_logical_operands (vrange &true_range, vrange &false_range,
 				 gimple *stmt, const irange &lhs,
 				 tree name, fur_source &src, tree op,
 				 bool op_in_chain);
-  bool logical_combine (irange &r, enum tree_code code, const irange &lhs,
-			const irange &op1_true, const irange &op1_false,
-			const irange &op2_true, const irange &op2_false);
+  bool logical_combine (vrange &r, enum tree_code code, const irange &lhs,
+			const vrange &op1_true, const vrange &op1_false,
+			const vrange &op2_true, const vrange &op2_false);
   int_range<2> m_bool_zero;	// Boolean false cached.
   int_range<2> m_bool_one;	// Boolean true cached.
 
@@ -193,14 +193,14 @@ private:
 };
 
 // These routines provide a GIMPLE interface to the range-ops code.
-extern bool gimple_range_calc_op1 (irange &r, const gimple *s,
-				   const irange &lhs_range);
-extern bool gimple_range_calc_op1 (irange &r, const gimple *s,
-				   const irange &lhs_range,
-				   const irange &op2_range);
-extern bool gimple_range_calc_op2 (irange &r, const gimple *s,
-				   const irange &lhs_range,
-				   const irange &op1_range);
+extern bool gimple_range_calc_op1 (vrange &r, const gimple *s,
+				   const vrange &lhs_range);
+extern bool gimple_range_calc_op1 (vrange &r, const gimple *s,
+				   const vrange &lhs_range,
+				   const vrange &op2_range);
+extern bool gimple_range_calc_op2 (vrange &r, const gimple *s,
+				   const vrange &lhs_range,
+				   const vrange &op1_range);
 
 // For each name that is an import into BB's exports..
 #define FOR_EACH_GORI_IMPORT_NAME(gori, bb, name)			\
diff --git a/gcc/gimple-range-infer.cc b/gcc/gimple-range-infer.cc
index 14ddfb803d8..eee149104b4 100644
--- a/gcc/gimple-range-infer.cc
+++ b/gcc/gimple-range-infer.cc
@@ -58,7 +58,7 @@ non_null_loadstore (gimple *, tree op, tree, void *data)
 // Add NAME and RANGE to the the range inference summary.
 
 void
-gimple_infer_range::add_range (tree name, irange &range)
+gimple_infer_range::add_range (tree name, vrange &range)
 {
   m_names[num_args] = name;
   m_ranges[num_args] = range;
@@ -126,7 +126,7 @@ class exit_range
 {
 public:
   tree name;
-  irange *range;
+  vrange *range;
   exit_range *next;
 };
 
@@ -181,7 +181,7 @@ infer_range_manager::~infer_range_manager ()
 // Return a non-zero range value of the appropriate type for NAME from
 // the cache, creating it if necessary.
 
-const irange&
+const vrange&
 infer_range_manager::get_nonzero (tree name)
 {
   unsigned v = SSA_NAME_VERSION (name);
@@ -189,10 +189,8 @@ infer_range_manager::get_nonzero (tree name)
     m_nonzero.safe_grow_cleared (num_ssa_names + 20);
   if (!m_nonzero[v])
     {
-      tree type = TREE_TYPE (name);
-      m_nonzero[v]
-	= static_cast <irange *> (m_range_allocator.alloc_vrange (type));
-      m_nonzero[v]->set_nonzero (type);
+      m_nonzero[v] = m_range_allocator.alloc_vrange (TREE_TYPE (name));
+      m_nonzero[v]->set_nonzero (TREE_TYPE (name));
     }
   return *(m_nonzero[v]);
 }
@@ -219,7 +217,7 @@ infer_range_manager::has_range_p (tree name, basic_block bb)
 // to include it.
 
 bool
-infer_range_manager::maybe_adjust_range (irange &r, tree name, basic_block bb)
+infer_range_manager::maybe_adjust_range (vrange &r, tree name, basic_block bb)
 {
   if (!has_range_p (name, bb))
     return false;
@@ -232,7 +230,7 @@ infer_range_manager::maybe_adjust_range (irange &r, tree name, basic_block bb)
 // Add range R as an inferred range for NAME in block BB.
 
 void
-infer_range_manager::add_range (tree name, basic_block bb, const irange &r)
+infer_range_manager::add_range (tree name, basic_block bb, const vrange &r)
 {
   if (bb->index >= (int)m_on_exit.length ())
     m_on_exit.safe_grow_cleared (last_basic_block_for_fn (cfun) + 1);
@@ -254,7 +252,7 @@ infer_range_manager::add_range (tree name, basic_block bb, const irange &r)
   exit_range *ptr = m_on_exit[bb->index].find_ptr (name);
   if (ptr)
     {
-      int_range_max cur = r;
+      Value_Range cur (r);
       // If no new info is added, just return.
       if (!cur.intersect (*(ptr->range)))
 	return;
@@ -263,7 +261,7 @@ infer_range_manager::add_range (tree name, basic_block bb, const irange &r)
       else
 	{
 	  vrange &v = cur;
-	  ptr->range = static_cast <irange *> (m_range_allocator.clone (v));
+	  ptr->range = m_range_allocator.clone (v);
 	}
       return;
     }
diff --git a/gcc/gimple-range-infer.h b/gcc/gimple-range-infer.h
index 65f6e83809d..aafa8bb74f0 100644
--- a/gcc/gimple-range-infer.h
+++ b/gcc/gimple-range-infer.h
@@ -35,15 +35,15 @@ public:
   inline unsigned num () const { return num_args; }
   inline tree name (unsigned index) const
     { gcc_checking_assert (index < num_args); return m_names[index]; }
-  inline const irange& range (unsigned index) const
+  inline const vrange& range (unsigned index) const
     { gcc_checking_assert (index < num_args); return m_ranges[index]; }
-  void add_range (tree name, irange &range);
+  void add_range (tree name, vrange &range);
   void add_nonzero (tree name);
 private:
   unsigned num_args;
   static const int size_limit = 10;
   tree m_names[size_limit];
-  int_range<3> m_ranges[size_limit];
+  Value_Range m_ranges[size_limit];
   inline void bump_index () { if (num_args < size_limit - 1) num_args++; }
 };
 
@@ -58,10 +58,10 @@ class infer_range_manager
 public:
   infer_range_manager (bool do_search);
   ~infer_range_manager ();
-  void add_range (tree name, basic_block bb, const irange &r);
+  void add_range (tree name, basic_block bb, const vrange &r);
   void add_nonzero (tree name, basic_block bb);
   bool has_range_p (tree name, basic_block bb);
-  bool maybe_adjust_range (irange &r, tree name, basic_block bb);
+  bool maybe_adjust_range (vrange &r, tree name, basic_block bb);
 private:
   class exit_range_head
   {
@@ -73,8 +73,8 @@ private:
   };
   void register_all_uses (tree name);
   vec <exit_range_head> m_on_exit;
-  const irange &get_nonzero (tree name);
-  vec <irange *> m_nonzero;
+  const vrange &get_nonzero (tree name);
+  vec <vrange *> m_nonzero;
   bitmap m_seen;
   bitmap_obstack m_bitmaps;
   struct obstack m_list_obstack;
diff --git a/gcc/gimple-range-path.cc b/gcc/gimple-range-path.cc
index 66f433dd1d5..f8ae6fb9ffb 100644
--- a/gcc/gimple-range-path.cc
+++ b/gcc/gimple-range-path.cc
@@ -83,7 +83,7 @@ path_range_query::clear_cache (tree name)
 // If NAME has a cache entry, return it in R, and return TRUE.
 
 inline bool
-path_range_query::get_cache (irange &r, tree name)
+path_range_query::get_cache (vrange &r, tree name)
 {
   if (!gimple_range_ssa_p (name))
     return get_global_range_query ()->range_of_expr (r, name);
@@ -98,7 +98,7 @@ path_range_query::get_cache (irange &r, tree name)
 // Set the cache entry for NAME to R.
 
 void
-path_range_query::set_cache (const irange &r, tree name)
+path_range_query::set_cache (const vrange &r, tree name)
 {
   unsigned v = SSA_NAME_VERSION (name);
   bitmap_set_bit (m_has_cache_entry, v);
@@ -149,7 +149,7 @@ path_range_query::defined_outside_path (tree name)
 // Return the range of NAME on entry to the path.
 
 void
-path_range_query::range_on_path_entry (irange &r, tree name)
+path_range_query::range_on_path_entry (vrange &r, tree name)
 {
   gcc_checking_assert (defined_outside_path (name));
   basic_block entry = entry_bb ();
@@ -168,7 +168,7 @@ path_range_query::range_on_path_entry (irange &r, tree name)
   // block.  This can happen when we're querying a block with only an
   // outgoing edge (no statement but the fall through edge), but for
   // which we can determine a range on entry to the block.
-  int_range_max tmp;
+  Value_Range tmp (TREE_TYPE (name));
   bool changed = false;
   r.set_undefined ();
   for (unsigned i = 0; i < EDGE_COUNT (entry->preds); ++i)
@@ -190,9 +190,9 @@ path_range_query::range_on_path_entry (irange &r, tree name)
 // Return the range of NAME at the end of the path being analyzed.
 
 bool
-path_range_query::internal_range_of_expr (irange &r, tree name, gimple *stmt)
+path_range_query::internal_range_of_expr (vrange &r, tree name, gimple *stmt)
 {
-  if (!irange::supports_type_p (TREE_TYPE (name)))
+  if (!vrange::supports_type_p (TREE_TYPE (name)))
     return false;
 
   if (get_cache (r, name))
@@ -209,18 +209,22 @@ path_range_query::internal_range_of_expr (irange &r, tree name, gimple *stmt)
       && range_defined_in_block (r, name, gimple_bb (stmt)))
     {
       if (TREE_CODE (name) == SSA_NAME)
-	r.intersect (gimple_range_global (name));
+	{
+	  Value_Range glob (TREE_TYPE (name));
+	  gimple_range_global (glob, name);
+	  r.intersect (glob);
+	}
 
       set_cache (r, name);
       return true;
     }
 
-  r = gimple_range_global (name);
+  gimple_range_global (r, name);
   return true;
 }
 
 bool
-path_range_query::range_of_expr (irange &r, tree name, gimple *stmt)
+path_range_query::range_of_expr (vrange &r, tree name, gimple *stmt)
 {
   if (internal_range_of_expr (r, name, stmt))
     {
@@ -269,7 +273,7 @@ path_range_query::ssa_defined_in_bb (tree name, basic_block bb)
 // calculating the PHI's range must not trigger additional lookups.
 
 void
-path_range_query::ssa_range_in_phi (irange &r, gphi *phi)
+path_range_query::ssa_range_in_phi (vrange &r, gphi *phi)
 {
   tree name = gimple_phi_result (phi);
   basic_block bb = gimple_bb (phi);
@@ -283,7 +287,7 @@ path_range_query::ssa_range_in_phi (irange &r, gphi *phi)
       // Try to fold the phi exclusively with global or cached values.
       // This will get things like PHI <5(99), 6(88)>.  We do this by
       // calling range_of_expr with no context.
-      int_range_max arg_range;
+      Value_Range arg_range (TREE_TYPE (name));
       r.set_undefined ();
       for (size_t i = 0; i < nargs; ++i)
 	{
@@ -312,7 +316,7 @@ path_range_query::ssa_range_in_phi (irange &r, gphi *phi)
 	  {
 	    if (m_resolve)
 	      {
-		int_range_max tmp;
+		Value_Range tmp (TREE_TYPE (name));
 		// Using both the range on entry to the path, and the
 		// range on this edge yields significantly better
 		// results.
@@ -335,7 +339,7 @@ path_range_query::ssa_range_in_phi (irange &r, gphi *phi)
 // TRUE.  Otherwise, return FALSE.
 
 bool
-path_range_query::range_defined_in_block (irange &r, tree name, basic_block bb)
+path_range_query::range_defined_in_block (vrange &r, tree name, basic_block bb)
 {
   gimple *def_stmt = SSA_NAME_DEF_STMT (name);
   basic_block def_bb = gimple_bb (def_stmt);
@@ -377,7 +381,6 @@ path_range_query::range_defined_in_block (irange &r, tree name, basic_block bb)
 void
 path_range_query::compute_ranges_in_phis (basic_block bb)
 {
-  int_range_max r;
   auto_bitmap phi_set;
 
   // PHIs must be resolved simultaneously on entry to the block
@@ -390,7 +393,11 @@ path_range_query::compute_ranges_in_phis (basic_block bb)
       gphi *phi = iter.phi ();
       tree name = gimple_phi_result (phi);
 
-      if (import_p (name) && range_defined_in_block (r, name, bb))
+      if (!import_p (name))
+	continue;
+
+      Value_Range r (TREE_TYPE (name));
+      if (range_defined_in_block (r, name, bb))
 	{
 	  unsigned v = SSA_NAME_VERSION (name);
 	  set_cache (r, name);
@@ -423,7 +430,6 @@ void
 path_range_query::compute_ranges_in_block (basic_block bb)
 {
   bitmap_iterator bi;
-  int_range_max r, cached_range;
   unsigned i;
 
   if (m_resolve && !at_entry ())
@@ -444,6 +450,7 @@ path_range_query::compute_ranges_in_block (basic_block bb)
   EXECUTE_IF_SET_IN_BITMAP (m_imports, 0, i, bi)
     {
       tree name = ssa_name (i);
+      Value_Range r (TREE_TYPE (name));
 
       if (gimple_code (SSA_NAME_DEF_STMT (name)) != GIMPLE_PHI
 	  && range_defined_in_block (r, name, bb))
@@ -480,8 +487,10 @@ path_range_query::compute_ranges_in_block (basic_block bb)
 
       if (bitmap_bit_p (exports, i))
 	{
+	  Value_Range r (TREE_TYPE (name));
 	  if (g.outgoing_edge_range_p (r, e, name, *this))
 	    {
+	      Value_Range cached_range (TREE_TYPE (name));
 	      if (get_cache (cached_range, name))
 		r.intersect (cached_range);
 
@@ -539,7 +548,7 @@ bool
 path_range_query::add_to_imports (tree name, bitmap imports)
 {
   if (TREE_CODE (name) == SSA_NAME
-      && irange::supports_type_p (TREE_TYPE (name)))
+      && vrange::supports_type_p (TREE_TYPE (name)))
     return bitmap_set_bit (imports, SSA_NAME_VERSION (name));
   return false;
 }
@@ -751,11 +760,11 @@ jt_fur_source::query_relation (tree op1, tree op2)
 // Return the range of STMT at the end of the path being analyzed.
 
 bool
-path_range_query::range_of_stmt (irange &r, gimple *stmt, tree)
+path_range_query::range_of_stmt (vrange &r, gimple *stmt, tree)
 {
   tree type = gimple_range_type (stmt);
 
-  if (!type || !irange::supports_type_p (type))
+  if (!type || !vrange::supports_type_p (type))
     return false;
 
   // If resolving unknowns, fold the statement making use of any
diff --git a/gcc/gimple-range-path.h b/gcc/gimple-range-path.h
index 914983bb0aa..2c4624e4cef 100644
--- a/gcc/gimple-range-path.h
+++ b/gcc/gimple-range-path.h
@@ -38,29 +38,29 @@ public:
 		       const bitmap_head *imports = NULL);
   void compute_ranges (edge e);
   void compute_imports (bitmap imports, basic_block exit);
-  bool range_of_expr (irange &r, tree name, gimple * = NULL) override;
-  bool range_of_stmt (irange &r, gimple *, tree name = NULL) override;
+  bool range_of_expr (vrange &r, tree name, gimple * = NULL) override;
+  bool range_of_stmt (vrange &r, gimple *, tree name = NULL) override;
   bool unreachable_path_p ();
   void dump (FILE *) override;
   void debug ();
 
 private:
-  bool internal_range_of_expr (irange &r, tree name, gimple *);
+  bool internal_range_of_expr (vrange &r, tree name, gimple *);
   bool defined_outside_path (tree name);
-  void range_on_path_entry (irange &r, tree name);
+  void range_on_path_entry (vrange &r, tree name);
   path_oracle *get_path_oracle () { return (path_oracle *)m_oracle; }
 
   // Cache manipulation.
-  void set_cache (const irange &r, tree name);
-  bool get_cache (irange &r, tree name);
+  void set_cache (const vrange &r, tree name);
+  bool get_cache (vrange &r, tree name);
   void clear_cache (tree name);
 
   // Methods to compute ranges for the given path.
-  bool range_defined_in_block (irange &, tree name, basic_block bb);
+  bool range_defined_in_block (vrange &, tree name, basic_block bb);
   void compute_ranges_in_block (basic_block bb);
   void compute_ranges_in_phis (basic_block bb);
   void adjust_for_non_null_uses (basic_block bb);
-  void ssa_range_in_phi (irange &r, gphi *phi);
+  void ssa_range_in_phi (vrange &r, gphi *phi);
   void compute_outgoing_relations (basic_block bb, basic_block next);
   void compute_phi_relations (basic_block bb, basic_block prev);
   void maybe_register_phi_relation (gphi *, edge e);
diff --git a/gcc/gimple-range-tests.cc b/gcc/gimple-range-tests.cc
index 572acd33d7f..84ecc486889 100644
--- a/gcc/gimple-range-tests.cc
+++ b/gcc/gimple-range-tests.cc
@@ -42,8 +42,9 @@ public:
     ASSERT_TRUE (r == expect);
   }
 
-  virtual bool range_of_expr (irange &r, tree expr, gimple * = NULL) override
+  virtual bool range_of_expr (vrange &v, tree expr, gimple * = NULL) override
   {
+    irange &r = as_a <irange> (v);
     if (expr == op0)
       {
 	r.set (build_int_cst (type, 5), build_int_cst (type, 10));
diff --git a/gcc/gimple-range-trace.cc b/gcc/gimple-range-trace.cc
index 39971093e6d..46827f9c580 100644
--- a/gcc/gimple-range-trace.cc
+++ b/gcc/gimple-range-trace.cc
@@ -102,7 +102,7 @@ range_tracer::print (unsigned counter, const char *str)
 
 void
 range_tracer::trailer (unsigned counter, const char *caller, bool result,
-		      tree name, const irange &r)
+		      tree name, const vrange &r)
 {
   gcc_checking_assert (tracing && counter != 0);
 
@@ -141,7 +141,6 @@ debug_seed_ranger (gimple_ranger &ranger)
     }
 
   basic_block bb;
-  int_range_max r;
   gimple_stmt_iterator gsi;
   FOR_EACH_BB_FN (bb, cfun)
     for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
@@ -151,7 +150,11 @@ debug_seed_ranger (gimple_ranger &ranger)
 	if (is_gimple_debug (stmt))
 	  continue;
 
-	ranger.range_of_stmt (r, stmt);
+	if (tree type = gimple_range_type (stmt))
+	  {
+	    Value_Range r (type);
+	    ranger.range_of_stmt (r, stmt);
+	  }
       }
 }
 
diff --git a/gcc/gimple-range-trace.h b/gcc/gimple-range-trace.h
index 302afda3104..3f92e51803b 100644
--- a/gcc/gimple-range-trace.h
+++ b/gcc/gimple-range-trace.h
@@ -32,7 +32,7 @@ public:
   range_tracer (const char *name = "");
   unsigned header (const char *str);
   void trailer (unsigned counter, const char *caller, bool result, tree name,
-		const irange &r);
+		const vrange &r);
   void print (unsigned counter, const char *str);
   inline void enable_trace () { tracing = true; }
   inline void disable_trace () { tracing = false; }
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 0a99787fc75..12da16841c2 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -71,7 +71,7 @@ gimple_ranger::~gimple_ranger ()
 }
 
 bool
-gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt)
+gimple_ranger::range_of_expr (vrange &r, tree expr, gimple *stmt)
 {
   unsigned idx;
   if (!gimple_range_ssa_p (expr))
@@ -93,7 +93,7 @@ gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt)
   // If there is no statement, just get the global value.
   if (!stmt)
     {
-      int_range_max tmp;
+      Value_Range tmp (TREE_TYPE (expr));
       m_cache.get_global_range (r, expr);
       // Pick up implied context information from the on-entry cache
       // if current_bb is set.  Do not attempt any new calculations.
@@ -137,9 +137,9 @@ gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt)
 // Return the range of NAME on entry to block BB in R.
 
 void
-gimple_ranger::range_on_entry (irange &r, basic_block bb, tree name)
+gimple_ranger::range_on_entry (vrange &r, basic_block bb, tree name)
 {
-  int_range_max entry_range;
+  Value_Range entry_range (TREE_TYPE (name));
   gcc_checking_assert (gimple_range_ssa_p (name));
 
   unsigned idx;
@@ -164,7 +164,7 @@ gimple_ranger::range_on_entry (irange &r, basic_block bb, tree name)
 // Return false if no range can be calculated.
 
 void
-gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name)
+gimple_ranger::range_on_exit (vrange &r, basic_block bb, tree name)
 {
   // on-exit from the exit block?
   gcc_checking_assert (bb != EXIT_BLOCK_PTR_FOR_FN (cfun));
@@ -198,10 +198,10 @@ gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name)
 // Calculate a range for NAME on edge E and return it in R.
 
 bool
-gimple_ranger::range_on_edge (irange &r, edge e, tree name)
+gimple_ranger::range_on_edge (vrange &r, edge e, tree name)
 {
-  int_range_max edge_range;
-  gcc_checking_assert (irange::supports_type_p (TREE_TYPE (name)));
+  Value_Range edge_range (TREE_TYPE (name));
+  gcc_checking_assert (vrange::supports_type_p (TREE_TYPE (name)));
 
   // Do not process values along abnormal edges.
   if (e->flags & EDGE_ABNORMAL)
@@ -249,7 +249,7 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name)
 // fold_range wrapper for range_of_stmt to use as an internal client.
 
 bool
-gimple_ranger::fold_range_internal (irange &r, gimple *s, tree name)
+gimple_ranger::fold_range_internal (vrange &r, gimple *s, tree name)
 {
   fold_using_range f;
   fur_depend src (s, &(gori ()), this);
@@ -263,7 +263,7 @@ gimple_ranger::fold_range_internal (irange &r, gimple *s, tree name)
 // avoided.  If a range cannot be calculated, return false and UNDEFINED.
 
 bool
-gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name)
+gimple_ranger::range_of_stmt (vrange &r, gimple *s, tree name)
 {
   bool res;
   r.set_undefined ();
@@ -313,7 +313,7 @@ gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name)
 	prefill_stmt_dependencies (name);
 
       // Calculate a new value.
-      int_range_max tmp;
+      Value_Range tmp (TREE_TYPE (name));
       fold_range_internal (tmp, s, name);
 
       // Combine the new value with the old value.  This is required because
@@ -334,7 +334,7 @@ gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name)
 // stack if so.  R is a scratch range.
 
 inline void
-gimple_ranger::prefill_name (irange &r, tree name)
+gimple_ranger::prefill_name (vrange &r, tree name)
 {
   if (!gimple_range_ssa_p (name))
     return;
@@ -357,7 +357,6 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
   if (SSA_NAME_IS_DEFAULT_DEF (ssa))
     return;
 
-  int_range_max r;
   unsigned idx;
   gimple *stmt = SSA_NAME_DEF_STMT (ssa);
   gcc_checking_assert (stmt && gimple_bb (stmt));
@@ -388,9 +387,10 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
 	    {
 	      // Fold and save the value for NAME.
 	      stmt = SSA_NAME_DEF_STMT (name);
+	      Value_Range r (TREE_TYPE (name));
 	      fold_range_internal (r, stmt, name);
 	      // Make sure we don't lose any current global info.
-	      int_range_max tmp;
+	      Value_Range tmp (TREE_TYPE (name));
 	      m_cache.get_global_range (tmp, name);
 	      r.intersect (tmp);
 	      m_cache.set_global_range (name, r);
@@ -414,6 +414,7 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
       gphi *phi = dyn_cast <gphi *> (stmt);
       if (phi)
 	{
+	  Value_Range r (TREE_TYPE (gimple_phi_result (phi)));
 	  for (unsigned x = 0; x < gimple_phi_num_args (phi); x++)
 	    prefill_name (r, gimple_phi_arg_def (phi, x));
 	}
@@ -421,6 +422,7 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
 	{
 	  gcc_checking_assert (range_op_handler (stmt));
 	  tree op = gimple_range_operand2 (stmt);
+	  Value_Range r (TREE_TYPE (name));
 	  if (op)
 	    prefill_name (r, op);
 	  op = gimple_range_operand1 (stmt);
@@ -429,7 +431,10 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
 	}
     }
   if (idx)
-    tracer.trailer (idx, "ROS ", false, ssa, r);
+    {
+      unsupported_range r;
+      tracer.trailer (idx, "ROS ", false, ssa, r);
+    }
 }
 
 
@@ -487,8 +492,10 @@ gimple_ranger::export_global_ranges ()
   bool print_header = true;
   for (unsigned x = 1; x < num_ssa_names; x++)
     {
-      int_range_max r;
       tree name = ssa_name (x);
+      if (!name)
+	continue;
+      Value_Range r (TREE_TYPE (name));
       if (name && !SSA_NAME_IN_FREE_LIST (name)
 	  && gimple_range_ssa_p (name)
 	  && m_cache.get_global_range (r, name)
@@ -507,13 +514,17 @@ gimple_ranger::export_global_ranges ()
 	      print_header = false;
 	    }
 
-	  value_range vr = r;
+	  if (!irange::supports_type_p (TREE_TYPE (name)))
+	    continue;
+
+	  vrange &v = r;
+	  value_range vr = as_a <irange> (v);
 	  print_generic_expr (dump_file, name , TDF_SLIM);
 	  fprintf (dump_file, "  : ");
 	  vr.dump (dump_file);
 	  fprintf (dump_file, "\n");
 	  int_range_max same = vr;
-	  if (same != r)
+	  if (same != as_a <irange> (v))
 	    {
 	      fprintf (dump_file, "         irange : ");
 	      r.dump (dump_file);
@@ -531,7 +542,6 @@ gimple_ranger::dump_bb (FILE *f, basic_block bb)
   unsigned x;
   edge_iterator ei;
   edge e;
-  int_range_max range, tmp_range;
   fprintf (f, "\n=========== BB %d ============\n", bb->index);
   m_cache.dump_bb (f, bb);
 
@@ -541,9 +551,11 @@ gimple_ranger::dump_bb (FILE *f, basic_block bb)
   for (x = 1; x < num_ssa_names; x++)
     {
       tree name = ssa_name (x);
-      if (gimple_range_ssa_p (name) && SSA_NAME_DEF_STMT (name) &&
-	  gimple_bb (SSA_NAME_DEF_STMT (name)) == bb &&
-	  m_cache.get_global_range (range, name))
+      if (!gimple_range_ssa_p (name) || !SSA_NAME_DEF_STMT (name))
+	continue;
+      Value_Range range (TREE_TYPE (name));
+      if (gimple_bb (SSA_NAME_DEF_STMT (name)) == bb
+	  && m_cache.get_global_range (range, name))
 	{
 	  if (!range.varying_p ())
 	    {
@@ -562,10 +574,14 @@ gimple_ranger::dump_bb (FILE *f, basic_block bb)
       for (x = 1; x < num_ssa_names; x++)
 	{
 	  tree name = gimple_range_ssa_p (ssa_name (x));
-	  if (name && gori ().has_edge_range_p (name, e)
-	      && m_cache.range_on_edge (range, e, name))
+	  if (!name || !gori ().has_edge_range_p (name, e))
+	    continue;
+
+	  Value_Range range (TREE_TYPE (name));
+	  if (m_cache.range_on_edge (range, e, name))
 	    {
 	      gimple *s = SSA_NAME_DEF_STMT (name);
+	      Value_Range tmp_range (TREE_TYPE (name));
 	      // Only print the range if this is the def block, or
 	      // the on entry cache for either end of the edge is
 	      // set.
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index c67280dc1d2..34f61025ac3 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -48,11 +48,11 @@ class gimple_ranger : public range_query
 public:
   gimple_ranger (bool use_imm_uses = true);
   ~gimple_ranger ();
-  virtual bool range_of_stmt (irange &r, gimple *, tree name = NULL) override;
-  virtual bool range_of_expr (irange &r, tree name, gimple * = NULL) override;
-  virtual bool range_on_edge (irange &r, edge e, tree name) override;
-  void range_on_entry (irange &r, basic_block bb, tree name);
-  void range_on_exit (irange &r, basic_block bb, tree name);
+  virtual bool range_of_stmt (vrange &r, gimple *, tree name = NULL) override;
+  virtual bool range_of_expr (vrange &r, tree name, gimple * = NULL) override;
+  virtual bool range_on_edge (vrange &r, edge e, tree name) override;
+  void range_on_entry (vrange &r, basic_block bb, tree name);
+  void range_on_exit (vrange &r, basic_block bb, tree name);
   void export_global_ranges ();
   inline gori_compute &gori ()  { return m_cache.m_gori; }
   virtual void dump (FILE *f) override;
@@ -62,8 +62,8 @@ public:
   bool fold_stmt (gimple_stmt_iterator *gsi, tree (*) (tree));
   void register_inferred_ranges (gimple *s);
 protected:
-  bool fold_range_internal (irange &r, gimple *s, tree name);
-  void prefill_name (irange &r, tree name);
+  bool fold_range_internal (vrange &r, gimple *s, tree name);
+  void prefill_name (vrange &r, tree name);
   void prefill_stmt_dependencies (tree ssa);
   ranger_cache m_cache;
   range_tracer tracer;
diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index 9357a4e576a..00f65858b0c 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -328,11 +328,11 @@ check_nul_terminated_array (GimpleOrTree expr, tree src, tree bound)
   wide_int bndrng[2];
   if (bound)
     {
-      value_range r;
+      Value_Range r (TREE_TYPE (bound));
 
       get_global_range_query ()->range_of_expr (r, bound);
 
-      if (r.kind () != VR_RANGE)
+      if (r.undefined_p () || r.varying_p ())
 	return true;
 
       bndrng[0] = r.lower_bound ();
@@ -2790,9 +2790,8 @@ memmodel_to_uhwi (tree ord, gimple *stmt, unsigned HOST_WIDE_INT *cstval)
     {
       /* Use the range query to determine constant values in the absence
 	 of constant propagation (such as at -O0).  */
-      value_range rng;
+      Value_Range rng (TREE_TYPE (ord));
       if (!get_range_query (cfun)->range_of_expr (rng, ord, stmt)
-	  || !rng.constant_p ()
 	  || !rng.singleton_p (&ord))
 	return false;
 
diff --git a/gcc/tree-ssa-loop-niter.cc b/gcc/tree-ssa-loop-niter.cc
index afa51064953..1e0f609d8b6 100644
--- a/gcc/tree-ssa-loop-niter.cc
+++ b/gcc/tree-ssa-loop-niter.cc
@@ -221,7 +221,7 @@ refine_value_range_using_guard (tree type, tree var,
   get_type_static_bounds (type, mint, maxt);
   mpz_init (minc1);
   mpz_init (maxc1);
-  value_range r;
+  Value_Range r (TREE_TYPE (varc1));
   /* Setup range information for varc1.  */
   if (integer_zerop (varc1))
     {
@@ -374,7 +374,7 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off,
       gphi_iterator gsi;
 
       /* Either for VAR itself...  */
-      value_range var_range;
+      Value_Range var_range (TREE_TYPE (var));
       get_range_query (cfun)->range_of_expr (var_range, var);
       rtype = var_range.kind ();
       if (!var_range.undefined_p ())
@@ -385,10 +385,10 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off,
 
       /* Or for PHI results in loop->header where VAR is used as
 	 PHI argument from the loop preheader edge.  */
+      Value_Range phi_range (TREE_TYPE (var));
       for (gsi = gsi_start_phis (loop->header); !gsi_end_p (gsi); gsi_next (&gsi))
 	{
 	  gphi *phi = gsi.phi ();
-	  value_range phi_range;
 	  if (PHI_ARG_DEF_FROM_EDGE (phi, e) == var
 	      && get_range_query (cfun)->range_of_expr (phi_range,
 						    gimple_phi_result (phi))
@@ -410,7 +410,7 @@ determine_value_range (class loop *loop, tree type, tree var, mpz_t off,
 		     involved.  */
 		  if (wi::gt_p (minv, maxv, sgn))
 		    {
-		      value_range vr;
+		      Value_Range vr (TREE_TYPE (var));
 		      get_range_query (cfun)->range_of_expr (vr, var);
 		      rtype = vr.kind ();
 		      if (!vr.undefined_p ())
@@ -3650,7 +3650,7 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt,
   if (tree_int_cst_sign_bit (step))
     {
       wide_int max;
-      value_range base_range;
+      Value_Range base_range (TREE_TYPE (orig_base));
       if (get_range_query (cfun)->range_of_expr (base_range, orig_base)
 	  && !base_range.undefined_p ())
 	max = base_range.upper_bound ();
@@ -3672,7 +3672,7 @@ record_nonwrapping_iv (class loop *loop, tree base, tree step, gimple *stmt,
   else
     {
       wide_int min;
-      value_range base_range;
+      Value_Range base_range (TREE_TYPE (orig_base));
       if (get_range_query (cfun)->range_of_expr (base_range, orig_base)
 	  && !base_range.undefined_p ())
 	min = base_range.lower_bound ();
@@ -3947,7 +3947,7 @@ infer_loop_bounds_from_signedness (class loop *loop, gimple *stmt)
 
   low = lower_bound_in_type (type, type);
   high = upper_bound_in_type (type, type);
-  value_range r;
+  Value_Range r (TREE_TYPE (def));
   get_range_query (cfun)->range_of_expr (r, def);
   if (r.kind () == VR_RANGE)
     {
@@ -4997,7 +4997,7 @@ scev_var_range_cant_overflow (tree var, tree step, class loop *loop)
   if (!def_bb || !dominated_by_p (CDI_DOMINATORS, loop->latch, def_bb))
     return false;
 
-  value_range r;
+  Value_Range r (TREE_TYPE (var));
   get_range_query (cfun)->range_of_expr (r, var);
   if (r.kind () != VR_RANGE)
     return false;
diff --git a/gcc/tree-ssa-loop-unswitch.cc b/gcc/tree-ssa-loop-unswitch.cc
index a55905c2c68..ad1d05ccdff 100644
--- a/gcc/tree-ssa-loop-unswitch.cc
+++ b/gcc/tree-ssa-loop-unswitch.cc
@@ -140,13 +140,13 @@ struct unswitch_predicate
 	int_range<2> rhs_range (TREE_TYPE (rhs));
 	if (CONSTANT_CLASS_P (rhs))
 	  rhs_range.set (rhs);
-	if (!range_op->op1_range (true_range, TREE_TYPE (lhs),
-				  int_range<2> (boolean_true_node,
-						boolean_true_node), rhs_range)
-	    || !range_op->op1_range (false_range, TREE_TYPE (lhs),
-				     int_range<2> (boolean_false_node,
-						   boolean_false_node),
-				     rhs_range))
+	if (!range_op.op1_range (true_range, TREE_TYPE (lhs),
+				 int_range<2> (boolean_true_node,
+					       boolean_true_node), rhs_range)
+	    || !range_op.op1_range (false_range, TREE_TYPE (lhs),
+				    int_range<2> (boolean_false_node,
+						  boolean_false_node),
+				    rhs_range))
 	  {
 	    true_range.set_varying (TREE_TYPE (lhs));
 	    false_range.set_varying (TREE_TYPE (lhs));
diff --git a/gcc/tree-ssa-threadedge.cc b/gcc/tree-ssa-threadedge.cc
index 4eb65ca7cac..931aa7479bb 100644
--- a/gcc/tree-ssa-threadedge.cc
+++ b/gcc/tree-ssa-threadedge.cc
@@ -1409,19 +1409,19 @@ tree
 hybrid_jt_simplifier::simplify (gimple *stmt, gimple *, basic_block,
 				jt_state *state)
 {
-  int_range_max r;
-
   compute_ranges_from_state (stmt, state);
 
   if (gimple_code (stmt) == GIMPLE_COND
       || gimple_code (stmt) == GIMPLE_ASSIGN)
     {
+      Value_Range r (gimple_range_type (stmt));
       tree ret;
       if (m_query->range_of_stmt (r, stmt) && r.singleton_p (&ret))
 	return ret;
     }
   else if (gimple_code (stmt) == GIMPLE_SWITCH)
     {
+      int_range_max r;
       gswitch *switch_stmt = dyn_cast <gswitch *> (stmt);
       tree index = gimple_switch_index (switch_stmt);
       if (m_query->range_of_expr (r, index, stmt))
diff --git a/gcc/value-query.cc b/gcc/value-query.cc
index 31e56eeae53..e40e358ebd4 100644
--- a/gcc/value-query.cc
+++ b/gcc/value-query.cc
@@ -57,13 +57,13 @@ value_query::value_of_stmt (gimple *stmt, tree name)
 // range_query default methods.
 
 bool
-range_query::range_on_edge (irange &r, edge, tree expr)
+range_query::range_on_edge (vrange &r, edge, tree expr)
 {
   return range_of_expr (r, expr);
 }
 
 bool
-range_query::range_of_stmt (irange &r, gimple *stmt, tree name)
+range_query::range_of_stmt (vrange &r, gimple *stmt, tree name)
 {
   if (!name)
     name = gimple_get_lhs (stmt);
@@ -79,11 +79,12 @@ tree
 range_query::value_of_expr (tree expr, gimple *stmt)
 {
   tree t;
-  int_range_max r;
 
-  if (!irange::supports_type_p (TREE_TYPE (expr)))
+  if (!vrange::supports_type_p (TREE_TYPE (expr)))
     return NULL_TREE;
 
+  Value_Range r (TREE_TYPE (expr));
+
   if (range_of_expr (r, expr, stmt))
     {
       // A constant used in an unreachable block oftens returns as UNDEFINED.
@@ -100,10 +101,10 @@ tree
 range_query::value_on_edge (edge e, tree expr)
 {
   tree t;
-  int_range_max r;
 
-  if (!irange::supports_type_p (TREE_TYPE (expr)))
+  if (!vrange::supports_type_p (TREE_TYPE (expr)))
     return NULL_TREE;
+  Value_Range r (TREE_TYPE (expr));
   if (range_on_edge (r, e, expr))
     {
       // A constant used in an unreachable block oftens returns as UNDEFINED.
@@ -121,15 +122,15 @@ tree
 range_query::value_of_stmt (gimple *stmt, tree name)
 {
   tree t;
-  int_range_max r;
 
   if (!name)
     name = gimple_get_lhs (stmt);
 
   gcc_checking_assert (!name || name == gimple_get_lhs (stmt));
 
-  if (!name || !irange::supports_type_p (TREE_TYPE (name)))
+  if (!name || !vrange::supports_type_p (TREE_TYPE (name)))
     return NULL_TREE;
+  Value_Range r (TREE_TYPE (name));
   if (range_of_stmt (r, stmt, name) && r.singleton_p (&t))
     return t;
   return NULL_TREE;
@@ -187,7 +188,7 @@ range_query::~range_query ()
 // representable, and UNDEFINED/false if not.
 
 bool
-range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
+range_query::get_tree_range (vrange &r, tree expr, gimple *stmt)
 {
   tree type;
   if (TYPE_P (expr))
@@ -195,7 +196,7 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
   else
     type = TREE_TYPE (expr);
 
-  if (!irange::supports_type_p (type))
+  if (!vrange::supports_type_p (type))
     {
       r.set_undefined ();
       return false;
@@ -214,7 +215,7 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
       return true;
 
     case SSA_NAME:
-      r = gimple_range_global (expr);
+      gimple_range_global (r, expr);
       return true;
 
     case ADDR_EXPR:
@@ -223,7 +224,7 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
 	bool ov;
 	if (tree_single_nonzero_warnv_p (expr, &ov))
 	  {
-	    r = range_nonzero (type);
+	    r.set_nonzero (type);
 	    return true;
 	  }
 	break;
@@ -237,7 +238,8 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
       range_op_handler op (TREE_CODE (expr), type);
       if (op)
 	{
-	  int_range_max r0, r1;
+	  Value_Range r0 (TREE_TYPE (TREE_OPERAND (expr, 0)));
+	  Value_Range r1 (TREE_TYPE (TREE_OPERAND (expr, 1)));
 	  range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
 	  range_of_expr (r1, TREE_OPERAND (expr, 1), stmt);
 	  op.fold_range (r, type, r0, r1);
@@ -250,11 +252,13 @@ range_query::get_tree_range (irange &r, tree expr, gimple *stmt)
     {
       range_op_handler op (TREE_CODE (expr), type);
       tree op0_type = TREE_TYPE (TREE_OPERAND (expr, 0));
-      if (op && irange::supports_type_p (op0_type))
+      if (op && vrange::supports_type_p (op0_type))
 	{
-	  int_range_max r0;
+	  Value_Range r0 (TREE_TYPE (TREE_OPERAND (expr, 0)));
+	  Value_Range r1 (type);
+	  r1.set_varying (type);
 	  range_of_expr (r0, TREE_OPERAND (expr, 0), stmt);
-	  op.fold_range (r, type, r0, int_range<1> (type));
+	  op.fold_range (r, type, r0, r1);
 	}
       else
 	r.set_varying (type);
@@ -311,7 +315,7 @@ get_ssa_name_ptr_info_nonnull (const_tree name)
 // updated.
 
 bool
-update_global_range (irange &r, tree name)
+update_global_range (vrange &r, tree name)
 {
   tree type = TREE_TYPE (name);
 
@@ -330,8 +334,7 @@ update_global_range (irange &r, tree name)
       if (r.undefined_p ())
 	return false;
 
-      value_range vr = r;
-      set_range_info (name, vr);
+      set_range_info (name, as_a <irange> (r));
       return true;
     }
   else if (POINTER_TYPE_P (type))
@@ -349,7 +352,7 @@ update_global_range (irange &r, tree name)
 // return VARYING.
 
 static void
-get_range_global (irange &r, tree name)
+get_range_global (vrange &r, tree name)
 {
   tree type = TREE_TYPE (name);
 
@@ -369,7 +372,7 @@ get_range_global (irange &r, tree name)
 	    r.set_nonzero (type);
 	  else if (INTEGRAL_TYPE_P (type))
 	    {
-	      get_ssa_name_range_info (r, name);
+	      get_ssa_name_range_info (as_a <irange> (r), name);
 	      if (r.undefined_p ())
 		r.set_varying (type);
 	    }
@@ -384,7 +387,8 @@ get_range_global (irange &r, tree name)
    }
   else if (!POINTER_TYPE_P (type) && SSA_NAME_RANGE_INFO (name))
     {
-      get_ssa_name_range_info (r, name);
+      gcc_checking_assert (irange::supports_type_p (TREE_TYPE (name)));
+      get_ssa_name_range_info (as_a <irange> (r), name);
       if (r.undefined_p ())
 	r.set_varying (type);
     }
@@ -414,21 +418,19 @@ get_range_global (irange &r, tree name)
 // See discussion here:
 // https://gcc.gnu.org/pipermail/gcc-patches/2021-June/571709.html
 
-value_range
-gimple_range_global (tree name)
+void
+gimple_range_global (vrange &r, tree name)
 {
   tree type = TREE_TYPE (name);
-  gcc_checking_assert (TREE_CODE (name) == SSA_NAME
-		       && irange::supports_type_p (type));
+  gcc_checking_assert (TREE_CODE (name) == SSA_NAME);
 
   if (SSA_NAME_IS_DEFAULT_DEF (name) || (cfun && cfun->after_inlining)
       || is_a<gphi *> (SSA_NAME_DEF_STMT (name)))
     {
-      value_range vr;
-      get_range_global (vr, name);
-      return vr;
+      get_range_global (r, name);
+      return;
     }
-  return value_range (type);
+  r.set_varying (type);
 }
 
 // ----------------------------------------------
@@ -437,7 +439,7 @@ gimple_range_global (tree name)
 global_range_query global_ranges;
 
 bool
-global_range_query::range_of_expr (irange &r, tree expr, gimple *stmt)
+global_range_query::range_of_expr (vrange &r, tree expr, gimple *stmt)
 {
   tree type = TREE_TYPE (expr);
 
@@ -456,15 +458,16 @@ global_range_query::range_of_expr (irange &r, tree expr, gimple *stmt)
 relation_kind
 range_query::query_relation (gimple *s, tree ssa1, tree ssa2, bool get_range)
 {
-  int_range_max tmp;
   if (!m_oracle || TREE_CODE (ssa1) != SSA_NAME || TREE_CODE (ssa2) != SSA_NAME)
     return VREL_VARYING;
 
   // Ensure ssa1 and ssa2 have both been evaluated.
   if (get_range)
     {
-      range_of_expr (tmp, ssa1, s);
-      range_of_expr (tmp, ssa2, s);
+      Value_Range tmp1 (TREE_TYPE (ssa1));
+      Value_Range tmp2 (TREE_TYPE (ssa2));
+      range_of_expr (tmp1, ssa1, s);
+      range_of_expr (tmp2, ssa2, s);
     }
   return m_oracle->query_relation (gimple_bb (s), ssa1, ssa2);
 }
@@ -477,7 +480,6 @@ relation_kind
 range_query::query_relation (edge e, tree ssa1, tree ssa2, bool get_range)
 {
   basic_block bb;
-  int_range_max tmp;
   if (!m_oracle || TREE_CODE (ssa1) != SSA_NAME || TREE_CODE (ssa2) != SSA_NAME)
     return VREL_VARYING;
 
@@ -492,6 +494,7 @@ range_query::query_relation (edge e, tree ssa1, tree ssa2, bool get_range)
   // Ensure ssa1 and ssa2 have both been evaluated.
   if (get_range)
     {
+      Value_Range tmp (TREE_TYPE (ssa1));
       range_on_edge (tmp, e, ssa1);
       range_on_edge (tmp, e, ssa2);
     }
diff --git a/gcc/value-query.h b/gcc/value-query.h
index cf1a1d74de3..280e47e3f6b 100644
--- a/gcc/value-query.h
+++ b/gcc/value-query.h
@@ -89,9 +89,9 @@ public:
   //
   // Note that range_of_expr must always return TRUE unless ranges are
   // unsupported for EXPR's type (supports_type_p is false).
-  virtual bool range_of_expr (irange &r, tree expr, gimple * = NULL) = 0;
-  virtual bool range_on_edge (irange &r, edge, tree expr);
-  virtual bool range_of_stmt (irange &r, gimple *, tree name = NULL);
+  virtual bool range_of_expr (vrange &r, tree expr, gimple * = NULL) = 0;
+  virtual bool range_on_edge (vrange &r, edge, tree expr);
+  virtual bool range_of_stmt (vrange &r, gimple *, tree name = NULL);
 
   // Query if there is any relation between SSA1 and SSA2.
   relation_kind query_relation (gimple *s, tree ssa1, tree ssa2,
@@ -110,8 +110,8 @@ public:
 protected:
   class value_range_equiv *allocate_value_range_equiv ();
   void free_value_range_equiv (class value_range_equiv *);
-  bool get_tree_range (irange &r, tree expr, gimple *stmt);
-  bool get_arith_expr_range (irange &r, tree expr, gimple *stmt);
+  bool get_tree_range (vrange &v, tree expr, gimple *stmt);
+  bool get_arith_expr_range (vrange &r, tree expr, gimple *stmt);
   relation_oracle *m_oracle;
 
 private:
@@ -123,7 +123,7 @@ private:
 class global_range_query : public range_query
 {
 public:
-  bool range_of_expr (irange &r, tree expr, gimple * = NULL) override;
+  bool range_of_expr (vrange &r, tree expr, gimple * = NULL) override;
 };
 
 extern global_range_query global_ranges;
@@ -143,7 +143,7 @@ get_range_query (const struct function *fun)
   return fun->x_range_query ? fun->x_range_query : &global_ranges;
 }
 
-extern value_range gimple_range_global (tree name);
-extern bool update_global_range (irange &r, tree name);
+extern void gimple_range_global (vrange &v, tree name);
+extern bool update_global_range (vrange &v, tree name);
 
 #endif // GCC_QUERY_H
diff --git a/gcc/vr-values.cc b/gcc/vr-values.cc
index 6f8583c8d01..38f204e2f5d 100644
--- a/gcc/vr-values.cc
+++ b/gcc/vr-values.cc
@@ -177,7 +177,7 @@ vr_values::get_value_range (const_tree var,
 }
 
 bool
-vr_values::range_of_expr (irange &r, tree expr, gimple *stmt)
+vr_values::range_of_expr (vrange &r, tree expr, gimple *stmt)
 {
   if (!gimple_range_ssa_p (expr))
     return get_tree_range (r, expr, stmt);
@@ -1630,6 +1630,20 @@ compare_range_with_value (enum tree_code comp, const value_range *vr,
   gcc_unreachable ();
 }
 
+static inline void
+fix_overflow (tree *min, tree *max)
+{
+  /* Even for valid range info, sometimes overflow flag will leak in.
+     As GIMPLE IL should have no constants with TREE_OVERFLOW set, we
+     drop them.  */
+  if (TREE_OVERFLOW_P (*min))
+    *min = drop_tree_overflow (*min);
+  if (TREE_OVERFLOW_P (*max))
+    *max = drop_tree_overflow (*max);
+
+  gcc_checking_assert (compare_values (*min, *max) != 1);
+}
+
 /* Given a VAR in STMT within LOOP, determine the bounds of the
    variable and store it in MIN/MAX and return TRUE.  If no bounds
    could be determined, return FALSE.  */
@@ -1640,6 +1654,7 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
 {
   tree init, step, chrec, tmin, tmax, type = TREE_TYPE (var);
   enum ev_direction dir;
+  int_range<2> r;
 
   chrec = instantiate_parameters (loop, analyze_scalar_evolution (loop, var));
 
@@ -1647,7 +1662,8 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
   if (is_gimple_min_invariant (chrec))
     {
       *min = *max = chrec;
-      goto fix_overflow;
+      fix_overflow (min, max);
+      return true;
     }
 
   if (TREE_CODE (chrec) != POLYNOMIAL_CHREC)
@@ -1659,13 +1675,17 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
   if (!init || !step)
     return false;
 
+  Value_Range rinit (TREE_TYPE (init));
+  Value_Range rstep (TREE_TYPE (step));
   /* If INIT is an SSA with a singleton range, set INIT to said
      singleton, otherwise leave INIT alone.  */
-  if (TREE_CODE (init) == SSA_NAME)
-    query->get_value_range (init, stmt)->singleton_p (&init);
+  if (TREE_CODE (init) == SSA_NAME
+      && query->range_of_expr (rinit, init, stmt))
+    rinit.singleton_p (&init);
   /* Likewise for step.  */
-  if (TREE_CODE (step) == SSA_NAME)
-    query->get_value_range (step, stmt)->singleton_p (&step);
+  if (TREE_CODE (step) == SSA_NAME
+      && query->range_of_expr (rstep, step, stmt))
+    rstep.singleton_p (&step);
 
   /* If STEP is symbolic, we can't know whether INIT will be the
      minimum or maximum value in the range.  Also, unless INIT is
@@ -1699,7 +1719,8 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
   if (TREE_CODE (step) == INTEGER_CST
       && is_gimple_val (init)
       && (TREE_CODE (init) != SSA_NAME
-	  || query->get_value_range (init, stmt)->kind () == VR_RANGE))
+	  || (query->range_of_expr (r, init, stmt)
+	      && r.kind () == VR_RANGE)))
     {
       widest_int nit;
 
@@ -1724,7 +1745,7 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
 	    {
 	      value_range maxvr, vr0, vr1;
 	      if (TREE_CODE (init) == SSA_NAME)
-		vr0 = *(query->get_value_range (init, stmt));
+		query->range_of_expr (vr0, init, stmt);
 	      else if (is_gimple_min_invariant (init))
 		vr0.set (init);
 	      else
@@ -1737,10 +1758,10 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
 	      /* Likewise if the addition did.  */
 	      if (maxvr.kind () == VR_RANGE)
 		{
-		  value_range initvr;
+		  int_range<2> initvr;
 
 		  if (TREE_CODE (init) == SSA_NAME)
-		    initvr = *(query->get_value_range (init, stmt));
+		    query->range_of_expr (initvr, init, stmt);
 		  else if (is_gimple_min_invariant (init))
 		    initvr.set (init);
 		  else
@@ -1770,16 +1791,7 @@ bounds_of_var_in_loop (tree *min, tree *max, range_query *query,
   else
     *min = init;
 
- fix_overflow:
-  /* Even for valid range info, sometimes overflow flag will leak in.
-     As GIMPLE IL should have no constants with TREE_OVERFLOW set, we
-     drop them.  */
-  if (TREE_OVERFLOW_P (*min))
-    *min = drop_tree_overflow (*min);
-  if (TREE_OVERFLOW_P (*max))
-    *max = drop_tree_overflow (*max);
-
-  gcc_checking_assert (compare_values (*min, *max) != 1);
+  fix_overflow (min, max);
   return true;
 }
 
@@ -2446,7 +2458,9 @@ simplify_using_ranges::vrp_visit_cond_stmt (gcond *stmt, edge *taken_edge_p)
 	  fprintf (dump_file, "\t");
 	  print_generic_expr (dump_file, use);
 	  fprintf (dump_file, ": ");
-	  dump_value_range (dump_file, query->get_value_range (use, stmt));
+	  Value_Range r (TREE_TYPE (use));
+	  query->range_of_expr (r, use, stmt);
+	  r.dump (dump_file);
 	}
 
       fprintf (dump_file, "\n");
diff --git a/gcc/vr-values.h b/gcc/vr-values.h
index 7a377cebd01..f018d0dfc4b 100644
--- a/gcc/vr-values.h
+++ b/gcc/vr-values.h
@@ -109,7 +109,7 @@ class vr_values : public range_query
   vr_values (void);
   ~vr_values (void);
 
-  virtual bool range_of_expr (irange &r, tree expr, gimple *stmt) override;
+  virtual bool range_of_expr (vrange &r, tree expr, gimple *stmt) override;
   virtual tree value_of_expr (tree, gimple * = NULL) override;
   virtual tree value_on_edge (edge, tree) override;
   virtual tree value_of_stmt (gimple *, tree = NULL_TREE) override;
-- 
2.36.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 5/5] Convert ranger and clients to vrange.
  2022-06-01  9:04   ` Aldy Hernandez
@ 2022-06-27  0:33     ` Xi Ruoyao
  0 siblings, 0 replies; 14+ messages in thread
From: Xi Ruoyao @ 2022-06-27  0:33 UTC (permalink / raw)
  To: Aldy Hernandez, GCC patches; +Cc: Chenghua Xu, Lulu Cheng

On Wed, 2022-06-01 at 11:04 +0200, Aldy Hernandez via Gcc-patches wrote:
> Final patch committed.
> 
> All users but one of Value_Range::set_type() have been removed in
> favor of using a constructor taking a type.   We still need to delay
> initialization for one use in gimple_infer_range, as it has an array
> of temporaries for which the type is not known until later.
> 
> Re-tested on x86-64 Linux.

Bootstrap on loongarch64-linux-gnu is broken since r13-911.  I've
created https://gcc.gnu.org/PR106096 and put all information I've
gathered so far in the PR.

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2022-06-27  0:33 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-05-30 13:27 [PATCH 1/5] Implement abstract vrange class Aldy Hernandez
2022-05-30 13:27 ` [PATCH 2/5] Implement generic range temporaries Aldy Hernandez
2022-05-30 14:56   ` Andrew MacLeod
2022-05-31  6:21     ` Aldy Hernandez
2022-05-31 16:40       ` Andrew MacLeod
2022-06-01  9:01       ` Aldy Hernandez
2022-05-30 13:27 ` [PATCH 3/5] Convert range-op.* to vrange Aldy Hernandez
2022-06-01  9:01   ` Aldy Hernandez
2022-05-30 13:27 ` [PATCH 4/5] Revamp irange_allocator to handle vranges Aldy Hernandez
2022-06-01  9:02   ` Aldy Hernandez
2022-05-30 13:27 ` [PATCH 5/5] Convert ranger and clients to vrange Aldy Hernandez
2022-06-01  9:04   ` Aldy Hernandez
2022-06-27  0:33     ` Xi Ruoyao
2022-06-01  8:57 ` [PATCH 1/5] Implement abstract vrange class Aldy Hernandez

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).