RFC: Implementing a new API for value_range
diff mbox series

Message ID e0333cf0-d384-9097-b5cc-440519e7d788@redhat.com
State New
Headers show
Series
  • RFC: Implementing a new API for value_range
Related show

Commit Message

Aldy Hernandez Oct. 3, 2018, 6:36 a.m. UTC
Hi Richard.  Hi folks.

I'd like to implement a clean API that disallows direct access to any of 
the value_range internals.  My aim is a clean API with no change in 
functionality.

This is mostly a clean-up, but could also pave the way for possibly 
changing the underlying implementation in the future so we can unite VPR 
and the on-demand work with a single common code base.

I am quoting the main structure below to give an idea where I'd like to 
head, and am also attaching a proof-of-concept patch to tree-vrp.[hc]. 
It is untested and only builds cc1.

Ideally I'd like to evolve this to include other methods that make the 
VRP / vr-values code more readable.

Note: I have added a tree type field (m_type) to make it easy to 
determine the tree type of the range.  Right now a value_range looses 
the range type if UNDEFINED or VARYING, as both min/max are NULL.  If 
there is strong objection to the extra word, we could set min/max to 
integer_zero_node in the type if UNDEFINED/VARYING.  But really, all 
this will be hidden in the API, so we could change the underlying 
representation at will.

Would you be ok with this if I continue down this path?

Thanks.
Aldy

struct GTY((for_user)) value_range
{
   value_range ();
   value_range (tree type);
   value_range (tree type, value_range_type, tree, tree, bitmap = NULL);
   value_range (const value_range &);
   bool operator== (const value_range &) const;
   bool operator!= (const value_range &) const;
   void intersect (const value_range *);
   void union_ (const value_range *);

   /* Types of value ranges.  */
   bool undefined_p () const;
   bool varying_p () const;
   bool symbolic_p () const;
   bool numeric_p () const;
   void set_undefined ();
   void set_varying ();

   /* Equivalence bitmap methods.  */
   bitmap equiv () const;
   void set_equiv (bitmap);
   void equiv_free ();
   void equiv_copy (const value_range *);
   void equiv_clear ();
   void equiv_and (const value_range *);
   void equiv_ior (const value_range *);

   /* Misc methods.  */
   tree type () const;
   bool null_p () const;
   bool may_contain_p (tree) const;
   tree singleton () const;
   void canonicalize ();
   void copy_with_equiv_update (const value_range *);
   void dump () const;

   /* Temporary accessors that should eventually be removed.  */
   enum value_range_type vrtype () const;
   tree min () const;
   tree max () const;

   /* private: These are public because of GTY stupidity.  */
   enum value_range_type m_vrtype;
   tree m_min;
   tree m_max;
   tree m_type;
   /* Set of SSA names whose value ranges are equivalent to this one.
      This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
   bitmap m_equiv;

  private:
   void init (tree type, value_range_type, tree, tree, bitmap);
   void check ();
};

Comments

Aldy Hernandez Oct. 3, 2018, 8:20 a.m. UTC | #1
Sorry, I meant to say it only builds tree-vrp.o.

On Wed, Oct 3, 2018, 09:36 Aldy Hernandez <aldyh@redhat.com> wrote:

> Hi Richard.  Hi folks.
>
> I'd like to implement a clean API that disallows direct access to any of
> the value_range internals.  My aim is a clean API with no change in
> functionality.
>
> This is mostly a clean-up, but could also pave the way for possibly
> changing the underlying implementation in the future so we can unite VPR
> and the on-demand work with a single common code base.
>
> I am quoting the main structure below to give an idea where I'd like to
> head, and am also attaching a proof-of-concept patch to tree-vrp.[hc].
> It is untested and only builds cc1.
>
> Ideally I'd like to evolve this to include other methods that make the
> VRP / vr-values code more readable.
>
> Note: I have added a tree type field (m_type) to make it easy to
> determine the tree type of the range.  Right now a value_range looses
> the range type if UNDEFINED or VARYING, as both min/max are NULL.  If
> there is strong objection to the extra word, we could set min/max to
> integer_zero_node in the type if UNDEFINED/VARYING.  But really, all
> this will be hidden in the API, so we could change the underlying
> representation at will.
>
> Would you be ok with this if I continue down this path?
>
> Thanks.
> Aldy
>
> struct GTY((for_user)) value_range
> {
>    value_range ();
>    value_range (tree type);
>    value_range (tree type, value_range_type, tree, tree, bitmap = NULL);
>    value_range (const value_range &);
>    bool operator== (const value_range &) const;
>    bool operator!= (const value_range &) const;
>    void intersect (const value_range *);
>    void union_ (const value_range *);
>
>    /* Types of value ranges.  */
>    bool undefined_p () const;
>    bool varying_p () const;
>    bool symbolic_p () const;
>    bool numeric_p () const;
>    void set_undefined ();
>    void set_varying ();
>
>    /* Equivalence bitmap methods.  */
>    bitmap equiv () const;
>    void set_equiv (bitmap);
>    void equiv_free ();
>    void equiv_copy (const value_range *);
>    void equiv_clear ();
>    void equiv_and (const value_range *);
>    void equiv_ior (const value_range *);
>
>    /* Misc methods.  */
>    tree type () const;
>    bool null_p () const;
>    bool may_contain_p (tree) const;
>    tree singleton () const;
>    void canonicalize ();
>    void copy_with_equiv_update (const value_range *);
>    void dump () const;
>
>    /* Temporary accessors that should eventually be removed.  */
>    enum value_range_type vrtype () const;
>    tree min () const;
>    tree max () const;
>
>    /* private: These are public because of GTY stupidity.  */
>    enum value_range_type m_vrtype;
>    tree m_min;
>    tree m_max;
>    tree m_type;
>    /* Set of SSA names whose value ranges are equivalent to this one.
>       This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
>    bitmap m_equiv;
>
>   private:
>    void init (tree type, value_range_type, tree, tree, bitmap);
>    void check ();
> };
>

Patch
diff mbox series

diff --git a/gcc/tree-vrp.h b/gcc/tree-vrp.h
index 655cf055f0a..b2b9f971bae 100644
--- a/gcc/tree-vrp.h
+++ b/gcc/tree-vrp.h
@@ -29,31 +29,177 @@  enum value_range_type { VR_UNDEFINED, VR_RANGE,
    has executed.  */
 struct GTY((for_user)) value_range
 {
-  /* Lattice value represented by this range.  */
-  enum value_range_type type;
+  value_range ();
+  value_range (tree type);
+  value_range (tree type, value_range_type, tree, tree, bitmap = NULL);
+  value_range (const value_range &);
+  bool operator== (const value_range &) const;
+  bool operator!= (const value_range &) const;
+  void intersect (const value_range *);
+  void union_ (const value_range *);
 
-  /* Minimum and maximum values represented by this range.  These
-     values should be interpreted as follows:
+  /* Types of value ranges.  */
+  bool undefined_p () const;
+  bool varying_p () const;
+  bool symbolic_p () const;
+  bool numeric_p () const;
+  void set_undefined ();
+  void set_varying ();
 
-	- If TYPE is VR_UNDEFINED or VR_VARYING then MIN and MAX must
-	  be NULL.
+  /* Equivalence bitmap methods.  */
+  bitmap equiv () const;
+  void set_equiv (bitmap);
+  void equiv_free ();
+  void equiv_copy (const value_range *);
+  void equiv_clear ();
+  void equiv_and (const value_range *);
+  void equiv_ior (const value_range *);
 
-	- If TYPE == VR_RANGE then MIN holds the minimum value and
-	  MAX holds the maximum value of the range [MIN, MAX].
+  /* Misc methods.  */
+  tree type () const;
+  bool null_p () const;
+  bool may_contain_p (tree) const;
+  tree singleton () const;
+  void canonicalize ();
+  void copy_with_equiv_update (const value_range *);
+  void dump () const;
 
-	- If TYPE == ANTI_RANGE the variable is known to NOT
-	  take any values in the range [MIN, MAX].  */
-  tree min;
-  tree max;
+  /* Temporary accessors that should eventually be removed.  */
+  enum value_range_type vrtype () const;
+  tree min () const;
+  tree max () const;
 
+  /* private: These are public because of GTY stupidity.  */
+  enum value_range_type m_vrtype;
+  tree m_min;
+  tree m_max;
+  tree m_type;
   /* Set of SSA names whose value ranges are equivalent to this one.
      This set is only valid when TYPE is VR_RANGE or VR_ANTI_RANGE.  */
-  bitmap equiv;
+  bitmap m_equiv;
 
-  /* Dump value range to stderr.  */
-  void dump () const;
+ private:
+  void init (tree type, value_range_type, tree, tree, bitmap);
+  void check ();
 };
 
+value_range::value_range ()
+{
+  m_type = m_min = m_max = NULL;
+  m_vrtype = VR_UNDEFINED;
+  m_equiv = NULL;
+}
+
+value_range::value_range (tree type)
+{
+  m_vrtype = VR_UNDEFINED;
+  m_min = m_max = NULL;
+  m_equiv = NULL;
+  m_type = type;
+}
+
+value_range::value_range (const value_range &other)
+{
+  *this = other;
+}
+
+inline value_range_type
+value_range::vrtype () const
+{
+  return m_vrtype;
+}
+
+inline tree
+value_range::type () const
+{
+  return m_type;
+}
+
+inline bitmap
+value_range::equiv () const
+{
+  return m_equiv;
+}
+
+inline tree
+value_range::min () const
+{
+  return m_min;
+}
+
+inline tree
+value_range::max () const
+{
+  return m_max;
+}
+
+inline void
+value_range::set_undefined ()
+{
+  if (m_equiv)
+    bitmap_clear (m_equiv);
+  *this = value_range (m_type, VR_UNDEFINED, NULL, NULL, m_equiv);
+}
+
+inline void
+value_range::set_varying ()
+{
+  if (m_equiv)
+    bitmap_clear (m_equiv);
+  *this = value_range (m_type, VR_VARYING, NULL, NULL, m_equiv);
+}
+
+inline bool
+value_range::varying_p () const
+{
+  return m_vrtype == VR_VARYING;
+}
+
+inline bool
+value_range::undefined_p () const
+{
+  return m_vrtype == VR_UNDEFINED;
+}
+
+inline void
+value_range::equiv_free ()
+{
+  BITMAP_FREE (m_equiv);
+  m_equiv = NULL;
+}
+
+inline void
+value_range::set_equiv (bitmap b)
+{
+  m_equiv = b;
+}
+
+inline void
+value_range::equiv_copy (const value_range *other)
+{
+  bitmap_copy (m_equiv, other->m_equiv);
+}
+
+inline void
+value_range::equiv_clear ()
+{
+  if (m_equiv)
+    bitmap_clear (m_equiv);
+}
+
+inline void
+value_range::equiv_and (const value_range *other)
+{
+  if (m_equiv && other->m_equiv)
+    bitmap_and_into (m_equiv, other->m_equiv);
+}
+
+inline void
+value_range::equiv_ior (const value_range *other)
+{
+  bitmap_ior_into (m_equiv, other->m_equiv);
+}
+
 extern void vrp_intersect_ranges (value_range *vr0, const value_range *vr1);
 extern void vrp_meet (value_range *vr0, const value_range *vr1);
 extern void dump_value_range (FILE *, const value_range *);
@@ -97,7 +243,6 @@  extern void set_and_canonicalize_value_range (value_range *,
 					      tree, tree, bitmap);
 extern bool vrp_bitmap_equal_p (const_bitmap, const_bitmap);
 extern tree value_range_constant_singleton (const value_range *);
-extern bool symbolic_range_p (const value_range *);
 extern int compare_values (tree, tree);
 extern int compare_values_warnv (tree, tree, bool *);
 extern bool vrp_val_is_min (const_tree);
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 005fc2ffe2d..34d76b5b5a6 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -73,6 +73,260 @@  along with GCC; see the file COPYING3.  If not see
    for still active basic-blocks.  */
 static sbitmap *live;
 
+void
+value_range::init (tree type, enum value_range_type vrtype,
+		   tree min, tree max, bitmap equiv)
+{
+  m_type = type;
+  m_vrtype = vrtype;
+  m_min = min;
+  m_max = max;
+
+  /* Since updating the equivalence set involves deep copying the
+     bitmaps, only do it if absolutely necessary.
+
+     All equivalence bitmaps are allocated from the same obstack.  So
+     we can use the obstack associated with EQUIV to allocate vr->equiv.  */
+  if (m_equiv == NULL
+      && equiv != NULL)
+    m_equiv = BITMAP_ALLOC (equiv->obstack);
+
+  if (equiv != m_equiv)
+    {
+      if (equiv && !bitmap_empty_p (equiv))
+	bitmap_copy (m_equiv, equiv);
+      else
+	bitmap_clear (m_equiv);
+    }
+}
+
+value_range::value_range (tree type, value_range_type vrtype,
+			  tree min, tree max, bitmap equiv)
+{
+  m_equiv = NULL;
+  init (type, vrtype, min, max, equiv);
+  if (flag_checking)
+    check ();
+}
+
+void
+value_range::copy_with_equiv_update (const value_range *from)
+{
+  init (from->m_type, from->m_vrtype, from->m_min, from->m_max,
+	from->m_equiv);
+}
+
+/* Check the validity of the range.  */
+
+void
+value_range::check ()
+{
+  if (flag_checking
+      && (m_vrtype == VR_RANGE || m_vrtype == VR_ANTI_RANGE))
+    {
+      int cmp;
+
+      gcc_assert (m_min && m_max);
+
+      gcc_assert (!TREE_OVERFLOW_P (m_min) && !TREE_OVERFLOW_P (m_max));
+
+      if (INTEGRAL_TYPE_P (TREE_TYPE (m_min)) && m_vrtype == VR_ANTI_RANGE)
+	gcc_assert (!vrp_val_is_min (m_min) || !vrp_val_is_max (m_max));
+
+      cmp = compare_values (m_min, m_max);
+      gcc_assert (cmp == 0 || cmp == -1 || cmp == -2);
+    }
+
+  if (flag_checking
+      && (m_vrtype == VR_UNDEFINED || m_vrtype == VR_VARYING))
+    {
+      gcc_assert (m_min == NULL_TREE && m_max == NULL_TREE);
+      gcc_assert (m_equiv == NULL || bitmap_empty_p (m_equiv));
+    }
+
+}
+
+bool
+value_range::operator== (const value_range &other) const
+{
+ return (m_type == other.m_type
+	 && m_vrtype == other.m_vrtype
+	 && vrp_operand_equal_p (m_min, other.m_min)
+	 && vrp_operand_equal_p (m_max, other.m_max)
+	 && vrp_bitmap_equal_p (m_equiv, other.m_equiv));
+}
+
+bool
+value_range::operator!= (const value_range &other) const
+{
+ return !(*this == other);
+}
+
+bool
+value_range::null_p () const
+{
+  return (m_vrtype == VR_RANGE
+	  && integer_zerop (m_min)
+	  && integer_zerop (m_max));
+}
+
+bool
+value_range::symbolic_p () const
+{
+  return (!varying_p ()
+	  && !undefined_p ()
+	  && (!is_gimple_min_invariant (m_min)
+	      || !is_gimple_min_invariant (m_max)));
+}
+
+/* NOTE: Numeric is not the inverse of symbolic_p because the range
+   could also be varying or undefined.  Ideally they should be inverse
+   of each other, with varying only applying to symbolics.  Varying of
+   numerics would be represented as [-MIN, +MAX].  */
+
+bool
+value_range::numeric_p () const
+{
+  return (!varying_p ()
+	  && !undefined_p ()
+	  && TREE_CODE (m_min) == INTEGER_CST
+	  && TREE_CODE (m_max) == INTEGER_CST);
+}
+
+bool
+value_range::may_contain_p (tree val) const
+{
+  if (varying_p ())
+    return true;
+
+  if (undefined_p ())
+    return true;
+
+  if (m_vrtype == VR_ANTI_RANGE)
+    {
+      int res = value_inside_range (val, m_min, m_max);
+      return res == 0 || res == -2;
+    }
+  return value_inside_range (val, m_min, m_max) != 0;
+}
+
+tree
+value_range::singleton () const
+{
+  if (range_int_cst_p (this) && vrp_operand_equal_p (m_min, m_max))
+    {
+      gcc_assert (is_gimple_min_invariant (m_min));
+      return m_min;
+    }
+  return NULL;
+}
+
+/* Canonicalize the current value_range.  This means adjusting for
+   wrapping ranges with MAX < MIN covering [MIN, type_max] U
+   [type_min, MAX] as anti-rage ~[MAX+1, MIN-1].  Likewise for
+   wrapping anti-ranges.  In corner cases where MAX+1 or MIN-1 wraps
+   this will fall back to varying.  This routine exists to ease
+   canonicalization in the case where we extract ranges from var + CST
+   op limit.  */
+
+void
+value_range::canonicalize ()
+{
+  if (undefined_p () || varying_p ())
+    return;
+
+  /* Nothing to canonicalize for symbolic ranges.  */
+  if (TREE_CODE (m_min) != INTEGER_CST
+      || TREE_CODE (m_max) != INTEGER_CST)
+    return;
+
+  /* Wrong order for min and max, to swap them and the VR type we need
+     to adjust them.  */
+  if (tree_int_cst_lt (m_max, m_min))
+    {
+      tree one, tmp;
+
+      /* For one bit precision if max < min, then the swapped
+	 range covers all values, so for VR_RANGE it is varying and
+	 for VR_ANTI_RANGE empty range, so drop to varying as well.  */
+      if (TYPE_PRECISION (TREE_TYPE (m_min)) == 1)
+	{
+	  set_varying ();
+	  return;
+	}
+
+      one = build_int_cst (TREE_TYPE (m_min), 1);
+      tmp = int_const_binop (PLUS_EXPR, m_max, one);
+      m_max = int_const_binop (MINUS_EXPR, m_min, one);
+      m_min = tmp;
+
+      /* There's one corner case, if we had [C+1, C] before we now have
+	 that again.  But this represents an empty value range, so drop
+	 to varying in this case.  */
+      if (tree_int_cst_lt (m_max, m_min))
+	{
+	  set_varying ();
+	  return;
+	}
+
+      m_vrtype = m_vrtype == VR_RANGE ? VR_ANTI_RANGE : VR_RANGE;
+    }
+
+  /* Anti-ranges that can be represented as ranges should be so.  */
+  if (m_vrtype == VR_ANTI_RANGE)
+    {
+      /* For -fstrict-enums we may receive out-of-range ranges so consider
+         values < -INF and values > INF as -INF/INF as well.  */
+      tree type = TREE_TYPE (m_min);
+      bool is_min = (INTEGRAL_TYPE_P (type)
+		     && tree_int_cst_compare (m_min,
+					      TYPE_MIN_VALUE (type)) <= 0);
+      bool is_max = (INTEGRAL_TYPE_P (type)
+		     && tree_int_cst_compare (m_max,
+					      TYPE_MAX_VALUE (type)) >= 0);
+
+      if (is_min && is_max)
+	{
+	  /* We cannot deal with empty ranges, drop to varying.
+	     ???  This could be VR_UNDEFINED instead.  */
+	  set_varying ();
+	  return;
+	}
+      else if (TYPE_PRECISION (TREE_TYPE (m_min)) == 1
+	       && (is_min || is_max))
+	{
+	  /* Non-empty boolean ranges can always be represented
+	     as a singleton range.  */
+	  if (is_min)
+	    m_min = m_max = vrp_val_max (TREE_TYPE (m_min));
+	  else
+	    m_min = m_max = vrp_val_min (TREE_TYPE (m_min));
+	  m_vrtype = VR_RANGE;
+	}
+      else if (is_min
+	       /* As a special exception preserve non-null ranges.  */
+	       && !(TYPE_UNSIGNED (TREE_TYPE (m_min))
+		    && integer_zerop (m_max)))
+        {
+	  tree one = build_int_cst (TREE_TYPE (m_max), 1);
+	  m_min = int_const_binop (PLUS_EXPR, m_max, one);
+	  m_max = vrp_val_max (TREE_TYPE (m_max));
+	  m_vrtype = VR_RANGE;
+        }
+      else if (is_max)
+        {
+	  tree one = build_int_cst (TREE_TYPE (m_min), 1);
+	  m_max = int_const_binop (MINUS_EXPR, m_min, one);
+	  m_min = vrp_val_min (TREE_TYPE (m_min));
+	  m_vrtype = VR_RANGE;
+        }
+    }
+
+  /* Do not drop [-INF(OVF), +INF(OVF)] to varying.  (OVF) has to be sticky
+     to make sure VRP iteration terminates, otherwise we can get into
+     oscillations.  */
+}
+
 /* Return true if the SSA name NAME is live on the edge E.  */
 
 static bool
@@ -245,10 +499,7 @@  intersect_range_with_nonzero_bits (enum value_range_type vr_type,
 static inline void
 set_value_range_to_undefined (value_range *vr)
 {
-  vr->type = VR_UNDEFINED;
-  vr->min = vr->max = NULL_TREE;
-  if (vr->equiv)
-    bitmap_clear (vr->equiv);
+  vr->set_undefined ();
 }
 
 /* Set value range VR to VR_VARYING.  */
@@ -256,183 +507,26 @@  set_value_range_to_undefined (value_range *vr)
 void
 set_value_range_to_varying (value_range *vr)
 {
-  vr->type = VR_VARYING;
-  vr->min = vr->max = NULL_TREE;
-  if (vr->equiv)
-    bitmap_clear (vr->equiv);
+  vr->set_varying ();
 }
 
 /* Set value range VR to {T, MIN, MAX, EQUIV}.  */
 
 void
-set_value_range (value_range *vr, enum value_range_type t, tree min,
-		 tree max, bitmap equiv)
+set_value_range (value_range *vr, tree type, enum value_range_type vrtype,
+		 tree min, tree max, bitmap equiv)
 {
-  /* Check the validity of the range.  */
-  if (flag_checking
-      && (t == VR_RANGE || t == VR_ANTI_RANGE))
-    {
-      int cmp;
-
-      gcc_assert (min && max);
-
-      gcc_assert (!TREE_OVERFLOW_P (min) && !TREE_OVERFLOW_P (max));
-
-      if (INTEGRAL_TYPE_P (TREE_TYPE (min)) && t == VR_ANTI_RANGE)
-	gcc_assert (!vrp_val_is_min (min) || !vrp_val_is_max (max));
-
-      cmp = compare_values (min, max);
-      gcc_assert (cmp == 0 || cmp == -1 || cmp == -2);
-    }
-
-  if (flag_checking
-      && (t == VR_UNDEFINED || t == VR_VARYING))
-    {
-      gcc_assert (min == NULL_TREE && max == NULL_TREE);
-      gcc_assert (equiv == NULL || bitmap_empty_p (equiv));
-    }
-
-  vr->type = t;
-  vr->min = min;
-  vr->max = max;
-
-  /* Since updating the equivalence set involves deep copying the
-     bitmaps, only do it if absolutely necessary.
-
-     All equivalence bitmaps are allocated from the same obstack.  So
-     we can use the obstack associated with EQUIV to allocate vr->equiv.  */
-  if (vr->equiv == NULL
-      && equiv != NULL)
-    vr->equiv = BITMAP_ALLOC (equiv->obstack);
-
-  if (equiv != vr->equiv)
-    {
-      if (equiv && !bitmap_empty_p (equiv))
-	bitmap_copy (vr->equiv, equiv);
-      else
-	bitmap_clear (vr->equiv);
-    }
+  value_range tmp (type, vrtype, min, max, equiv);
+  vr->copy_with_equiv_update (&tmp);
 }
 
-
-/* Set value range VR to the canonical form of {T, MIN, MAX, EQUIV}.
-   This means adjusting T, MIN and MAX representing the case of a
-   wrapping range with MAX < MIN covering [MIN, type_max] U [type_min, MAX]
-   as anti-rage ~[MAX+1, MIN-1].  Likewise for wrapping anti-ranges.
-   In corner cases where MAX+1 or MIN-1 wraps this will fall back
-   to varying.
-   This routine exists to ease canonicalization in the case where we
-   extract ranges from var + CST op limit.  */
-
 void
-set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
+set_and_canonicalize_value_range (value_range *vr,
+				  enum value_range_type vrtype,
 				  tree min, tree max, bitmap equiv)
 {
-  /* Use the canonical setters for VR_UNDEFINED and VR_VARYING.  */
-  if (t == VR_UNDEFINED)
-    {
-      set_value_range_to_undefined (vr);
-      return;
-    }
-  else if (t == VR_VARYING)
-    {
-      set_value_range_to_varying (vr);
-      return;
-    }
-
-  /* Nothing to canonicalize for symbolic ranges.  */
-  if (TREE_CODE (min) != INTEGER_CST
-      || TREE_CODE (max) != INTEGER_CST)
-    {
-      set_value_range (vr, t, min, max, equiv);
-      return;
-    }
-
-  /* Wrong order for min and max, to swap them and the VR type we need
-     to adjust them.  */
-  if (tree_int_cst_lt (max, min))
-    {
-      tree one, tmp;
-
-      /* For one bit precision if max < min, then the swapped
-	 range covers all values, so for VR_RANGE it is varying and
-	 for VR_ANTI_RANGE empty range, so drop to varying as well.  */
-      if (TYPE_PRECISION (TREE_TYPE (min)) == 1)
-	{
-	  set_value_range_to_varying (vr);
-	  return;
-	}
-
-      one = build_int_cst (TREE_TYPE (min), 1);
-      tmp = int_const_binop (PLUS_EXPR, max, one);
-      max = int_const_binop (MINUS_EXPR, min, one);
-      min = tmp;
-
-      /* There's one corner case, if we had [C+1, C] before we now have
-	 that again.  But this represents an empty value range, so drop
-	 to varying in this case.  */
-      if (tree_int_cst_lt (max, min))
-	{
-	  set_value_range_to_varying (vr);
-	  return;
-	}
-
-      t = t == VR_RANGE ? VR_ANTI_RANGE : VR_RANGE;
-    }
-
-  /* Anti-ranges that can be represented as ranges should be so.  */
-  if (t == VR_ANTI_RANGE)
-    {
-      /* For -fstrict-enums we may receive out-of-range ranges so consider
-         values < -INF and values > INF as -INF/INF as well.  */
-      tree type = TREE_TYPE (min);
-      bool is_min = (INTEGRAL_TYPE_P (type)
-		     && tree_int_cst_compare (min, TYPE_MIN_VALUE (type)) <= 0);
-      bool is_max = (INTEGRAL_TYPE_P (type)
-		     && tree_int_cst_compare (max, TYPE_MAX_VALUE (type)) >= 0);
-
-      if (is_min && is_max)
-	{
-	  /* We cannot deal with empty ranges, drop to varying.
-	     ???  This could be VR_UNDEFINED instead.  */
-	  set_value_range_to_varying (vr);
-	  return;
-	}
-      else if (TYPE_PRECISION (TREE_TYPE (min)) == 1
-	       && (is_min || is_max))
-	{
-	  /* Non-empty boolean ranges can always be represented
-	     as a singleton range.  */
-	  if (is_min)
-	    min = max = vrp_val_max (TREE_TYPE (min));
-	  else
-	    min = max = vrp_val_min (TREE_TYPE (min));
-	  t = VR_RANGE;
-	}
-      else if (is_min
-	       /* As a special exception preserve non-null ranges.  */
-	       && !(TYPE_UNSIGNED (TREE_TYPE (min))
-		    && integer_zerop (max)))
-        {
-	  tree one = build_int_cst (TREE_TYPE (max), 1);
-	  min = int_const_binop (PLUS_EXPR, max, one);
-	  max = vrp_val_max (TREE_TYPE (max));
-	  t = VR_RANGE;
-        }
-      else if (is_max)
-        {
-	  tree one = build_int_cst (TREE_TYPE (min), 1);
-	  max = int_const_binop (MINUS_EXPR, min, one);
-	  min = vrp_val_min (TREE_TYPE (min));
-	  t = VR_RANGE;
-        }
-    }
-
-  /* Do not drop [-INF(OVF), +INF(OVF)] to varying.  (OVF) has to be sticky
-     to make sure VRP iteration terminates, otherwise we can get into
-     oscillations.  */
-
-  set_value_range (vr, t, min, max, equiv);
+  *vr = value_range (vr->type (), vrtype, min, max, equiv);
+  vr->canonicalize ();
 }
 
 /* Copy value range FROM into value range TO.  */
@@ -440,7 +534,7 @@  set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
 void
 copy_value_range (value_range *to, const value_range *from)
 {
-  set_value_range (to, from->type, from->min, from->max, from->equiv);
+  to->copy_with_equiv_update (from);
 }
 
 /* Set value range VR to a single value.  This function is only called
@@ -462,7 +556,7 @@  void
 set_value_range_to_nonnull (value_range *vr, tree type)
 {
   tree zero = build_int_cst (type, 0);
-  set_value_range (vr, VR_ANTI_RANGE, zero, zero, vr->equiv);
+  set_value_range (vr, VR_ANTI_RANGE, zero, zero, vr->equiv ());
 }
 
 
@@ -471,7 +565,7 @@  set_value_range_to_nonnull (value_range *vr, tree type)
 void
 set_value_range_to_null (value_range *vr, tree type)
 {
-  set_value_range_to_value (vr, build_int_cst (type, 0), vr->equiv);
+  set_value_range_to_value (vr, build_int_cst (type, 0), vr->equiv ());
 }
 
 /* Return true, if VAL1 and VAL2 are equal values for VRP purposes.  */
@@ -503,9 +597,15 @@  vrp_bitmap_equal_p (const_bitmap b1, const_bitmap b2)
 static inline bool
 range_is_null (const value_range *vr)
 {
-  return vr->type == VR_RANGE
-	 && integer_zerop (vr->min)
-	 && integer_zerop (vr->max);
+  return vr->null_p ();
+}
+
+static inline bool
+range_is_nonnull (const value_range *vr)
+{
+  return (vr->vrtype () == VR_ANTI_RANGE
+	  && vr->min () == vr->max ()
+	  && integer_zerop (vr->min ()));
 }
 
 /* Return true if max and min of VR are INTEGER_CST.  It's not necessary
@@ -514,9 +614,9 @@  range_is_null (const value_range *vr)
 bool
 range_int_cst_p (const value_range *vr)
 {
-  return (vr->type == VR_RANGE
-	  && TREE_CODE (vr->max) == INTEGER_CST
-	  && TREE_CODE (vr->min) == INTEGER_CST);
+  return (vr->vrtype () == VR_RANGE
+	  && TREE_CODE (vr->min ()) == INTEGER_CST
+	  && TREE_CODE (vr->max ()) == INTEGER_CST);
 }
 
 /* Return true if VR is a INTEGER_CST singleton.  */
@@ -525,16 +625,7 @@  bool
 range_int_cst_singleton_p (const value_range *vr)
 {
   return (range_int_cst_p (vr)
-	  && tree_int_cst_equal (vr->min, vr->max));
-}
-
-/* Return true if value range VR involves at least one symbol.  */
-
-bool
-symbolic_range_p (const value_range *vr)
-{
-  return (!is_gimple_min_invariant (vr->min)
-          || !is_gimple_min_invariant (vr->max));
+	  && tree_int_cst_equal (vr->min (), vr->max ()));
 }
 
 /* Return the single symbol (an SSA_NAME) contained in T if any, or NULL_TREE
@@ -849,20 +940,8 @@  value_inside_range (tree val, tree min, tree max)
 bool
 range_includes_zero_p (const value_range *vr)
 {
-  if (vr->type == VR_VARYING)
-    return true;
-
-  /* Ughh, we don't know.  We choose not to optimize.  */
-  if (vr->type == VR_UNDEFINED)
-    return true;
-
-  tree zero = build_int_cst (TREE_TYPE (vr->min), 0);
-  if (vr->type == VR_ANTI_RANGE)
-    {
-      int res = value_inside_range (zero, vr->min, vr->max);
-      return res == 0 || res == -2;
-    }
-  return value_inside_range (zero, vr->min, vr->max) != 0;
+  tree zero = build_int_cst (TREE_TYPE (vr->type ()), 0);
+  return vr->may_contain_p (zero);
 }
 
 /* If *VR has a value rante that is a single constant value return that,
@@ -871,12 +950,7 @@  range_includes_zero_p (const value_range *vr)
 tree
 value_range_constant_singleton (const value_range *vr)
 {
-  if (vr->type == VR_RANGE
-      && vrp_operand_equal_p (vr->min, vr->max)
-      && is_gimple_min_invariant (vr->min))
-    return vr->min;
-
-  return NULL_TREE;
+  return vr->singleton ();
 }
 
 /* Value range wrapper for wide_int_range_set_zero_nonzero_bits.
@@ -899,8 +973,8 @@  vrp_set_zero_nonzero_bits (const tree expr_type,
       return false;
     }
   wide_int_range_set_zero_nonzero_bits (TYPE_SIGN (expr_type),
-					wi::to_wide (vr->min),
-					wi::to_wide (vr->max),
+					wi::to_wide (vr->min ()),
+					wi::to_wide (vr->max ()),
 					*may_be_nonzero, *must_be_nonzero);
   return true;
 }
@@ -914,40 +988,36 @@  static bool
 ranges_from_anti_range (const value_range *ar,
 			value_range *vr0, value_range *vr1)
 {
-  tree type = TREE_TYPE (ar->min);
+  tree type = TREE_TYPE (ar->type ());
 
-  vr0->type = VR_UNDEFINED;
-  vr1->type = VR_UNDEFINED;
+  vr0->set_undefined ();
+  vr1->set_undefined ();
 
   /* As a future improvement, we could handle ~[0, A] as: [-INF, -1] U
      [A+1, +INF].  Not sure if this helps in practice, though.  */
 
-  if (ar->type != VR_ANTI_RANGE
-      || TREE_CODE (ar->min) != INTEGER_CST
-      || TREE_CODE (ar->max) != INTEGER_CST
+  if (ar->vrtype () != VR_ANTI_RANGE
+      || TREE_CODE (ar->min ()) != INTEGER_CST
+      || TREE_CODE (ar->max ()) != INTEGER_CST
       || !vrp_val_min (type)
       || !vrp_val_max (type))
     return false;
 
-  if (!vrp_val_is_min (ar->min))
-    {
-      vr0->type = VR_RANGE;
-      vr0->min = vrp_val_min (type);
-      vr0->max = wide_int_to_tree (type, wi::to_wide (ar->min) - 1);
-    }
-  if (!vrp_val_is_max (ar->max))
-    {
-      vr1->type = VR_RANGE;
-      vr1->min = wide_int_to_tree (type, wi::to_wide (ar->max) + 1);
-      vr1->max = vrp_val_max (type);
-    }
-  if (vr0->type == VR_UNDEFINED)
+  if (!vrp_val_is_min (ar->min ()))
+    *vr0 = value_range (type, VR_RANGE,
+			vrp_val_min (type),
+			wide_int_to_tree (type, wi::to_wide (ar->min ()) - 1));
+  if (!vrp_val_is_max (ar->max ()))
+    *vr1 = value_range (type, VR_RANGE,
+			wide_int_to_tree (type, wi::to_wide (ar->max ()) + 1),
+			vrp_val_max (type));
+  if (vr0->undefined_p ())
     {
       *vr0 = *vr1;
-      vr1->type = VR_UNDEFINED;
+      vr1->set_undefined ();
     }
 
-  return vr0->type != VR_UNDEFINED;
+  return !vr0->undefined_p ();
 }
 
 /* Extract the components of a value range into a pair of wide ints in
@@ -961,13 +1031,11 @@  extract_range_into_wide_ints (const value_range *vr,
 			      signop sign, unsigned prec,
 			      wide_int &wmin, wide_int &wmax)
 {
-  if ((vr->type == VR_RANGE
-       || vr->type == VR_ANTI_RANGE)
-      && TREE_CODE (vr->min) == INTEGER_CST
-      && TREE_CODE (vr->max) == INTEGER_CST)
+  gcc_assert (vr->vrtype () != VR_ANTI_RANGE);
+  if (range_int_cst_p (vr))
     {
-      wmin = wi::to_wide (vr->min);
-      wmax = wi::to_wide (vr->max);
+      wmin = wi::to_wide (vr->min ());
+      wmax = wi::to_wide (vr->max ());
     }
   else
     {
@@ -994,14 +1062,15 @@  extract_range_from_multiplicative_op (value_range *vr,
 	      || code == ROUND_DIV_EXPR
 	      || code == RSHIFT_EXPR
 	      || code == LSHIFT_EXPR);
-  gcc_assert (vr0->type == VR_RANGE && vr0->type == vr1->type);
+  gcc_assert (vr0->vrtype () == VR_RANGE
+	      && vr0->vrtype () == vr1->vrtype ());
 
-  tree type = TREE_TYPE (vr0->min);
+  tree type = vr0->type ();
   wide_int res_lb, res_ub;
-  wide_int vr0_lb = wi::to_wide (vr0->min);
-  wide_int vr0_ub = wi::to_wide (vr0->max);
-  wide_int vr1_lb = wi::to_wide (vr1->min);
-  wide_int vr1_ub = wi::to_wide (vr1->max);
+  wide_int vr0_lb = wi::to_wide (vr0->min ());
+  wide_int vr0_ub = wi::to_wide (vr0->max ());
+  wide_int vr1_lb = wi::to_wide (vr1->min ());
+  wide_int vr1_ub = wi::to_wide (vr1->max ());
   bool overflow_undefined = TYPE_OVERFLOW_UNDEFINED (type);
   bool overflow_wraps = TYPE_OVERFLOW_WRAPS (type);
   unsigned prec = TYPE_PRECISION (type);
@@ -1114,8 +1183,6 @@  set_value_range_with_overflow (value_range &vr,
 {
   const signop sgn = TYPE_SIGN (type);
   const unsigned int prec = TYPE_PRECISION (type);
-  vr.type = VR_RANGE;
-  vr.equiv = NULL;
   if (TYPE_OVERFLOW_WRAPS (type))
     {
       /* If overflow wraps, truncate the values and adjust the
@@ -1126,8 +1193,10 @@  set_value_range_with_overflow (value_range &vr,
 	{
 	  /* No overflow or both overflow or underflow.  The
 	     range kind stays VR_RANGE.  */
-	  vr.min = wide_int_to_tree (type, tmin);
-	  vr.max = wide_int_to_tree (type, tmax);
+	  vr = value_range (type, VR_RANGE,
+			    wide_int_to_tree (type, tmin),
+			    wide_int_to_tree (type, tmax));
+	  return;
 	}
       else if ((min_ovf == wi::OVF_UNDERFLOW && max_ovf == wi::OVF_NONE)
 	       || (max_ovf == wi::OVF_OVERFLOW && min_ovf == wi::OVF_NONE))
@@ -1136,7 +1205,6 @@  set_value_range_with_overflow (value_range &vr,
 	     changes to VR_ANTI_RANGE.  */
 	  bool covers = false;
 	  wide_int tem = tmin;
-	  vr.type = VR_ANTI_RANGE;
 	  tmin = tmax + 1;
 	  if (wi::cmp (tmin, tmax, sgn) < 0)
 	    covers = true;
@@ -1151,8 +1219,10 @@  set_value_range_with_overflow (value_range &vr,
 	      set_value_range_to_varying (&vr);
 	      return;
 	    }
-	  vr.min = wide_int_to_tree (type, tmin);
-	  vr.max = wide_int_to_tree (type, tmax);
+	  vr = value_range (type, VR_ANTI_RANGE,
+			    wide_int_to_tree (type, tmin),
+			    wide_int_to_tree (type, tmax));
+	  return;
 	}
       else
 	{
@@ -1167,19 +1237,21 @@  set_value_range_with_overflow (value_range &vr,
 	 value.  */
       wide_int type_min = wi::min_value (prec, sgn);
       wide_int type_max = wi::max_value (prec, sgn);
+      tree min, max;
       if (min_ovf == wi::OVF_UNDERFLOW)
-	vr.min = wide_int_to_tree (type, type_min);
+	min = wide_int_to_tree (type, type_min);
       else if (min_ovf == wi::OVF_OVERFLOW)
-	vr.min = wide_int_to_tree (type, type_max);
+	min = wide_int_to_tree (type, type_max);
       else
-	vr.min = wide_int_to_tree (type, wmin);
+	min = wide_int_to_tree (type, wmin);
 
       if (max_ovf == wi::OVF_UNDERFLOW)
-	vr.max = wide_int_to_tree (type, type_min);
+	max = wide_int_to_tree (type, type_min);
       else if (max_ovf == wi::OVF_OVERFLOW)
-	vr.max = wide_int_to_tree (type, type_max);
+	max = wide_int_to_tree (type, type_max);
       else
-	vr.max = wide_int_to_tree (type, wmax);
+	max = wide_int_to_tree (type, wmax);
+      vr = value_range (type, VR_RANGE, min, max);
     }
 }
 
@@ -1196,7 +1268,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
   signop sign = TYPE_SIGN (expr_type);
   unsigned int prec = TYPE_PRECISION (expr_type);
   value_range vr0 = *vr0_, vr1 = *vr1_;
-  value_range vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
+  value_range vrtem0 (expr_type), vrtem1 (expr_type);
   enum value_range_type type;
   tree min = NULL_TREE, max = NULL_TREE;
   int cmp;
@@ -1233,7 +1305,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
     }
 
   /* If both ranges are UNDEFINED, so is the result.  */
-  if (vr0.type == VR_UNDEFINED && vr1.type == VR_UNDEFINED)
+  if (vr0.undefined_p () && vr1.undefined_p ())
     {
       set_value_range_to_undefined (vr);
       return;
@@ -1242,19 +1314,16 @@  extract_range_from_binary_expr_1 (value_range *vr,
      code.  At some point we may want to special-case operations that
      have UNDEFINED result for all or some value-ranges of the not UNDEFINED
      operand.  */
-  else if (vr0.type == VR_UNDEFINED)
+  else if (vr0.undefined_p ())
     set_value_range_to_varying (&vr0);
-  else if (vr1.type == VR_UNDEFINED)
+  else if (vr1.undefined_p ())
     set_value_range_to_varying (&vr1);
 
   /* We get imprecise results from ranges_from_anti_range when
      code is EXACT_DIV_EXPR.  We could mask out bits in the resulting
      range, but then we also need to hack up vrp_meet.  It's just
      easier to special case when vr0 is ~[0,0] for EXACT_DIV_EXPR.  */
-  if (code == EXACT_DIV_EXPR
-      && vr0.type == VR_ANTI_RANGE
-      && vr0.min == vr0.max
-      && integer_zerop (vr0.min))
+  if (code == EXACT_DIV_EXPR && range_is_nonnull (&vr0))
     {
       set_value_range_to_nonnull (vr, expr_type);
       return;
@@ -1262,27 +1331,26 @@  extract_range_from_binary_expr_1 (value_range *vr,
 
   /* Now canonicalize anti-ranges to ranges when they are not symbolic
      and express ~[] op X as ([]' op X) U ([]'' op X).  */
-  if (vr0.type == VR_ANTI_RANGE
+  if (vr0.vrtype () == VR_ANTI_RANGE
       && ranges_from_anti_range (&vr0, &vrtem0, &vrtem1))
     {
       extract_range_from_binary_expr_1 (vr, code, expr_type, &vrtem0, vr1_);
-      if (vrtem1.type != VR_UNDEFINED)
+      if (!vrtem1.undefined_p ())
 	{
-	  value_range vrres = VR_INITIALIZER;
-	  extract_range_from_binary_expr_1 (&vrres, code, expr_type,
-					    &vrtem1, vr1_);
+	  value_range vrres (expr_type);
+	  extract_range_from_binary_expr_1 (&vrres, code, expr_type,					    &vrtem1, vr1_);
 	  vrp_meet (vr, &vrres);
 	}
       return;
     }
   /* Likewise for X op ~[].  */
-  if (vr1.type == VR_ANTI_RANGE
+  if (vr1.vrtype () == VR_ANTI_RANGE
       && ranges_from_anti_range (&vr1, &vrtem0, &vrtem1))
     {
       extract_range_from_binary_expr_1 (vr, code, expr_type, vr0_, &vrtem0);
-      if (vrtem1.type != VR_UNDEFINED)
+      if (!vrtem1.undefined_p ())
 	{
-	  value_range vrres = VR_INITIALIZER;
+	  value_range vrres (expr_type);
 	  extract_range_from_binary_expr_1 (&vrres, code, expr_type,
 					    vr0_, &vrtem1);
 	  vrp_meet (vr, &vrres);
@@ -1291,7 +1359,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
     }
 
   /* The type of the resulting value range defaults to VR0.TYPE.  */
-  type = vr0.type;
+  type = vr0.vrtype ();
 
   /* Refuse to operate on VARYING ranges, ranges of different kinds
      and symbolic ranges.  As an exception, we allow BIT_{AND,IOR}
@@ -1314,11 +1382,11 @@  extract_range_from_binary_expr_1 (value_range *vr,
       && code != MINUS_EXPR
       && code != RSHIFT_EXPR
       && code != POINTER_PLUS_EXPR
-      && (vr0.type == VR_VARYING
-	  || vr1.type == VR_VARYING
-	  || vr0.type != vr1.type
-	  || symbolic_range_p (&vr0)
-	  || symbolic_range_p (&vr1)))
+      && (vr0.varying_p ()
+	  || vr1.varying_p ()
+	  || vr0.vrtype () != vr1.vrtype ()
+	  || vr0.symbolic_p ()
+	  || vr1.symbolic_p ()))
     {
       set_value_range_to_varying (vr);
       return;
@@ -1376,24 +1444,20 @@  extract_range_from_binary_expr_1 (value_range *vr,
       /* This will normalize things such that calculating
 	 [0,0] - VR_VARYING is not dropped to varying, but is
 	 calculated as [MIN+1, MAX].  */
-      if (vr0.type == VR_VARYING)
-	{
-	  vr0.type = VR_RANGE;
-	  vr0.min = vrp_val_min (expr_type);
-	  vr0.max = vrp_val_max (expr_type);
-	}
-      if (vr1.type == VR_VARYING)
-	{
-	  vr1.type = VR_RANGE;
-	  vr1.min = vrp_val_min (expr_type);
-	  vr1.max = vrp_val_max (expr_type);
-	}
+      if (vr0.varying_p ())
+	vr0 = value_range (vr0.type (), VR_RANGE,
+			   vrp_val_min (expr_type),
+			   vrp_val_max (expr_type), vr0.equiv ());
+      if (vr1.varying_p ())
+	vr1 = value_range (vr1.type (), VR_RANGE,
+			   vrp_val_min (expr_type),
+			   vrp_val_max (expr_type), vr0.equiv ());
 
       const bool minus_p = (code == MINUS_EXPR);
-      tree min_op0 = vr0.min;
-      tree min_op1 = minus_p ? vr1.max : vr1.min;
-      tree max_op0 = vr0.max;
-      tree max_op1 = minus_p ? vr1.min : vr1.max;
+      tree min_op0 = vr0.min ();
+      tree min_op1 = minus_p ? vr1.max () : vr1.min ();
+      tree max_op0 = vr0.max ();
+      tree max_op1 = minus_p ? vr1.min () : vr1.max ();
       tree sym_min_op0 = NULL_TREE;
       tree sym_min_op1 = NULL_TREE;
       tree sym_max_op0 = NULL_TREE;
@@ -1406,7 +1470,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
 	 single-symbolic ranges, try to compute the precise resulting range,
 	 but only if we know that this resulting range will also be constant
 	 or single-symbolic.  */
-      if (vr0.type == VR_RANGE && vr1.type == VR_RANGE
+      if (vr0.vrtype () == VR_RANGE && vr1.vrtype () == VR_RANGE
 	  && (TREE_CODE (min_op0) == INTEGER_CST
 	      || (sym_min_op0
 		  = get_single_symbol (min_op0, &neg_min_op0, &min_op0)))
@@ -1446,21 +1510,19 @@  extract_range_from_binary_expr_1 (value_range *vr,
 	  /* Adjust the range for possible overflow.  */
 	  set_value_range_with_overflow (*vr, expr_type,
 					 wmin, wmax, min_ovf, max_ovf);
-	  if (vr->type == VR_VARYING)
+	  if (vr->varying_p ())
 	    return;
 
 	  /* Build the symbolic bounds if needed.  */
-	  adjust_symbolic_bound (vr->min, code, expr_type,
+	  min = vr->min ();
+	  max = vr->max ();
+	  adjust_symbolic_bound (min, code, expr_type,
 				 sym_min_op0, sym_min_op1,
 				 neg_min_op0, neg_min_op1);
-	  adjust_symbolic_bound (vr->max, code, expr_type,
+	  adjust_symbolic_bound (max, code, expr_type,
 				 sym_max_op0, sym_max_op1,
 				 neg_max_op0, neg_max_op1);
-	  /* ?? It would probably be cleaner to eliminate min/max/type
-	     entirely and hold these values in VR directly.  */
-	  min = vr->min;
-	  max = vr->max;
-	  type = vr->type;
+	  type = vr->vrtype ();
 	}
       else
 	{
@@ -1513,19 +1575,21 @@  extract_range_from_binary_expr_1 (value_range *vr,
     {
       if (range_int_cst_p (&vr1)
 	  && !wide_int_range_shift_undefined_p (prec,
-						wi::to_wide (vr1.min),
-						wi::to_wide (vr1.max)))
+						wi::to_wide (vr1.min ()),
+						wi::to_wide (vr1.max ())))
 	{
 	  if (code == RSHIFT_EXPR)
 	    {
 	      /* Even if vr0 is VARYING or otherwise not usable, we can derive
 		 useful ranges just from the shift count.  E.g.
 		 x >> 63 for signed 64-bit x is always [-1, 0].  */
-	      if (vr0.type != VR_RANGE || symbolic_range_p (&vr0))
+	      if (vr0.vrtype () != VR_RANGE || vr0.symbolic_p ())
 		{
-		  vr0.type = type = VR_RANGE;
-		  vr0.min = vrp_val_min (expr_type);
-		  vr0.max = vrp_val_max (expr_type);
+		  type = VR_RANGE;
+		  vr0 = value_range (vr0.type (), type,
+				     vrp_val_min (expr_type),
+				     vrp_val_max (expr_type),
+				     vr0.equiv ());
 		}
 	      extract_range_from_multiplicative_op (vr, code, &vr0, &vr1);
 	      return;
@@ -1535,10 +1599,10 @@  extract_range_from_binary_expr_1 (value_range *vr,
 	    {
 	      wide_int res_lb, res_ub;
 	      if (wide_int_range_lshift (res_lb, res_ub, sign, prec,
-					 wi::to_wide (vr0.min),
-					 wi::to_wide (vr0.max),
-					 wi::to_wide (vr1.min),
-					 wi::to_wide (vr1.max),
+					 wi::to_wide (vr0.min ()),
+					 wi::to_wide (vr0.max ()),
+					 wi::to_wide (vr1.min ()),
+					 wi::to_wide (vr1.max ()),
 					 TYPE_OVERFLOW_UNDEFINED (expr_type),
 					 TYPE_OVERFLOW_WRAPS (expr_type)))
 		{
@@ -1596,7 +1660,7 @@  extract_range_from_binary_expr_1 (value_range *vr,
 		       wide_int_to_tree (expr_type, wmax), NULL);
       if (extra_range_p)
 	{
-	  value_range extra_range = VR_INITIALIZER;
+	  value_range extra_range (expr_type);
 	  set_value_range (&extra_range, VR_RANGE,
 			   wide_int_to_tree (expr_type, extra_min),
 			   wide_int_to_tree (expr_type, extra_max), NULL);
@@ -1733,7 +1797,9 @@  extract_range_from_unary_expr (value_range *vr,
 {
   signop sign = TYPE_SIGN (type);
   unsigned int prec = TYPE_PRECISION (type);
-  value_range vr0 = *vr0_, vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
+  value_range vr0 = *vr0_;
+  value_range vrtem0 (vr0.type ());
+  value_range vrtem1 (vr0.type ());
 
   /* VRP only operates on integral and pointer types.  */
   if (!(INTEGRAL_TYPE_P (op0_type)
@@ -1746,7 +1812,7 @@  extract_range_from_unary_expr (value_range *vr,
     }
 
   /* If VR0 is UNDEFINED, so is the result.  */
-  if (vr0.type == VR_UNDEFINED)
+  if (vr0.undefined_p ())
     {
       set_value_range_to_undefined (vr);
       return;
@@ -1763,7 +1829,7 @@  extract_range_from_unary_expr (value_range *vr,
     {
       /* -X is simply 0 - X, so re-use existing code that also handles
          anti-ranges fine.  */
-      value_range zero = VR_INITIALIZER;
+      value_range zero (type);
       set_value_range_to_value (&zero, build_int_cst (type, 0), NULL);
       extract_range_from_binary_expr_1 (vr, MINUS_EXPR, type, &zero, &vr0);
       return;
@@ -1772,7 +1838,7 @@  extract_range_from_unary_expr (value_range *vr,
     {
       /* ~X is simply -1 - X, so re-use existing code that also handles
          anti-ranges fine.  */
-      value_range minusone = VR_INITIALIZER;
+      value_range minusone (type);
       set_value_range_to_value (&minusone, build_int_cst (type, -1), NULL);
       extract_range_from_binary_expr_1 (vr, MINUS_EXPR,
 					type, &minusone, &vr0);
@@ -1781,13 +1847,13 @@  extract_range_from_unary_expr (value_range *vr,
 
   /* Now canonicalize anti-ranges to ranges when they are not symbolic
      and express op ~[]  as (op []') U (op []'').  */
-  if (vr0.type == VR_ANTI_RANGE
+  if (vr0.vrtype () == VR_ANTI_RANGE
       && ranges_from_anti_range (&vr0, &vrtem0, &vrtem1))
     {
       extract_range_from_unary_expr (vr, code, type, &vrtem0, op0_type);
-      if (vrtem1.type != VR_UNDEFINED)
+      if (!vrtem1.undefined_p ())
 	{
-	  value_range vrres = VR_INITIALIZER;
+	  value_range vrres (type);
 	  extract_range_from_unary_expr (&vrres, code, type,
 					 &vrtem1, op0_type);
 	  vrp_meet (vr, &vrres);
@@ -1822,8 +1888,8 @@  extract_range_from_unary_expr (value_range *vr,
 	 pointer anti-ranges.  Any remaining anti-ranges at this point
 	 will be integer conversions from SSA names that will be
 	 normalized into VARYING.  For instance: ~[x_55, x_55].  */
-      gcc_assert (vr0.type != VR_ANTI_RANGE
-		  || TREE_CODE (vr0.min) != INTEGER_CST);
+      gcc_assert (vr0.vrtype () != VR_ANTI_RANGE
+		  || TREE_CODE (vr0.min ()) != INTEGER_CST);
 
       /* NOTES: Previously we were returning VARYING for all symbolics, but
 	 we can do better by treating them as [-MIN, +MAX].  For
@@ -1888,39 +1954,39 @@  dump_value_range (FILE *file, const value_range *vr)
 {
   if (vr == NULL)
     fprintf (file, "[]");
-  else if (vr->type == VR_UNDEFINED)
+  else if (vr->undefined_p ())
     fprintf (file, "UNDEFINED");
-  else if (vr->type == VR_RANGE || vr->type == VR_ANTI_RANGE)
+  else if (vr->vrtype () == VR_RANGE || vr->vrtype () == VR_ANTI_RANGE)
     {
-      tree type = TREE_TYPE (vr->min);
+      tree type = TREE_TYPE (vr->min ());
 
-      fprintf (file, "%s[", (vr->type == VR_ANTI_RANGE) ? "~" : "");
+      fprintf (file, "%s[", (vr->vrtype () == VR_ANTI_RANGE) ? "~" : "");
 
       if (INTEGRAL_TYPE_P (type)
 	  && !TYPE_UNSIGNED (type)
-	  && vrp_val_is_min (vr->min))
+	  && vrp_val_is_min (vr->min ()))
 	fprintf (file, "-INF");
       else
-	print_generic_expr (file, vr->min);
+	print_generic_expr (file, vr->min ());
 
       fprintf (file, ", ");
 
       if (INTEGRAL_TYPE_P (type)
-	  && vrp_val_is_max (vr->max))
+	  && vrp_val_is_max (vr->max ()))
 	fprintf (file, "+INF");
       else
-	print_generic_expr (file, vr->max);
+	print_generic_expr (file, vr->max ());
 
       fprintf (file, "]");
 
-      if (vr->equiv)
+      if (vr->equiv ())
 	{
 	  bitmap_iterator bi;
 	  unsigned i, c = 0;
 
 	  fprintf (file, "  EQUIVALENCES: { ");
 
-	  EXECUTE_IF_SET_IN_BITMAP (vr->equiv, 0, i, bi)
+	  EXECUTE_IF_SET_IN_BITMAP (vr->equiv (), 0, i, bi)
 	    {
 	      print_generic_expr (file, ssa_name (i));
 	      fprintf (file, " ");
@@ -1930,7 +1996,7 @@  dump_value_range (FILE *file, const value_range *vr)
 	  fprintf (file, "} (%u elements)", c);
 	}
     }
-  else if (vr->type == VR_VARYING)
+  else if (vr->varying_p ())
     fprintf (file, "VARYING");
   else
     fprintf (file, "INVALID RANGE");
@@ -4193,14 +4259,14 @@  vrp_prop::check_array_ref (location_t location, tree ref,
   if (TREE_CODE (low_sub) == SSA_NAME)
     {
       vr = get_value_range (low_sub);
-      if (vr->type == VR_RANGE || vr->type == VR_ANTI_RANGE)
+      if (!vr->undefined_p () && !vr->varying_p ())
         {
-          low_sub = vr->type == VR_RANGE ? vr->max : vr->min;
-          up_sub = vr->type == VR_RANGE ? vr->min : vr->max;
+          low_sub = vr->vrtype () == VR_RANGE ? vr->max () : vr->min ();
+          up_sub = vr->vrtype () == VR_RANGE ? vr->min () : vr->max ();
         }
     }
 
-  if (vr && vr->type == VR_ANTI_RANGE)
+  if (vr && vr->vrtype () == VR_ANTI_RANGE)
     {
       if (up_bound
 	  && TREE_CODE (up_sub) == INTEGER_CST
@@ -4328,21 +4394,24 @@  vrp_prop::check_mem_ref (location_t location, tree ref,
 	break;
 
       vr = get_value_range (varoff);
-      if (!vr || vr->type == VR_UNDEFINED || !vr->min || !vr->max)
+      // FIXME: If this never triggers, both tests below simplify to:
+      // if (!vr || !vr->numeric_p ())
+      if (!vr->min () || !vr->max ())
+	gcc_assert (vr->varying_p ());
+      if (!vr || vr->undefined_p () || !vr->min () || !vr->max ())
 	break;
 
-      if (TREE_CODE (vr->min) != INTEGER_CST
-          || TREE_CODE (vr->max) != INTEGER_CST)
+      if (!vr->numeric_p ())
         break;
 
-      if (vr->type == VR_RANGE)
+      if (vr->vrtype () == VR_RANGE)
 	{
-	  if (tree_int_cst_lt (vr->min, vr->max))
+	  if (tree_int_cst_lt (vr->min (), vr->max ()))
 	    {
 	      offset_int min
-		= wi::to_offset (fold_convert (ptrdiff_type_node, vr->min));
+		= wi::to_offset (fold_convert (ptrdiff_type_node, vr->min ()));
 	      offset_int max
-		= wi::to_offset (fold_convert (ptrdiff_type_node, vr->max));
+		= wi::to_offset (fold_convert (ptrdiff_type_node, vr->max ()));
 	      if (min < max)
 		{
 		  offrange[0] += min;
@@ -5114,8 +5183,8 @@  find_case_label_range (gswitch *stmt, tree min, tree max, size_t *min_idx,
 enum ssa_prop_result
 vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
 {
-  value_range vr = VR_INITIALIZER;
   tree lhs = gimple_get_lhs (stmt);
+  value_range vr (TREE_TYPE (lhs));
   extract_range_from_stmt (stmt, taken_edge_p, output_p, &vr);
 
   if (*output_p)
@@ -5131,7 +5200,7 @@  vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
 	      fprintf (dump_file, "\n");
 	    }
 
-	  if (vr.type == VR_VARYING)
+	  if (vr.varying_p ())
 	    return SSA_PROP_VARYING;
 
 	  return SSA_PROP_INTERESTING;
@@ -5184,17 +5253,14 @@  vrp_prop::visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
 		   SSA_PROP_NOT_INTERESTING.  If there are no
 		   {REAL,IMAG}PART_EXPR uses at all,
 		   return SSA_PROP_VARYING.  */
-		value_range new_vr = VR_INITIALIZER;
+		value_range new_vr (TREE_TYPE (lhs));
 		extract_range_basic (&new_vr, use_stmt);
 		const value_range *old_vr = get_value_range (use_lhs);
-		if (old_vr->type != new_vr.type
-		    || !vrp_operand_equal_p (old_vr->min, new_vr.min)
-		    || !vrp_operand_equal_p (old_vr->max, new_vr.max)
-		    || !vrp_bitmap_equal_p (old_vr->equiv, new_vr.equiv))
+		if (*old_vr != new_vr)
 		  res = SSA_PROP_INTERESTING;
 		else
 		  res = SSA_PROP_NOT_INTERESTING;
-		BITMAP_FREE (new_vr.equiv);
+		new_vr.equiv_free ();
 		if (res == SSA_PROP_INTERESTING)
 		  {
 		    *output_p = lhs;
@@ -5805,8 +5871,6 @@  intersect_ranges (enum value_range_type *vr0type,
       *vr0min = vr1min;
       *vr0max = vr1max;
     }
-
-  return;
 }
 
 
@@ -5816,12 +5880,10 @@  intersect_ranges (enum value_range_type *vr0type,
 static void
 vrp_intersect_ranges_1 (value_range *vr0, const value_range *vr1)
 {
-  value_range saved;
-
   /* If either range is VR_VARYING the other one wins.  */
-  if (vr1->type == VR_VARYING)
+  if (vr1->varying_p ())
     return;
-  if (vr0->type == VR_VARYING)
+  if (vr0->varying_p ())
     {
       copy_value_range (vr0, vr1);
       return;
@@ -5829,9 +5891,9 @@  vrp_intersect_ranges_1 (value_range *vr0, const value_range *vr1)
 
   /* When either range is VR_UNDEFINED the resulting range is
      VR_UNDEFINED, too.  */
-  if (vr0->type == VR_UNDEFINED)
+  if (vr0->undefined_p ())
     return;
-  if (vr1->type == VR_UNDEFINED)
+  if (vr1->undefined_p ())
     {
       set_value_range_to_undefined (vr0);
       return;
@@ -5839,34 +5901,38 @@  vrp_intersect_ranges_1 (value_range *vr0, const value_range *vr1)
 
   /* Save the original vr0 so we can return it as conservative intersection
      result when our worker turns things to varying.  */
-  saved = *vr0;
-  intersect_ranges (&vr0->type, &vr0->min, &vr0->max,
-		    vr1->type, vr1->min, vr1->max);
+  value_range saved (*vr0);
+
+  value_range_type vr0type = vr0->vrtype ();
+  tree vr0min = vr0->min ();
+  tree vr0max = vr0->max ();
+  intersect_ranges (&vr0type, &vr0min, &vr0max,
+		    vr1->vrtype (), vr1->min (), vr1->max ());
+  *vr0 = value_range (vr0->type (), vr0type, vr0min, vr0max, vr0->equiv ());
   /* Make sure to canonicalize the result though as the inversion of a
      VR_RANGE can still be a VR_RANGE.  */
-  set_and_canonicalize_value_range (vr0, vr0->type,
-				    vr0->min, vr0->max, vr0->equiv);
+  vr0->canonicalize ();
   /* If that failed, use the saved original VR0.  */
-  if (vr0->type == VR_VARYING)
+  if (vr0->varying_p ())
     {
       *vr0 = saved;
       return;
     }
   /* If the result is VR_UNDEFINED there is no need to mess with
      the equivalencies.  */
-  if (vr0->type == VR_UNDEFINED)
+  if (vr0->undefined_p ())
     return;
 
   /* The resulting set of equivalences for range intersection is the union of
      the two sets.  */
-  if (vr0->equiv && vr1->equiv && vr0->equiv != vr1->equiv)
-    bitmap_ior_into (vr0->equiv, vr1->equiv);
-  else if (vr1->equiv && !vr0->equiv)
+  if (vr0->equiv () && vr1->equiv () && vr0->equiv () != vr1->equiv ())
+    vr0->equiv_ior (vr1);
+  else if (vr1->equiv () && !vr0->equiv ())
     {
       /* All equivalence bitmaps are allocated from the same obstack.  So
 	 we can use the obstack associated with VR to allocate vr0->equiv.  */
-      vr0->equiv = BITMAP_ALLOC (vr1->equiv->obstack);
-      bitmap_copy (vr0->equiv, vr1->equiv);
+      vr0->set_equiv (BITMAP_ALLOC (vr1->equiv ()->obstack));
+      vr0->equiv_copy (vr1);
     }
 }
 
@@ -5897,36 +5963,39 @@  vrp_intersect_ranges (value_range *vr0, const value_range *vr1)
 static void
 vrp_meet_1 (value_range *vr0, const value_range *vr1)
 {
-  value_range saved;
-
-  if (vr0->type == VR_UNDEFINED)
+  if (vr0->undefined_p ())
     {
-      set_value_range (vr0, vr1->type, vr1->min, vr1->max, vr1->equiv);
+      set_value_range (vr0, vr1->vrtype (), vr1->min (), vr1->max (),
+		       vr1->equiv ());
       return;
     }
 
-  if (vr1->type == VR_UNDEFINED)
+  if (vr1->undefined_p ())
     {
       /* VR0 already has the resulting range.  */
       return;
     }
 
-  if (vr0->type == VR_VARYING)
+  if (vr0->varying_p ())
     {
       /* Nothing to do.  VR0 already has the resulting range.  */
       return;
     }
 
-  if (vr1->type == VR_VARYING)
+  if (vr1->varying_p ())
     {
       set_value_range_to_varying (vr0);
       return;
     }
 
-  saved = *vr0;
-  union_ranges (&vr0->type, &vr0->min, &vr0->max,
-		vr1->type, vr1->min, vr1->max);
-  if (vr0->type == VR_VARYING)
+  value_range saved (*vr0);
+  value_range_type vr0type = vr0->vrtype ();
+  tree vr0min = vr0->min ();
+  tree vr0max = vr0->max ();
+  union_ranges (&vr0type, &vr0min, &vr0max,
+		vr1->vrtype (), vr1->min (), vr1->max ());
+  *vr0 = value_range (vr0->type (), vr0type, vr0min, vr0max, vr0->equiv ());
+  if (vr0->varying_p ())
     {
       /* Failed to find an efficient meet.  Before giving up and setting
 	 the result to VARYING, see if we can at least derive a useful
@@ -5934,29 +6003,27 @@  vrp_meet_1 (value_range *vr0, const value_range *vr1)
       if (range_includes_zero_p (&saved) == 0
 	  && range_includes_zero_p (vr1) == 0)
 	{
-	  set_value_range_to_nonnull (vr0, TREE_TYPE (saved.min));
+	  set_value_range_to_nonnull (vr0, saved.type ());
 
 	  /* Since this meet operation did not result from the meeting of
 	     two equivalent names, VR0 cannot have any equivalences.  */
-	  if (vr0->equiv)
-	    bitmap_clear (vr0->equiv);
+	  vr0->equiv_clear ();
 	  return;
 	}
 
       set_value_range_to_varying (vr0);
       return;
     }
-  set_and_canonicalize_value_range (vr0, vr0->type, vr0->min, vr0->max,
-				    vr0->equiv);
-  if (vr0->type == VR_VARYING)
+  vr0->canonicalize ();
+  if (vr0->varying_p ())
     return;
 
   /* The resulting set of equivalences is always the intersection of
      the two sets.  */
-  if (vr0->equiv && vr1->equiv && vr0->equiv != vr1->equiv)
-    bitmap_and_into (vr0->equiv, vr1->equiv);
-  else if (vr0->equiv && !vr1->equiv)
-    bitmap_clear (vr0->equiv);
+  if (vr0->equiv () != vr1->equiv ())
+    vr0->equiv_and (vr1);
+  else if (!vr1->equiv ())
+    vr0->equiv_clear ();
 }
 
 void
@@ -5988,7 +6055,7 @@  enum ssa_prop_result
 vrp_prop::visit_phi (gphi *phi)
 {
   tree lhs = PHI_RESULT (phi);
-  value_range vr_result = VR_INITIALIZER;
+  value_range vr_result (TREE_TYPE (lhs));
   extract_range_from_phi_node (phi, &vr_result);
   if (update_value_range (lhs, &vr_result))
     {
@@ -6001,7 +6068,7 @@  vrp_prop::visit_phi (gphi *phi)
 	  fprintf (dump_file, "\n");
 	}
 
-      if (vr_result.type == VR_VARYING)
+      if (vr_result.varying_p ())
 	return SSA_PROP_VARYING;
 
       return SSA_PROP_INTERESTING;
@@ -6185,16 +6252,17 @@  simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
       op = lhs_of_dominating_assert (op, bb, stmt);
 
       const value_range *vr = vr_values->get_value_range (op);
-      if ((vr->type != VR_RANGE && vr->type != VR_ANTI_RANGE)
-	  || symbolic_range_p (vr))
+      if (vr->undefined_p ()
+	  || vr->varying_p ()
+	  || vr->symbolic_p ())
 	return NULL_TREE;
 
-      if (vr->type == VR_RANGE)
+      if (vr->vrtype () == VR_RANGE)
 	{
 	  size_t i, j;
 	  /* Get the range of labels that contain a part of the operand's
 	     value range.  */
-	  find_case_label_range (switch_stmt, vr->min, vr->max, &i, &j);
+	  find_case_label_range (switch_stmt, vr->min (), vr->max (), &i, &j);
 
 	  /* Is there only one such label?  */
 	  if (i == j)
@@ -6204,10 +6272,13 @@  simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
 	      /* The i'th label will be taken only if the value range of the
 		 operand is entirely within the bounds of this label.  */
 	      if (CASE_HIGH (label) != NULL_TREE
-		  ? (tree_int_cst_compare (CASE_LOW (label), vr->min) <= 0
-		     && tree_int_cst_compare (CASE_HIGH (label), vr->max) >= 0)
-		  : (tree_int_cst_equal (CASE_LOW (label), vr->min)
-		     && tree_int_cst_equal (vr->min, vr->max)))
+		  // FIXME: Rewrite in terms of an API call
+		  // vr->contains_p() or some such.
+		  ? (tree_int_cst_compare (CASE_LOW (label), vr->min ()) <= 0
+		     && tree_int_cst_compare (CASE_HIGH (label),
+					      vr->max ()) >= 0)
+		  : (tree_int_cst_equal (CASE_LOW (label), vr->min ())
+		     && tree_int_cst_equal (vr->min (), vr->max ())))
 		return label;
 	    }
 
@@ -6217,7 +6288,7 @@  simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
 	    return gimple_switch_label (switch_stmt, 0);
 	}
 
-      if (vr->type == VR_ANTI_RANGE)
+      if (vr->vrtype () == VR_ANTI_RANGE)
 	{
 	  unsigned n = gimple_switch_num_labels (switch_stmt);
 	  tree min_label = gimple_switch_label (switch_stmt, 1);
@@ -6226,10 +6297,14 @@  simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
 	  /* The default label will be taken only if the anti-range of the
 	     operand is entirely outside the bounds of all the (non-default)
 	     case labels.  */
-	  if (tree_int_cst_compare (vr->min, CASE_LOW (min_label)) <= 0
+	  // FIXME: Rewrite in terms of an API call vr->contains_p()
+	  // or some such.
+	  if (tree_int_cst_compare (vr->min (), CASE_LOW (min_label)) <= 0
 	      && (CASE_HIGH (max_label) != NULL_TREE
-		  ? tree_int_cst_compare (vr->max, CASE_HIGH (max_label)) >= 0
-		  : tree_int_cst_compare (vr->max, CASE_LOW (max_label)) >= 0))
+		  ? tree_int_cst_compare (vr->max (),
+					  CASE_HIGH (max_label)) >= 0
+		  : tree_int_cst_compare (vr->max (),
+					  CASE_LOW (max_label)) >= 0))
 	  return gimple_switch_label (switch_stmt, 0);
 	}
 
@@ -6246,11 +6321,12 @@  simplify_stmt_for_jump_threading (gimple *stmt, gimple *within_stmt,
 	{
 	  edge dummy_e;
 	  tree dummy_tree;
-	  value_range new_vr = VR_INITIALIZER;
+	  value_range new_vr (TREE_TYPE (lhs));
 	  vr_values->extract_range_from_stmt (stmt, &dummy_e,
 					      &dummy_tree, &new_vr);
-	  if (range_int_cst_singleton_p (&new_vr))
-	    return new_vr.min;
+	  tree singleton = new_vr.singleton ();
+	  if (singleton)
+	    return singleton;
 	}
     }
 
@@ -6422,20 +6498,16 @@  vrp_prop::vrp_finalize (bool warn_array_bounds_p)
 	continue;
 
       const value_range *vr = get_value_range (name);
-      if (!name
-	  || (vr->type == VR_VARYING)
-	  || (vr->type == VR_UNDEFINED)
-	  || (TREE_CODE (vr->min) != INTEGER_CST)
-	  || (TREE_CODE (vr->max) != INTEGER_CST))
+      if (!name || vr->numeric_p ())
 	continue;
 
       if (POINTER_TYPE_P (TREE_TYPE (name))
 	  && range_includes_zero_p (vr) == 0)
 	set_ptr_nonnull (name);
       else if (!POINTER_TYPE_P (TREE_TYPE (name)))
-	set_range_info (name, vr->type,
-			wi::to_wide (vr->min),
-			wi::to_wide (vr->max));
+	set_range_info (name, vr->vrtype (),
+			wi::to_wide (vr->min ()),
+			wi::to_wide (vr->max ()));
     }
 
   /* If we're checking array refs, we want to merge information on
@@ -6627,7 +6699,8 @@  determine_value_range_1 (value_range *vr, tree expr)
 {
   if (BINARY_CLASS_P (expr))
     {
-      value_range vr0 = VR_INITIALIZER, vr1 = VR_INITIALIZER;
+      value_range vr0 (TREE_TYPE (TREE_OPERAND (expr, 0)));
+      value_range vr1 (TREE_TYPE (TREE_OPERAND (expr, 1)));
       determine_value_range_1 (&vr0, TREE_OPERAND (expr, 0));
       determine_value_range_1 (&vr1, TREE_OPERAND (expr, 1));
       extract_range_from_binary_expr_1 (vr, TREE_CODE (expr), TREE_TYPE (expr),
@@ -6635,7 +6708,7 @@  determine_value_range_1 (value_range *vr, tree expr)
     }
   else if (UNARY_CLASS_P (expr))
     {
-      value_range vr0 = VR_INITIALIZER;
+      value_range vr0 (TREE_TYPE (TREE_OPERAND (expr, 0)));
       determine_value_range_1 (&vr0, TREE_OPERAND (expr, 0));
       extract_range_from_unary_expr (vr, TREE_CODE (expr), TREE_TYPE (expr),
 				     &vr0, TREE_TYPE (TREE_OPERAND (expr, 0)));
@@ -6664,15 +6737,13 @@  determine_value_range_1 (value_range *vr, tree expr)
 value_range_type
 determine_value_range (tree expr, wide_int *min, wide_int *max)
 {
-  value_range vr = VR_INITIALIZER;
+  value_range vr (TREE_TYPE (expr));
   determine_value_range_1 (&vr, expr);
-  if ((vr.type == VR_RANGE
-       || vr.type == VR_ANTI_RANGE)
-      && !symbolic_range_p (&vr))
+  if (vr.numeric_p ())
     {
-      *min = wi::to_wide (vr.min);
-      *max = wi::to_wide (vr.max);
-      return vr.type;
+      *min = wi::to_wide (vr.min ());
+      *max = wi::to_wide (vr.max ());
+      return vr.vrtype ();
     }
 
   return VR_VARYING;