diff gcc/tree-vrp.c @ 132:d34655255c78

update gcc-8.2
author mir3636
date Thu, 25 Oct 2018 10:21:07 +0900
parents 84e7813d76e9
children 1830386684a0
line wrap: on
line diff
--- a/gcc/tree-vrp.c	Thu Oct 25 08:08:40 2018 +0900
+++ b/gcc/tree-vrp.c	Thu Oct 25 10:21:07 2018 +0900
@@ -1,5 +1,5 @@
 /* Support routines for Value Range Propagation (VRP).
-   Copyright (C) 2005-2017 Free Software Foundation, Inc.
+   Copyright (C) 2005-2018 Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>.
 
 This file is part of GCC.
@@ -42,6 +42,7 @@
 #include "gimple-iterator.h"
 #include "gimple-walk.h"
 #include "tree-cfg.h"
+#include "tree-dfa.h"
 #include "tree-ssa-loop-manip.h"
 #include "tree-ssa-loop-niter.h"
 #include "tree-ssa-loop.h"
@@ -64,17 +65,311 @@
 #include "tree-cfgcleanup.h"
 #include "stringpool.h"
 #include "attribs.h"
-
-#define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
-
-/* Allocation pools for tree-vrp allocations.  */
-static object_allocator<value_range> vrp_value_range_pool ("Tree VRP value ranges");
-static bitmap_obstack vrp_equiv_obstack;
+#include "vr-values.h"
+#include "builtins.h"
+#include "wide-int-range.h"
 
 /* Set of SSA names found live during the RPO traversal of the function
    for still active basic-blocks.  */
 static sbitmap *live;
 
+/* Initialize value_range.  */
+
+void
+value_range::set (enum value_range_kind kind, tree min, tree max,
+		  bitmap equiv)
+{
+  m_kind = kind;
+  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);
+    }
+  if (flag_checking)
+    check ();
+}
+
+value_range::value_range (value_range_kind kind, tree min, tree max,
+			  bitmap equiv)
+{
+  m_equiv = NULL;
+  set (kind, min, max, equiv);
+}
+
+/* Like above, but keep the equivalences intact.  */
+
+void
+value_range::update (value_range_kind kind, tree min, tree max)
+{
+  set (kind, min, max, m_equiv);
+}
+
+/* Copy value_range in FROM into THIS while avoiding bitmap sharing.
+
+   Note: The code that avoids the bitmap sharing looks at the existing
+   this->m_equiv, so this function cannot be used to initalize an
+   object.  Use the constructors for initialization.  */
+
+void
+value_range::deep_copy (const value_range *from)
+{
+  set (from->m_kind, from->min (), from->max (), from->m_equiv);
+}
+
+/* Check the validity of the range.  */
+
+void
+value_range::check ()
+{
+  switch (m_kind)
+    {
+    case VR_RANGE:
+    case VR_ANTI_RANGE:
+      {
+	int cmp;
+
+	gcc_assert (m_min && m_max);
+
+	gcc_assert (!TREE_OVERFLOW_P (m_min) && !TREE_OVERFLOW_P (m_max));
+
+	/* Creating ~[-MIN, +MAX] is stupid because that would be
+	   the empty set.  */
+	if (INTEGRAL_TYPE_P (TREE_TYPE (m_min)) && m_kind == 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);
+	break;
+      }
+    case VR_UNDEFINED:
+    case VR_VARYING:
+      gcc_assert (!m_min && !m_max);
+      gcc_assert (!m_equiv || bitmap_empty_p (m_equiv));
+      break;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Returns TRUE if THIS == OTHER.  Ignores the equivalence bitmap if
+   IGNORE_EQUIVS is TRUE.  */
+
+bool
+value_range::equal_p (const value_range &other, bool ignore_equivs) const
+{
+  return (m_kind == other.m_kind
+	  && vrp_operand_equal_p (m_min, other.m_min)
+	  && vrp_operand_equal_p (m_max, other.m_max)
+	  && (ignore_equivs
+	      || vrp_bitmap_equal_p (m_equiv, other.m_equiv)));
+}
+
+/* Return equality while ignoring equivalence bitmap.  */
+
+bool
+value_range::ignore_equivs_equal_p (const value_range &other) const
+{
+  return equal_p (other, /*ignore_equivs=*/true);
+}
+
+bool
+value_range::operator== (const value_range &other) const
+{
+  return equal_p (other, /*ignore_equivs=*/false);
+}
+
+bool
+value_range::operator!= (const value_range &other) const
+{
+  return !(*this == other);
+}
+
+/* Return TRUE if this is a symbolic range.  */
+
+bool
+value_range::symbolic_p () const
+{
+  return (!varying_p ()
+	  && !undefined_p ()
+	  && (!is_gimple_min_invariant (m_min)
+	      || !is_gimple_min_invariant (m_max)));
+}
+
+/* NOTE: This 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
+   constants would be represented as [-MIN, +MAX].  */
+
+bool
+value_range::constant_p () const
+{
+  return (!varying_p ()
+	  && !undefined_p ()
+	  && TREE_CODE (m_min) == INTEGER_CST
+	  && TREE_CODE (m_max) == INTEGER_CST);
+}
+
+void
+value_range::set_undefined ()
+{
+  equiv_clear ();
+  *this = value_range (VR_UNDEFINED, NULL, NULL, NULL);
+}
+
+void
+value_range::set_varying ()
+{
+  equiv_clear ();
+  *this = value_range (VR_VARYING, NULL, NULL, NULL);
+}
+
+/* Return TRUE if it is possible that range contains VAL.  */
+
+bool
+value_range::may_contain_p (tree val) const
+{
+  if (varying_p ())
+    return true;
+
+  if (undefined_p ())
+    return true;
+
+  if (m_kind == 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;
+}
+
+void
+value_range::equiv_clear ()
+{
+  if (m_equiv)
+    bitmap_clear (m_equiv);
+}
+
+/* Add VAR and VAR's equivalence set (VAR_VR) to the equivalence
+   bitmap.  If no equivalence table has been created, OBSTACK is the
+   obstack to use (NULL for the default obstack).
+
+   This is the central point where equivalence processing can be
+   turned on/off.  */
+
+void
+value_range::equiv_add (const_tree var,
+			const value_range *var_vr,
+			bitmap_obstack *obstack)
+{
+  if (!m_equiv)
+    m_equiv = BITMAP_ALLOC (obstack);
+  unsigned ver = SSA_NAME_VERSION (var);
+  bitmap_set_bit (m_equiv, ver);
+  if (var_vr && var_vr->m_equiv)
+    bitmap_ior_into (m_equiv, var_vr->m_equiv);
+}
+
+/* If range is a singleton, place it in RESULT and return TRUE.
+   Note: A singleton can be any gimple invariant, not just constants.
+   So, [&x, &x] counts as a singleton.  */
+
+bool
+value_range::singleton_p (tree *result) const
+{
+  if (m_kind == VR_RANGE
+      && vrp_operand_equal_p (m_min, m_max)
+      && is_gimple_min_invariant (m_min))
+    {
+      if (result)
+        *result = m_min;
+      return true;
+    }
+  return false;
+}
+
+tree
+value_range::type () const
+{
+  /* Types are only valid for VR_RANGE and VR_ANTI_RANGE, which are
+     known to have non-zero min/max.  */
+  gcc_assert (m_min);
+  return TREE_TYPE (m_min);
+}
+
+/* Dump value range to FILE.  */
+
+void
+value_range::dump (FILE *file) const
+{
+  if (undefined_p ())
+    fprintf (file, "UNDEFINED");
+  else if (m_kind == VR_RANGE || m_kind == VR_ANTI_RANGE)
+    {
+      tree type = TREE_TYPE (min ());
+
+      fprintf (file, "%s[", (m_kind == VR_ANTI_RANGE) ? "~" : "");
+
+      if (INTEGRAL_TYPE_P (type)
+	  && !TYPE_UNSIGNED (type)
+	  && vrp_val_is_min (min ()))
+	fprintf (file, "-INF");
+      else
+	print_generic_expr (file, min ());
+
+      fprintf (file, ", ");
+
+      if (INTEGRAL_TYPE_P (type)
+	  && vrp_val_is_max (max ()))
+	fprintf (file, "+INF");
+      else
+	print_generic_expr (file, max ());
+
+      fprintf (file, "]");
+
+      if (m_equiv)
+	{
+	  bitmap_iterator bi;
+	  unsigned i, c = 0;
+
+	  fprintf (file, "  EQUIVALENCES: { ");
+
+	  EXECUTE_IF_SET_IN_BITMAP (m_equiv, 0, i, bi)
+	    {
+	      print_generic_expr (file, ssa_name (i));
+	      fprintf (file, " ");
+	      c++;
+	    }
+
+	  fprintf (file, "} (%u elements)", c);
+	}
+    }
+  else if (varying_p ())
+    fprintf (file, "VARYING");
+  else
+    fprintf (file, "INVALID RANGE");
+}
+
+void
+value_range::dump () const
+{
+  dump_value_range (stderr, this);
+  fprintf (stderr, "\n");
+}
+
 /* Return true if the SSA name NAME is live on the edge E.  */
 
 static bool
@@ -84,28 +379,6 @@
 	  && bitmap_bit_p (live[e->dest->index], SSA_NAME_VERSION (name)));
 }
 
-/* Local functions.  */
-static int compare_values (tree val1, tree val2);
-static int compare_values_warnv (tree val1, tree val2, bool *);
-static tree vrp_evaluate_conditional_warnv_with_ops (enum tree_code,
-						     tree, tree, bool, bool *,
-						     bool *);
-
-struct assert_info
-{
-  /* Predicate code for the ASSERT_EXPR.  Must be COMPARISON_CLASS_P.  */
-  enum tree_code comp_code;
-
-  /* Name to register the assert for.  */
-  tree name;
-
-  /* Value being compared against.  */
-  tree val;
-
-  /* Expression to compare.  */
-  tree expr;
-};
-
 /* Location information for ASSERT_EXPRs.  Each instance of this
    structure describes an ASSERT_EXPR for an SSA name.  Since a single
    SSA name may have more than one assertion associated with it, these
@@ -145,29 +418,9 @@
    ASSERT_EXPRs for SSA name N_I should be inserted.  */
 static assert_locus **asserts_for;
 
-/* Value range array.  After propagation, VR_VALUE[I] holds the range
-   of values that SSA name N_I may take.  */
-static unsigned num_vr_values;
-static value_range **vr_value;
-static bool values_propagated;
-
-/* For a PHI node which sets SSA name N_I, VR_COUNTS[I] holds the
-   number of executable edges we saw the last time we visited the
-   node.  */
-static int *vr_phi_edge_counts;
-
-struct switch_update {
-  gswitch *stmt;
-  tree vec;
-};
-
-static vec<edge> to_remove_edges;
-static vec<switch_update> to_update_switch_stmts;
-
-
 /* Return the maximum value for TYPE.  */
 
-static inline tree
+tree
 vrp_val_max (const_tree type)
 {
   if (!INTEGRAL_TYPE_P (type))
@@ -178,7 +431,7 @@
 
 /* Return the minimum value for TYPE.  */
 
-static inline tree
+tree
 vrp_val_min (const_tree type)
 {
   if (!INTEGRAL_TYPE_P (type))
@@ -192,7 +445,7 @@
    C typedefs and Ada subtypes can produce types whose TYPE_MAX_VALUE
    is not == to the integer constant with the same value in the type.  */
 
-static inline bool
+bool
 vrp_val_is_max (const_tree val)
 {
   tree type_max = vrp_val_max (TREE_TYPE (val));
@@ -203,7 +456,7 @@
 
 /* Return whether VAL is equal to the minimum value of its type.  */
 
-static inline bool
+bool
 vrp_val_is_min (const_tree val)
 {
   tree type_min = vrp_val_min (TREE_TYPE (val));
@@ -212,83 +465,106 @@
 	      && operand_equal_p (val, type_min, 0)));
 }
 
+/* VR_TYPE describes a range with mininum value *MIN and maximum
+   value *MAX.  Restrict the range to the set of values that have
+   no bits set outside NONZERO_BITS.  Update *MIN and *MAX and
+   return the new range type.
+
+   SGN gives the sign of the values described by the range.  */
+
+enum value_range_kind
+intersect_range_with_nonzero_bits (enum value_range_kind vr_type,
+				   wide_int *min, wide_int *max,
+				   const wide_int &nonzero_bits,
+				   signop sgn)
+{
+  if (vr_type == VR_ANTI_RANGE)
+    {
+      /* The VR_ANTI_RANGE is equivalent to the union of the ranges
+	 A: [-INF, *MIN) and B: (*MAX, +INF].  First use NONZERO_BITS
+	 to create an inclusive upper bound for A and an inclusive lower
+	 bound for B.  */
+      wide_int a_max = wi::round_down_for_mask (*min - 1, nonzero_bits);
+      wide_int b_min = wi::round_up_for_mask (*max + 1, nonzero_bits);
+
+      /* If the calculation of A_MAX wrapped, A is effectively empty
+	 and A_MAX is the highest value that satisfies NONZERO_BITS.
+	 Likewise if the calculation of B_MIN wrapped, B is effectively
+	 empty and B_MIN is the lowest value that satisfies NONZERO_BITS.  */
+      bool a_empty = wi::ge_p (a_max, *min, sgn);
+      bool b_empty = wi::le_p (b_min, *max, sgn);
+
+      /* If both A and B are empty, there are no valid values.  */
+      if (a_empty && b_empty)
+	return VR_UNDEFINED;
+
+      /* If exactly one of A or B is empty, return a VR_RANGE for the
+	 other one.  */
+      if (a_empty || b_empty)
+	{
+	  *min = b_min;
+	  *max = a_max;
+	  gcc_checking_assert (wi::le_p (*min, *max, sgn));
+	  return VR_RANGE;
+	}
+
+      /* Update the VR_ANTI_RANGE bounds.  */
+      *min = a_max + 1;
+      *max = b_min - 1;
+      gcc_checking_assert (wi::le_p (*min, *max, sgn));
+
+      /* Now check whether the excluded range includes any values that
+	 satisfy NONZERO_BITS.  If not, switch to a full VR_RANGE.  */
+      if (wi::round_up_for_mask (*min, nonzero_bits) == b_min)
+	{
+	  unsigned int precision = min->get_precision ();
+	  *min = wi::min_value (precision, sgn);
+	  *max = wi::max_value (precision, sgn);
+	  vr_type = VR_RANGE;
+	}
+    }
+  if (vr_type == VR_RANGE)
+    {
+      *max = wi::round_down_for_mask (*max, nonzero_bits);
+
+      /* Check that the range contains at least one valid value.  */
+      if (wi::gt_p (*min, *max, sgn))
+	return VR_UNDEFINED;
+
+      *min = wi::round_up_for_mask (*min, nonzero_bits);
+      gcc_checking_assert (wi::le_p (*min, *max, sgn));
+    }
+  return vr_type;
+}
 
 /* Set value range VR to VR_UNDEFINED.  */
 
 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.  */
 
-static inline void
+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}.  */
 
-static void
-set_value_range (value_range *vr, enum value_range_type t, tree min,
-		 tree max, bitmap equiv)
+void
+set_value_range (value_range *vr, enum value_range_kind kind,
+		 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.  */
-  if (vr->equiv == NULL
-      && equiv != NULL)
-    vr->equiv = BITMAP_ALLOC (&vrp_equiv_obstack);
-
-  if (equiv != vr->equiv)
-    {
-      if (equiv && !bitmap_empty_p (equiv))
-	bitmap_copy (vr->equiv, equiv);
-      else
-	bitmap_clear (vr->equiv);
-    }
+  *vr = value_range (kind, min, max, equiv);
 }
 
 
-/* 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
+/* Set value range to the canonical form of {VRTYPE, MIN, MAX, EQUIV}.
+   This means adjusting VRTYPE, 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
@@ -296,19 +572,19 @@
    This routine exists to ease canonicalization in the case where we
    extract ranges from var + CST op limit.  */
 
-static void
-set_and_canonicalize_value_range (value_range *vr, enum value_range_type t,
-				  tree min, tree max, bitmap equiv)
+void
+value_range::set_and_canonicalize (enum value_range_kind kind,
+				   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);
+  if (kind == VR_UNDEFINED)
+    {
+      set_undefined ();
       return;
     }
-  else if (t == VR_VARYING)
-    {
-      set_value_range_to_varying (vr);
+  else if (kind == VR_VARYING)
+    {
+      set_varying ();
       return;
     }
 
@@ -316,7 +592,7 @@
   if (TREE_CODE (min) != INTEGER_CST
       || TREE_CODE (max) != INTEGER_CST)
     {
-      set_value_range (vr, t, min, max, equiv);
+      set_value_range (this, kind, min, max, equiv);
       return;
     }
 
@@ -331,7 +607,7 @@
 	 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);
+	  set_varying ();
 	  return;
 	}
 
@@ -345,24 +621,29 @@
 	 to varying in this case.  */
       if (tree_int_cst_lt (max, min))
 	{
-	  set_value_range_to_varying (vr);
+	  set_varying ();
 	  return;
 	}
 
-      t = t == VR_RANGE ? VR_ANTI_RANGE : VR_RANGE;
+      kind = kind == VR_RANGE ? VR_ANTI_RANGE : VR_RANGE;
     }
 
   /* Anti-ranges that can be represented as ranges should be so.  */
-  if (t == VR_ANTI_RANGE)
-    {
-      bool is_min = vrp_val_is_min (min);
-      bool is_max = vrp_val_is_max (max);
+  if (kind == 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);
+	  set_varying ();
 	  return;
 	}
       else if (TYPE_PRECISION (TREE_TYPE (min)) == 1
@@ -374,7 +655,7 @@
 	    min = max = vrp_val_max (TREE_TYPE (min));
 	  else
 	    min = max = vrp_val_min (TREE_TYPE (min));
-	  t = VR_RANGE;
+	  kind = VR_RANGE;
 	}
       else if (is_min
 	       /* As a special exception preserve non-null ranges.  */
@@ -384,14 +665,14 @@
 	  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;
+	  kind = 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;
+	  kind = VR_RANGE;
         }
     }
 
@@ -399,22 +680,14 @@
      to make sure VRP iteration terminates, otherwise we can get into
      oscillations.  */
 
-  set_value_range (vr, t, min, max, equiv);
-}
-
-/* Copy value range FROM into value range TO.  */
-
-static inline void
-copy_value_range (value_range *to, value_range *from)
-{
-  set_value_range (to, from->type, from->min, from->max, from->equiv);
+  set_value_range (this, kind, min, max, equiv);
 }
 
 /* Set value range VR to a single value.  This function is only called
    with values we get from statements, and exists to clear the
    TREE_OVERFLOW flag.  */
 
-static inline void
+void
 set_value_range_to_value (value_range *vr, tree val, bitmap equiv)
 {
   gcc_assert (is_gimple_min_invariant (val));
@@ -423,180 +696,27 @@
   set_value_range (vr, VR_RANGE, val, val, equiv);
 }
 
-/* Set value range VR to a non-negative range of type TYPE.  */
-
-static inline void
-set_value_range_to_nonnegative (value_range *vr, tree type)
-{
-  tree zero = build_int_cst (type, 0);
-  set_value_range (vr, VR_RANGE, zero, vrp_val_max (type), vr->equiv);
-}
-
 /* Set value range VR to a non-NULL range of type TYPE.  */
 
-static inline void
+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);
+  vr->update (VR_ANTI_RANGE, zero, zero);
 }
 
 
 /* Set value range VR to a NULL range of type TYPE.  */
 
-static inline void
+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 VR to a range of a truthvalue of type TYPE.  */
-
-static inline void
-set_value_range_to_truthvalue (value_range *vr, tree type)
-{
-  if (TYPE_PRECISION (type) == 1)
-    set_value_range_to_varying (vr);
-  else
-    set_value_range (vr, VR_RANGE,
-		     build_int_cst (type, 0), build_int_cst (type, 1),
-		     vr->equiv);
-}
-
-
-/* If abs (min) < abs (max), set VR to [-max, max], if
-   abs (min) >= abs (max), set VR to [-min, min].  */
-
-static void
-abs_extent_range (value_range *vr, tree min, tree max)
-{
-  int cmp;
-
-  gcc_assert (TREE_CODE (min) == INTEGER_CST);
-  gcc_assert (TREE_CODE (max) == INTEGER_CST);
-  gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (min)));
-  gcc_assert (!TYPE_UNSIGNED (TREE_TYPE (min)));
-  min = fold_unary (ABS_EXPR, TREE_TYPE (min), min);
-  max = fold_unary (ABS_EXPR, TREE_TYPE (max), max);
-  if (TREE_OVERFLOW (min) || TREE_OVERFLOW (max))
-    {
-      set_value_range_to_varying (vr);
-      return;
-    }
-  cmp = compare_values (min, max);
-  if (cmp == -1)
-    min = fold_unary (NEGATE_EXPR, TREE_TYPE (min), max);
-  else if (cmp == 0 || cmp == 1)
-    {
-      max = min;
-      min = fold_unary (NEGATE_EXPR, TREE_TYPE (min), min);
-    }
-  else
-    {
-      set_value_range_to_varying (vr);
-      return;
-    }
-  set_and_canonicalize_value_range (vr, VR_RANGE, min, max, NULL);
+  set_value_range_to_value (vr, build_int_cst (type, 0), vr->equiv ());
 }
 
-
-/* Return value range information for VAR.
-
-   If we have no values ranges recorded (ie, VRP is not running), then
-   return NULL.  Otherwise create an empty range if none existed for VAR.  */
-
-static value_range *
-get_value_range (const_tree var)
-{
-  static const value_range vr_const_varying
-    = { VR_VARYING, NULL_TREE, NULL_TREE, NULL };
-  value_range *vr;
-  tree sym;
-  unsigned ver = SSA_NAME_VERSION (var);
-
-  /* If we have no recorded ranges, then return NULL.  */
-  if (! vr_value)
-    return NULL;
-
-  /* If we query the range for a new SSA name return an unmodifiable VARYING.
-     We should get here at most from the substitute-and-fold stage which
-     will never try to change values.  */
-  if (ver >= num_vr_values)
-    return CONST_CAST (value_range *, &vr_const_varying);
-
-  vr = vr_value[ver];
-  if (vr)
-    return vr;
-
-  /* After propagation finished do not allocate new value-ranges.  */
-  if (values_propagated)
-    return CONST_CAST (value_range *, &vr_const_varying);
-
-  /* Create a default value range.  */
-  vr_value[ver] = vr = vrp_value_range_pool.allocate ();
-  memset (vr, 0, sizeof (*vr));
-
-  /* Defer allocating the equivalence set.  */
-  vr->equiv = NULL;
-
-  /* If VAR is a default definition of a parameter, the variable can
-     take any value in VAR's type.  */
-  if (SSA_NAME_IS_DEFAULT_DEF (var))
-    {
-      sym = SSA_NAME_VAR (var);
-      if (TREE_CODE (sym) == PARM_DECL)
-	{
-	  /* Try to use the "nonnull" attribute to create ~[0, 0]
-	     anti-ranges for pointers.  Note that this is only valid with
-	     default definitions of PARM_DECLs.  */
-	  if (POINTER_TYPE_P (TREE_TYPE (sym))
-	      && (nonnull_arg_p (sym)
-		  || get_ptr_nonnull (var)))
-	    set_value_range_to_nonnull (vr, TREE_TYPE (sym));
-	  else if (INTEGRAL_TYPE_P (TREE_TYPE (sym)))
-	    {
-	      wide_int min, max;
-	      value_range_type rtype = get_range_info (var, &min, &max);
-	      if (rtype == VR_RANGE || rtype == VR_ANTI_RANGE)
-		set_value_range (vr, rtype,
-				 wide_int_to_tree (TREE_TYPE (var), min),
-				 wide_int_to_tree (TREE_TYPE (var), max),
-				 NULL);
-	      else
-		set_value_range_to_varying (vr);
-	    }
-	  else
-	    set_value_range_to_varying (vr);
-	}
-      else if (TREE_CODE (sym) == RESULT_DECL
-	       && DECL_BY_REFERENCE (sym))
-	set_value_range_to_nonnull (vr, TREE_TYPE (sym));
-    }
-
-  return vr;
-}
-
-/* Set value-ranges of all SSA names defined by STMT to varying.  */
-
-static void
-set_defs_to_varying (gimple *stmt)
-{
-  ssa_op_iter i;
-  tree def;
-  FOR_EACH_SSA_TREE_OPERAND (def, stmt, i, SSA_OP_DEF)
-    {
-      value_range *vr = get_value_range (def);
-      /* Avoid writing to vr_const_varying get_value_range may return.  */
-      if (vr->type != VR_VARYING)
-	set_value_range_to_varying (vr);
-    }
-}
-
-
 /* Return true, if VAL1 and VAL2 are equal values for VRP purposes.  */
 
-static inline bool
+bool
 vrp_operand_equal_p (const_tree val1, const_tree val2)
 {
   if (val1 == val2)
@@ -608,7 +728,7 @@
 
 /* Return true, if the bitmaps B1 and B2 are equal.  */
 
-static inline bool
+bool
 vrp_bitmap_equal_p (const_bitmap b1, const_bitmap b2)
 {
   return (b1 == b2
@@ -618,144 +738,47 @@
 	      && bitmap_equal_p (b1, b2)));
 }
 
-/* Update the value range and equivalence set for variable VAR to
-   NEW_VR.  Return true if NEW_VR is different from VAR's previous
-   value.
-
-   NOTE: This function assumes that NEW_VR is a temporary value range
-   object created for the sole purpose of updating VAR's range.  The
-   storage used by the equivalence set from NEW_VR will be freed by
-   this function.  Do not call update_value_range when NEW_VR
-   is the range object associated with another SSA name.  */
-
-static inline bool
-update_value_range (const_tree var, value_range *new_vr)
-{
-  value_range *old_vr;
-  bool is_new;
-
-  /* If there is a value-range on the SSA name from earlier analysis
-     factor that in.  */
-  if (INTEGRAL_TYPE_P (TREE_TYPE (var)))
-    {
-      wide_int min, max;
-      value_range_type rtype = get_range_info (var, &min, &max);
-      if (rtype == VR_RANGE || rtype == VR_ANTI_RANGE)
-	{
-	  tree nr_min, nr_max;
-	  nr_min = wide_int_to_tree (TREE_TYPE (var), min);
-	  nr_max = wide_int_to_tree (TREE_TYPE (var), max);
-	  value_range nr = VR_INITIALIZER;
-	  set_and_canonicalize_value_range (&nr, rtype, nr_min, nr_max, NULL);
-	  vrp_intersect_ranges (new_vr, &nr);
-	}
-    }
-
-  /* Update the value range, if necessary.  */
-  old_vr = get_value_range (var);
-  is_new = 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 (is_new)
-    {
-      /* Do not allow transitions up the lattice.  The following
-	 is slightly more awkward than just new_vr->type < old_vr->type
-	 because VR_RANGE and VR_ANTI_RANGE need to be considered
-	 the same.  We may not have is_new when transitioning to
-	 UNDEFINED.  If old_vr->type is VARYING, we shouldn't be
-	 called.  */
-      if (new_vr->type == VR_UNDEFINED)
-	{
-	  BITMAP_FREE (new_vr->equiv);
-	  set_value_range_to_varying (old_vr);
-	  set_value_range_to_varying (new_vr);
-	  return true;
-	}
-      else
-	set_value_range (old_vr, new_vr->type, new_vr->min, new_vr->max,
-			 new_vr->equiv);
-    }
-
-  BITMAP_FREE (new_vr->equiv);
-
-  return is_new;
-}
-
-
-/* Add VAR and VAR's equivalence set to EQUIV.  This is the central
-   point where equivalence processing can be turned on/off.  */
-
-static void
-add_equivalence (bitmap *equiv, const_tree var)
-{
-  unsigned ver = SSA_NAME_VERSION (var);
-  value_range *vr = get_value_range (var);
-
-  if (*equiv == NULL)
-    *equiv = BITMAP_ALLOC (&vrp_equiv_obstack);
-  bitmap_set_bit (*equiv, ver);
-  if (vr && vr->equiv)
-    bitmap_ior_into (*equiv, vr->equiv);
-}
-
-
-/* Return true if VR is ~[0, 0].  */
-
-static inline bool
-range_is_nonnull (value_range *vr)
-{
-  return vr->type == VR_ANTI_RANGE
-	 && integer_zerop (vr->min)
-	 && integer_zerop (vr->max);
-}
-
-
 /* Return true if VR is [0, 0].  */
 
 static inline bool
-range_is_null (value_range *vr)
+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->kind () == 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
    a singleton.  */
 
-static inline bool
-range_int_cst_p (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->kind () == VR_RANGE
+	  && TREE_CODE (vr->min ()) == INTEGER_CST
+	  && TREE_CODE (vr->max ()) == INTEGER_CST);
 }
 
 /* Return true if VR is a INTEGER_CST singleton.  */
 
-static inline bool
-range_int_cst_singleton_p (value_range *vr)
+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.  */
-
-static inline bool
-symbolic_range_p (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
    otherwise.  We only handle additive operations and set NEG to true if the
    symbol is negated and INV to the invariant part, if any.  */
 
-static tree
+tree
 get_single_symbol (tree t, bool *neg, tree *inv)
 {
   bool neg_;
@@ -824,161 +847,11 @@
   return build2 (pointer_p ? POINTER_PLUS_EXPR : PLUS_EXPR, type, t, inv);
 }
 
-/* Return true if value range VR involves exactly one symbol SYM.  */
-
-static bool
-symbolic_range_based_on_p (value_range *vr, const_tree sym)
-{
-  bool neg, min_has_symbol, max_has_symbol;
-  tree inv;
-
-  if (is_gimple_min_invariant (vr->min))
-    min_has_symbol = false;
-  else if (get_single_symbol (vr->min, &neg, &inv) == sym)
-    min_has_symbol = true;
-  else
-    return false;
-
-  if (is_gimple_min_invariant (vr->max))
-    max_has_symbol = false;
-  else if (get_single_symbol (vr->max, &neg, &inv) == sym)
-    max_has_symbol = true;
-  else
-    return false;
-
-  return (min_has_symbol || max_has_symbol);
-}
-
-/* Return true if the result of assignment STMT is know to be non-zero.  */
-
-static bool
-gimple_assign_nonzero_p (gimple *stmt)
-{
-  enum tree_code code = gimple_assign_rhs_code (stmt);
-  bool strict_overflow_p;
-  switch (get_gimple_rhs_class (code))
-    {
-    case GIMPLE_UNARY_RHS:
-      return tree_unary_nonzero_warnv_p (gimple_assign_rhs_code (stmt),
-					 gimple_expr_type (stmt),
-					 gimple_assign_rhs1 (stmt),
-					 &strict_overflow_p);
-    case GIMPLE_BINARY_RHS:
-      return tree_binary_nonzero_warnv_p (gimple_assign_rhs_code (stmt),
-					  gimple_expr_type (stmt),
-					  gimple_assign_rhs1 (stmt),
-					  gimple_assign_rhs2 (stmt),
-					  &strict_overflow_p);
-    case GIMPLE_TERNARY_RHS:
-      return false;
-    case GIMPLE_SINGLE_RHS:
-      return tree_single_nonzero_warnv_p (gimple_assign_rhs1 (stmt),
-					  &strict_overflow_p);
-    case GIMPLE_INVALID_RHS:
-      gcc_unreachable ();
-    default:
-      gcc_unreachable ();
-    }
-}
-
-/* Return true if STMT is known to compute a non-zero value.  */
-
-static bool
-gimple_stmt_nonzero_p (gimple *stmt)
-{
-  switch (gimple_code (stmt))
-    {
-    case GIMPLE_ASSIGN:
-      return gimple_assign_nonzero_p (stmt);
-    case GIMPLE_CALL:
-      {
-	tree fndecl = gimple_call_fndecl (stmt);
-	if (!fndecl) return false;
-	if (flag_delete_null_pointer_checks && !flag_check_new
-	    && DECL_IS_OPERATOR_NEW (fndecl)
-	    && !TREE_NOTHROW (fndecl))
-	  return true;
-	/* References are always non-NULL.  */
-	if (flag_delete_null_pointer_checks
-	    && TREE_CODE (TREE_TYPE (fndecl)) == REFERENCE_TYPE)
-	  return true;
-	if (flag_delete_null_pointer_checks && 
-	    lookup_attribute ("returns_nonnull",
-			      TYPE_ATTRIBUTES (gimple_call_fntype (stmt))))
-	  return true;
-
-	gcall *call_stmt = as_a<gcall *> (stmt);
-	unsigned rf = gimple_call_return_flags (call_stmt);
-	if (rf & ERF_RETURNS_ARG)
-	  {
-	    unsigned argnum = rf & ERF_RETURN_ARG_MASK;
-	    if (argnum < gimple_call_num_args (call_stmt))
-	      {
-		tree arg = gimple_call_arg (call_stmt, argnum);
-		if (SSA_VAR_P (arg)
-		    && infer_nonnull_range_by_attribute (stmt, arg))
-		  return true;
-	      }
-	  }
-	return gimple_alloca_call_p (stmt);
-      }
-    default:
-      gcc_unreachable ();
-    }
-}
-
-/* Like tree_expr_nonzero_p, but this function uses value ranges
-   obtained so far.  */
-
-static bool
-vrp_stmt_computes_nonzero (gimple *stmt)
-{
-  if (gimple_stmt_nonzero_p (stmt))
-    return true;
-
-  /* If we have an expression of the form &X->a, then the expression
-     is nonnull if X is nonnull.  */
-  if (is_gimple_assign (stmt)
-      && gimple_assign_rhs_code (stmt) == ADDR_EXPR)
-    {
-      tree expr = gimple_assign_rhs1 (stmt);
-      tree base = get_base_address (TREE_OPERAND (expr, 0));
-
-      if (base != NULL_TREE
-	  && TREE_CODE (base) == MEM_REF
-	  && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
-	{
-	  value_range *vr = get_value_range (TREE_OPERAND (base, 0));
-	  if (range_is_nonnull (vr))
-	    return true;
-	}
-    }
-
-  return false;
-}
-
-/* Returns true if EXPR is a valid value (as expected by compare_values) --
-   a gimple invariant, or SSA_NAME +- CST.  */
-
-static bool
-valid_value_p (tree expr)
-{
-  if (TREE_CODE (expr) == SSA_NAME)
-    return true;
-
-  if (TREE_CODE (expr) == PLUS_EXPR
-      || TREE_CODE (expr) == MINUS_EXPR)
-    return (TREE_CODE (TREE_OPERAND (expr, 0)) == SSA_NAME
-	    && TREE_CODE (TREE_OPERAND (expr, 1)) == INTEGER_CST);
-
-  return is_gimple_min_invariant (expr);
-}
-
 /* Return
    1 if VAL < VAL2
    0 if !(VAL < VAL2)
    -2 if those are incomparable.  */
-static inline int
+int
 operand_less_p (tree val, tree val2)
 {
   /* LT is folded faster than GE and others.  Inline the common case.  */
@@ -1020,7 +893,7 @@
    true if the return value is only valid if we assume that signed
    overflow is undefined.  */
 
-static int
+int
 compare_values_warnv (tree val1, tree val2, bool *strict_overflow_p)
 {
   if (val1 == val2)
@@ -1121,7 +994,24 @@
       if (TREE_OVERFLOW (val1) || TREE_OVERFLOW (val2))
 	return -2;
 
-      return tree_int_cst_compare (val1, val2);
+      if (TREE_CODE (val1) == INTEGER_CST
+	  && TREE_CODE (val2) == INTEGER_CST)
+	return tree_int_cst_compare (val1, val2);
+
+      if (poly_int_tree_p (val1) && poly_int_tree_p (val2))
+	{
+	  if (known_eq (wi::to_poly_widest (val1),
+			wi::to_poly_widest (val2)))
+	    return 0;
+	  if (known_lt (wi::to_poly_widest (val1),
+			wi::to_poly_widest (val2)))
+	    return -1;
+	  if (known_gt (wi::to_poly_widest (val1),
+			wi::to_poly_widest (val2)))
+	    return 1;
+	}
+
+      return -2;
     }
   else
     {
@@ -1157,7 +1047,7 @@
 
 /* Compare values like compare_values_warnv.  */
 
-static int
+int
 compare_values (tree val1, tree val2)
 {
   bool sop;
@@ -1172,7 +1062,7 @@
    Benchmark compile/20001226-1.c compilation time after changing this
    function.  */
 
-static inline int
+int
 value_inside_range (tree val, tree min, tree max)
 {
   int cmp1, cmp2;
@@ -1191,595 +1081,55 @@
 }
 
 
-/* Return true if value ranges VR0 and VR1 have a non-empty
-   intersection.
-
-   Benchmark compile/20001226-1.c compilation time after changing this
-   function.
-   */
-
-static inline bool
-value_ranges_intersect_p (value_range *vr0, value_range *vr1)
-{
-  /* The value ranges do not intersect if the maximum of the first range is
-     less than the minimum of the second range or vice versa.
-     When those relations are unknown, we can't do any better.  */
-  if (operand_less_p (vr0->max, vr1->min) != 0)
-    return false;
-  if (operand_less_p (vr1->max, vr0->min) != 0)
-    return false;
-  return true;
-}
-
-
-/* Return 1 if [MIN, MAX] includes the value zero, 0 if it does not
-   include the value zero, -2 if we cannot tell.  */
-
-static inline int
-range_includes_zero_p (tree min, tree max)
-{
-  tree zero = build_int_cst (TREE_TYPE (min), 0);
-  return value_inside_range (zero, min, max);
-}
-
-/* Return true if *VR is know to only contain nonnegative values.  */
-
-static inline bool
-value_range_nonnegative_p (value_range *vr)
-{
-  /* Testing for VR_ANTI_RANGE is not useful here as any anti-range
-     which would return a useful value should be encoded as a 
-     VR_RANGE.  */
-  if (vr->type == VR_RANGE)
-    {
-      int result = compare_values (vr->min, integer_zero_node);
-      return (result == 0 || result == 1);
-    }
-
-  return false;
-}
-
-/* If *VR has a value rante that is a single constant value return that,
-   otherwise return NULL_TREE.  */
-
-static tree
-value_range_constant_singleton (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;
-}
-
-/* If OP has a value range with a single constant value return that,
-   otherwise return NULL_TREE.  This returns OP itself if OP is a
-   constant.  */
-
-static tree
-op_with_constant_singleton_value_range (tree op)
-{
-  if (is_gimple_min_invariant (op))
-    return op;
-
-  if (TREE_CODE (op) != SSA_NAME)
-    return NULL_TREE;
-
-  return value_range_constant_singleton (get_value_range (op));
-}
-
-/* Return true if op is in a boolean [0, 1] value-range.  */
-
-static bool
-op_with_boolean_value_range_p (tree op)
-{
-  value_range *vr;
-
-  if (TYPE_PRECISION (TREE_TYPE (op)) == 1)
-    return true;
-
-  if (integer_zerop (op)
-      || integer_onep (op))
-    return true;
-
-  if (TREE_CODE (op) != SSA_NAME)
-    return false;
-
-  vr = get_value_range (op);
-  return (vr->type == VR_RANGE
-	  && integer_zerop (vr->min)
-	  && integer_onep (vr->max));
-}
-
-/* Extract value range information for VAR when (OP COND_CODE LIMIT) is
-   true and store it in *VR_P.  */
-
-static void
-extract_range_for_var_from_comparison_expr (tree var, enum tree_code cond_code,
-					    tree op, tree limit,
-					    value_range *vr_p)
+/* Return TRUE if *VR includes the value zero.  */
+
+bool
+range_includes_zero_p (const value_range *vr)
 {
-  tree  min, max, type;
-  value_range *limit_vr;
-  type = TREE_TYPE (var);
-  gcc_assert (limit != var);
-
-  /* For pointer arithmetic, we only keep track of pointer equality
-     and inequality.  */
-  if (POINTER_TYPE_P (type) && cond_code != NE_EXPR && cond_code != EQ_EXPR)
-    {
-      set_value_range_to_varying (vr_p);
-      return;
-    }
-
-  /* If LIMIT is another SSA name and LIMIT has a range of its own,
-     try to use LIMIT's range to avoid creating symbolic ranges
-     unnecessarily. */
-  limit_vr = (TREE_CODE (limit) == SSA_NAME) ? get_value_range (limit) : NULL;
-
-  /* LIMIT's range is only interesting if it has any useful information.  */
-  if (! limit_vr
-      || limit_vr->type == VR_UNDEFINED
-      || limit_vr->type == VR_VARYING
-      || (symbolic_range_p (limit_vr)
-	  && ! (limit_vr->type == VR_RANGE
-		&& (limit_vr->min == limit_vr->max
-		    || operand_equal_p (limit_vr->min, limit_vr->max, 0)))))
-    limit_vr = NULL;
-
-  /* Initially, the new range has the same set of equivalences of
-     VAR's range.  This will be revised before returning the final
-     value.  Since assertions may be chained via mutually exclusive
-     predicates, we will need to trim the set of equivalences before
-     we are done.  */
-  gcc_assert (vr_p->equiv == NULL);
-  add_equivalence (&vr_p->equiv, var);
-
-  /* Extract a new range based on the asserted comparison for VAR and
-     LIMIT's value range.  Notice that if LIMIT has an anti-range, we
-     will only use it for equality comparisons (EQ_EXPR).  For any
-     other kind of assertion, we cannot derive a range from LIMIT's
-     anti-range that can be used to describe the new range.  For
-     instance, ASSERT_EXPR <x_2, x_2 <= b_4>.  If b_4 is ~[2, 10],
-     then b_4 takes on the ranges [-INF, 1] and [11, +INF].  There is
-     no single range for x_2 that could describe LE_EXPR, so we might
-     as well build the range [b_4, +INF] for it.
-     One special case we handle is extracting a range from a
-     range test encoded as (unsigned)var + CST <= limit.  */
-  if (TREE_CODE (op) == NOP_EXPR
-      || TREE_CODE (op) == PLUS_EXPR)
-    {
-      if (TREE_CODE (op) == PLUS_EXPR)
-        {
-	  min = fold_build1 (NEGATE_EXPR, TREE_TYPE (TREE_OPERAND (op, 1)),
-			     TREE_OPERAND (op, 1));
-          max = int_const_binop (PLUS_EXPR, limit, min);
-	  op = TREE_OPERAND (op, 0);
-	}
-      else
-	{
-	  min = build_int_cst (TREE_TYPE (var), 0);
-	  max = limit;
-	}
-
-      /* Make sure to not set TREE_OVERFLOW on the final type
-	 conversion.  We are willingly interpreting large positive
-	 unsigned values as negative signed values here.  */
-      min = force_fit_type (TREE_TYPE (var), wi::to_widest (min), 0, false);
-      max = force_fit_type (TREE_TYPE (var), wi::to_widest (max), 0, false);
-
-      /* We can transform a max, min range to an anti-range or
-         vice-versa.  Use set_and_canonicalize_value_range which does
-	 this for us.  */
-      if (cond_code == LE_EXPR)
-        set_and_canonicalize_value_range (vr_p, VR_RANGE,
-					  min, max, vr_p->equiv);
-      else if (cond_code == GT_EXPR)
-        set_and_canonicalize_value_range (vr_p, VR_ANTI_RANGE,
-					  min, max, vr_p->equiv);
-      else
-	gcc_unreachable ();
-    }
-  else if (cond_code == EQ_EXPR)
-    {
-      enum value_range_type range_type;
-
-      if (limit_vr)
-	{
-	  range_type = limit_vr->type;
-	  min = limit_vr->min;
-	  max = limit_vr->max;
-	}
-      else
-	{
-	  range_type = VR_RANGE;
-	  min = limit;
-	  max = limit;
-	}
-
-      set_value_range (vr_p, range_type, min, max, vr_p->equiv);
-
-      /* When asserting the equality VAR == LIMIT and LIMIT is another
-	 SSA name, the new range will also inherit the equivalence set
-	 from LIMIT.  */
-      if (TREE_CODE (limit) == SSA_NAME)
-	add_equivalence (&vr_p->equiv, limit);
-    }
-  else if (cond_code == NE_EXPR)
-    {
-      /* As described above, when LIMIT's range is an anti-range and
-	 this assertion is an inequality (NE_EXPR), then we cannot
-	 derive anything from the anti-range.  For instance, if
-	 LIMIT's range was ~[0, 0], the assertion 'VAR != LIMIT' does
-	 not imply that VAR's range is [0, 0].  So, in the case of
-	 anti-ranges, we just assert the inequality using LIMIT and
-	 not its anti-range.
-
-	 If LIMIT_VR is a range, we can only use it to build a new
-	 anti-range if LIMIT_VR is a single-valued range.  For
-	 instance, if LIMIT_VR is [0, 1], the predicate
-	 VAR != [0, 1] does not mean that VAR's range is ~[0, 1].
-	 Rather, it means that for value 0 VAR should be ~[0, 0]
-	 and for value 1, VAR should be ~[1, 1].  We cannot
-	 represent these ranges.
-
-	 The only situation in which we can build a valid
-	 anti-range is when LIMIT_VR is a single-valued range
-	 (i.e., LIMIT_VR->MIN == LIMIT_VR->MAX).  In that case,
-	 build the anti-range ~[LIMIT_VR->MIN, LIMIT_VR->MAX].  */
-      if (limit_vr
-	  && limit_vr->type == VR_RANGE
-	  && compare_values (limit_vr->min, limit_vr->max) == 0)
-	{
-	  min = limit_vr->min;
-	  max = limit_vr->max;
-	}
-      else
-	{
-	  /* In any other case, we cannot use LIMIT's range to build a
-	     valid anti-range.  */
-	  min = max = limit;
-	}
-
-      /* If MIN and MAX cover the whole range for their type, then
-	 just use the original LIMIT.  */
-      if (INTEGRAL_TYPE_P (type)
-	  && vrp_val_is_min (min)
-	  && vrp_val_is_max (max))
-	min = max = limit;
-
-      set_and_canonicalize_value_range (vr_p, VR_ANTI_RANGE,
-					min, max, vr_p->equiv);
-    }
-  else if (cond_code == LE_EXPR || cond_code == LT_EXPR)
-    {
-      min = TYPE_MIN_VALUE (type);
-
-      if (limit_vr == NULL || limit_vr->type == VR_ANTI_RANGE)
-	max = limit;
-      else
-	{
-	  /* If LIMIT_VR is of the form [N1, N2], we need to build the
-	     range [MIN, N2] for LE_EXPR and [MIN, N2 - 1] for
-	     LT_EXPR.  */
-	  max = limit_vr->max;
-	}
-
-      /* If the maximum value forces us to be out of bounds, simply punt.
-	 It would be pointless to try and do anything more since this
-	 all should be optimized away above us.  */
-      if (cond_code == LT_EXPR
-	  && compare_values (max, min) == 0)
-	set_value_range_to_varying (vr_p);
-      else
-	{
-	  /* For LT_EXPR, we create the range [MIN, MAX - 1].  */
-	  if (cond_code == LT_EXPR)
-	    {
-	      if (TYPE_PRECISION (TREE_TYPE (max)) == 1
-		  && !TYPE_UNSIGNED (TREE_TYPE (max)))
-		max = fold_build2 (PLUS_EXPR, TREE_TYPE (max), max,
-				   build_int_cst (TREE_TYPE (max), -1));
-	      else
-		max = fold_build2 (MINUS_EXPR, TREE_TYPE (max), max,
-				   build_int_cst (TREE_TYPE (max), 1));
-	      /* Signal to compare_values_warnv this expr doesn't overflow.  */
-	      if (EXPR_P (max))
-		TREE_NO_WARNING (max) = 1;
-	    }
-
-	  set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
-	}
-    }
-  else if (cond_code == GE_EXPR || cond_code == GT_EXPR)
-    {
-      max = TYPE_MAX_VALUE (type);
-
-      if (limit_vr == NULL || limit_vr->type == VR_ANTI_RANGE)
-	min = limit;
-      else
-	{
-	  /* If LIMIT_VR is of the form [N1, N2], we need to build the
-	     range [N1, MAX] for GE_EXPR and [N1 + 1, MAX] for
-	     GT_EXPR.  */
-	  min = limit_vr->min;
-	}
-
-      /* If the minimum value forces us to be out of bounds, simply punt.
-	 It would be pointless to try and do anything more since this
-	 all should be optimized away above us.  */
-      if (cond_code == GT_EXPR
-	  && compare_values (min, max) == 0)
-	set_value_range_to_varying (vr_p);
-      else
-	{
-	  /* For GT_EXPR, we create the range [MIN + 1, MAX].  */
-	  if (cond_code == GT_EXPR)
-	    {
-	      if (TYPE_PRECISION (TREE_TYPE (min)) == 1
-		  && !TYPE_UNSIGNED (TREE_TYPE (min)))
-		min = fold_build2 (MINUS_EXPR, TREE_TYPE (min), min,
-				   build_int_cst (TREE_TYPE (min), -1));
-	      else
-		min = fold_build2 (PLUS_EXPR, TREE_TYPE (min), min,
-				   build_int_cst (TREE_TYPE (min), 1));
-	      /* Signal to compare_values_warnv this expr doesn't overflow.  */
-	      if (EXPR_P (min))
-		TREE_NO_WARNING (min) = 1;
-	    }
-
-	  set_value_range (vr_p, VR_RANGE, min, max, vr_p->equiv);
-	}
-    }
-  else
-    gcc_unreachable ();
-
-  /* Finally intersect the new range with what we already know about var.  */
-  vrp_intersect_ranges (vr_p, get_value_range (var));
+  if (vr->varying_p () || vr->undefined_p ())
+    return true;
+  tree zero = build_int_cst (vr->type (), 0);
+  return vr->may_contain_p (zero);
 }
 
-/* Extract value range information from an ASSERT_EXPR EXPR and store
-   it in *VR_P.  */
-
-static void
-extract_range_from_assert (value_range *vr_p, tree expr)
-{
-  tree var = ASSERT_EXPR_VAR (expr);
-  tree cond = ASSERT_EXPR_COND (expr);
-  tree limit, op;
-  enum tree_code cond_code;
-  gcc_assert (COMPARISON_CLASS_P (cond));
-
-  /* Find VAR in the ASSERT_EXPR conditional.  */
-  if (var == TREE_OPERAND (cond, 0)
-      || TREE_CODE (TREE_OPERAND (cond, 0)) == PLUS_EXPR
-      || TREE_CODE (TREE_OPERAND (cond, 0)) == NOP_EXPR)
-    {
-      /* If the predicate is of the form VAR COMP LIMIT, then we just
-	 take LIMIT from the RHS and use the same comparison code.  */
-      cond_code = TREE_CODE (cond);
-      limit = TREE_OPERAND (cond, 1);
-      op = TREE_OPERAND (cond, 0);
-    }
-  else
-    {
-      /* If the predicate is of the form LIMIT COMP VAR, then we need
-	 to flip around the comparison code to create the proper range
-	 for VAR.  */
-      cond_code = swap_tree_comparison (TREE_CODE (cond));
-      limit = TREE_OPERAND (cond, 0);
-      op = TREE_OPERAND (cond, 1);
-    }
-  extract_range_for_var_from_comparison_expr (var, cond_code, op,
-					      limit, vr_p);
-}
-
-/* Extract range information from SSA name VAR and store it in VR.  If
-   VAR has an interesting range, use it.  Otherwise, create the
-   range [VAR, VAR] and return it.  This is useful in situations where
-   we may have conditionals testing values of VARYING names.  For
-   instance,
-
-   	x_3 = y_5;
-	if (x_3 > y_5)
-	  ...
-
-    Even if y_5 is deemed VARYING, we can determine that x_3 > y_5 is
-    always false.  */
-
-static void
-extract_range_from_ssa_name (value_range *vr, tree var)
-{
-  value_range *var_vr = get_value_range (var);
-
-  if (var_vr->type != VR_VARYING)
-    copy_value_range (vr, var_vr);
-  else
-    set_value_range (vr, VR_RANGE, var, var, NULL);
-
-  add_equivalence (&vr->equiv, var);
-}
-
-
-/* Wrapper around int_const_binop.  If the operation overflows and
-   overflow is undefined, then adjust the result to be
-   -INF or +INF depending on CODE, VAL1 and VAL2.  Sets *OVERFLOW_P
-   to whether the operation overflowed.  For division by zero
-   the result is indeterminate but *OVERFLOW_P is set.  */
-
-static wide_int
-vrp_int_const_binop (enum tree_code code, tree val1, tree val2,
-		     bool *overflow_p)
+/* If *VR has a value range that is a single constant value return that,
+   otherwise return NULL_TREE.
+
+   ?? This actually returns TRUE for [&x, &x], so perhaps "constant"
+   is not the best name.  */
+
+tree
+value_range_constant_singleton (const value_range *vr)
 {
-  bool overflow = false;
-  signop sign = TYPE_SIGN (TREE_TYPE (val1));
-  wide_int res;
-
-  *overflow_p = false;
-
-  switch (code)
-    {
-    case RSHIFT_EXPR:
-    case LSHIFT_EXPR:
-      {
-	wide_int wval2 = wi::to_wide (val2, TYPE_PRECISION (TREE_TYPE (val1)));
-	if (wi::neg_p (wval2))
-	  {
-	    wval2 = -wval2;
-	    if (code == RSHIFT_EXPR)
-	      code = LSHIFT_EXPR;
-	    else
-	      code = RSHIFT_EXPR;
-	  }
-
-	if (code == RSHIFT_EXPR)
-	  /* It's unclear from the C standard whether shifts can overflow.
-	     The following code ignores overflow; perhaps a C standard
-	     interpretation ruling is needed.  */
-	  res = wi::rshift (wi::to_wide (val1), wval2, sign);
-	else
-	  res = wi::lshift (wi::to_wide (val1), wval2);
-	break;
-      }
-
-    case MULT_EXPR:
-      res = wi::mul (wi::to_wide (val1),
-		     wi::to_wide (val2), sign, &overflow);
-      break;
-
-    case TRUNC_DIV_EXPR:
-    case EXACT_DIV_EXPR:
-      if (val2 == 0)
-	{
-	  *overflow_p = true;
-	  return res;
-	}
-      else
-	res = wi::div_trunc (wi::to_wide (val1),
-			     wi::to_wide (val2), sign, &overflow);
-      break;
-
-    case FLOOR_DIV_EXPR:
-      if (val2 == 0)
-	{
-	  *overflow_p = true;
-	  return res;
-	}
-      res = wi::div_floor (wi::to_wide (val1),
-			   wi::to_wide (val2), sign, &overflow);
-      break;
-
-    case CEIL_DIV_EXPR:
-      if (val2 == 0)
-	{
-	  *overflow_p = true;
-	  return res;
-	}
-      res = wi::div_ceil (wi::to_wide (val1),
-			  wi::to_wide (val2), sign, &overflow);
-      break;
-
-    case ROUND_DIV_EXPR:
-      if (val2 == 0)
-	{
-	  *overflow_p = 0;
-	  return res;
-	}
-      res = wi::div_round (wi::to_wide (val1),
-			   wi::to_wide (val2), sign, &overflow);
-      break;
-
-    default:
-      gcc_unreachable ();
-    }
-
-  if (overflow
-      && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (val1)))
-    {
-      /* If the operation overflowed return -INF or +INF depending
-	 on the operation and the combination of signs of the operands.  */
-      int sgn1 = tree_int_cst_sgn (val1);
-      int sgn2 = tree_int_cst_sgn (val2);
-
-      /* Notice that we only need to handle the restricted set of
-	 operations handled by extract_range_from_binary_expr.
-	 Among them, only multiplication, addition and subtraction
-	 can yield overflow without overflown operands because we
-	 are working with integral types only... except in the
-	 case VAL1 = -INF and VAL2 = -1 which overflows to +INF
-	 for division too.  */
-
-      /* For multiplication, the sign of the overflow is given
-	 by the comparison of the signs of the operands.  */
-      if ((code == MULT_EXPR && sgn1 == sgn2)
-          /* For addition, the operands must be of the same sign
-	     to yield an overflow.  Its sign is therefore that
-	     of one of the operands, for example the first.  */
-	  || (code == PLUS_EXPR && sgn1 >= 0)
-	  /* For subtraction, operands must be of
-	     different signs to yield an overflow.  Its sign is
-	     therefore that of the first operand or the opposite of
-	     that of the second operand.  A first operand of 0 counts
-	     as positive here, for the corner case 0 - (-INF), which
-	     overflows, but must yield +INF.  */
-	  || (code == MINUS_EXPR && sgn1 >= 0)
-	  /* For division, the only case is -INF / -1 = +INF.  */
-	  || code == TRUNC_DIV_EXPR
-	  || code == FLOOR_DIV_EXPR
-	  || code == CEIL_DIV_EXPR
-	  || code == EXACT_DIV_EXPR
-	  || code == ROUND_DIV_EXPR)
-	return wi::max_value (TYPE_PRECISION (TREE_TYPE (val1)),
-			      TYPE_SIGN (TREE_TYPE (val1)));
-      else
-	return wi::min_value (TYPE_PRECISION (TREE_TYPE (val1)),
-			      TYPE_SIGN (TREE_TYPE (val1)));
-    }
-
-  *overflow_p = overflow;
-
-  return res;
+  tree result = NULL;
+  if (vr->singleton_p (&result))
+    return result;
+  return NULL;
 }
 
-
-/* For range VR compute two wide_int bitmasks.  In *MAY_BE_NONZERO
-   bitmask if some bit is unset, it means for all numbers in the range
-   the bit is 0, otherwise it might be 0 or 1.  In *MUST_BE_NONZERO
-   bitmask if some bit is set, it means for all numbers in the range
-   the bit is 1, otherwise it might be 0 or 1.  */
-
-static bool
-zero_nonzero_bits_from_vr (const tree expr_type,
-			   value_range *vr,
+/* Value range wrapper for wide_int_range_set_zero_nonzero_bits.
+
+   Compute MAY_BE_NONZERO and MUST_BE_NONZERO bit masks for range in VR.
+
+   Return TRUE if VR was a constant range and we were able to compute
+   the bit masks.  */
+
+bool
+vrp_set_zero_nonzero_bits (const tree expr_type,
+			   const value_range *vr,
 			   wide_int *may_be_nonzero,
 			   wide_int *must_be_nonzero)
 {
-  *may_be_nonzero = wi::minus_one (TYPE_PRECISION (expr_type));
-  *must_be_nonzero = wi::zero (TYPE_PRECISION (expr_type));
   if (!range_int_cst_p (vr))
-    return false;
-
-  if (range_int_cst_singleton_p (vr))
-    {
-      *may_be_nonzero = wi::to_wide (vr->min);
-      *must_be_nonzero = *may_be_nonzero;
-    }
-  else if (tree_int_cst_sgn (vr->min) >= 0
-	   || tree_int_cst_sgn (vr->max) < 0)
-    {
-      wide_int xor_mask = wi::to_wide (vr->min) ^ wi::to_wide (vr->max);
-      *may_be_nonzero = wi::to_wide (vr->min) | wi::to_wide (vr->max);
-      *must_be_nonzero = wi::to_wide (vr->min) & wi::to_wide (vr->max);
-      if (xor_mask != 0)
-	{
-	  wide_int mask = wi::mask (wi::floor_log2 (xor_mask), false,
-				    may_be_nonzero->get_precision ());
-	  *may_be_nonzero = *may_be_nonzero | mask;
-	  *must_be_nonzero = wi::bit_and_not (*must_be_nonzero, mask);
-	}
-    }
-
+    {
+      *may_be_nonzero = wi::minus_one (TYPE_PRECISION (expr_type));
+      *must_be_nonzero = wi::zero (TYPE_PRECISION (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 ()),
+					*may_be_nonzero, *must_be_nonzero);
   return true;
 }
 
@@ -1789,67 +1139,75 @@
    *VR1 will be VR_UNDEFINED.  */
 
 static bool
-ranges_from_anti_range (value_range *ar,
+ranges_from_anti_range (const value_range *ar,
 			value_range *vr0, value_range *vr1)
 {
-  tree type = TREE_TYPE (ar->min);
-
-  vr0->type = VR_UNDEFINED;
-  vr1->type = VR_UNDEFINED;
-
-  if (ar->type != VR_ANTI_RANGE
-      || TREE_CODE (ar->min) != INTEGER_CST
-      || TREE_CODE (ar->max) != INTEGER_CST
+  tree type = ar->type ();
+
+  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->kind () != 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 (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 (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;
-    }
-
-  return vr0->type != VR_UNDEFINED;
+      vr1->set_undefined ();
+    }
+
+  return !vr0->undefined_p ();
 }
 
-/* Helper to extract a value-range *VR for a multiplicative operation
-   *VR0 CODE *VR1.  */
+/* Extract the components of a value range into a pair of wide ints in
+   [WMIN, WMAX].
+
+   If the value range is anything but a VR_*RANGE of constants, the
+   resulting wide ints are set to [-MIN, +MAX] for the type.  */
+
+static void inline
+extract_range_into_wide_ints (const value_range *vr,
+			      signop sign, unsigned prec,
+			      wide_int &wmin, wide_int &wmax)
+{
+  gcc_assert (vr->kind () != VR_ANTI_RANGE || vr->symbolic_p ());
+  if (range_int_cst_p (vr))
+    {
+      wmin = wi::to_wide (vr->min ());
+      wmax = wi::to_wide (vr->max ());
+    }
+  else
+    {
+      wmin = wi::min_value (prec, sign);
+      wmax = wi::max_value (prec, sign);
+    }
+}
+
+/* Value range wrapper for wide_int_range_multiplicative_op:
+
+     *VR = *VR0 .CODE. *VR1.  */
 
 static void
-extract_range_from_multiplicative_op_1 (value_range *vr,
-					enum tree_code code,
-					value_range *vr0, value_range *vr1)
+extract_range_from_multiplicative_op (value_range *vr,
+				      enum tree_code code,
+				      const value_range *vr0,
+				      const value_range *vr1)
 {
-  enum value_range_type rtype;
-  wide_int val, min, max;
-  bool sop;
-  tree type;
-
-  /* Multiplications, divisions and shifts are a bit tricky to handle,
-     depending on the mix of signs we have in the two ranges, we
-     need to operate on different values to get the minimum and
-     maximum values for the new range.  One approach is to figure
-     out all the variations of range combinations and do the
-     operations.
-
-     However, this involves several calls to compare_values and it
-     is pretty convoluted.  It's simpler to do the 4 operations
-     (MIN0 OP MIN1, MIN0 OP MAX1, MAX0 OP MIN1 and MAX0 OP MAX0 OP
-     MAX1) and then figure the smallest and largest values to form
-     the new range.  */
   gcc_assert (code == MULT_EXPR
 	      || code == TRUNC_DIV_EXPR
 	      || code == FLOOR_DIV_EXPR
@@ -1858,104 +1216,229 @@
 	      || code == ROUND_DIV_EXPR
 	      || code == RSHIFT_EXPR
 	      || code == LSHIFT_EXPR);
-  gcc_assert (vr0->type == VR_RANGE
-	      && vr0->type == vr1->type);
-
-  rtype = vr0->type;
-  type = TREE_TYPE (vr0->min);
-  signop sgn = TYPE_SIGN (type);
-
-  /* Compute the 4 cross operations and their minimum and maximum value.  */
-  sop = false;
-  val = vrp_int_const_binop (code, vr0->min, vr1->min, &sop);
-  if (! sop)
-    min = max = val;
-
-  if (vr1->max == vr1->min)
+  gcc_assert (vr0->kind () == VR_RANGE
+	      && vr0->kind () == vr1->kind ());
+
+  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 ());
+  bool overflow_undefined = TYPE_OVERFLOW_UNDEFINED (type);
+  unsigned prec = TYPE_PRECISION (type);
+
+  if (wide_int_range_multiplicative_op (res_lb, res_ub,
+					code, TYPE_SIGN (type), prec,
+					vr0_lb, vr0_ub, vr1_lb, vr1_ub,
+					overflow_undefined))
+    vr->set_and_canonicalize (VR_RANGE,
+			      wide_int_to_tree (type, res_lb),
+			      wide_int_to_tree (type, res_ub), NULL);
+  else
+    set_value_range_to_varying (vr);
+}
+
+/* If BOUND will include a symbolic bound, adjust it accordingly,
+   otherwise leave it as is.
+
+   CODE is the original operation that combined the bounds (PLUS_EXPR
+   or MINUS_EXPR).
+
+   TYPE is the type of the original operation.
+
+   SYM_OPn is the symbolic for OPn if it has a symbolic.
+
+   NEG_OPn is TRUE if the OPn was negated.  */
+
+static void
+adjust_symbolic_bound (tree &bound, enum tree_code code, tree type,
+		       tree sym_op0, tree sym_op1,
+		       bool neg_op0, bool neg_op1)
+{
+  bool minus_p = (code == MINUS_EXPR);
+  /* If the result bound is constant, we're done; otherwise, build the
+     symbolic lower bound.  */
+  if (sym_op0 == sym_op1)
     ;
-  else if (! sop)
-    {
-      val = vrp_int_const_binop (code, vr0->min, vr1->max, &sop);
-      if (! sop)
+  else if (sym_op0)
+    bound = build_symbolic_expr (type, sym_op0,
+				 neg_op0, bound);
+  else if (sym_op1)
+    {
+      /* We may not negate if that might introduce
+	 undefined overflow.  */
+      if (!minus_p
+	  || neg_op1
+	  || TYPE_OVERFLOW_WRAPS (type))
+	bound = build_symbolic_expr (type, sym_op1,
+				     neg_op1 ^ minus_p, bound);
+      else
+	bound = NULL_TREE;
+    }
+}
+
+/* Combine OP1 and OP1, which are two parts of a bound, into one wide
+   int bound according to CODE.  CODE is the operation combining the
+   bound (either a PLUS_EXPR or a MINUS_EXPR).
+
+   TYPE is the type of the combine operation.
+
+   WI is the wide int to store the result.
+
+   OVF is -1 if an underflow occurred, +1 if an overflow occurred or 0
+   if over/underflow occurred.  */
+
+static void
+combine_bound (enum tree_code code, wide_int &wi, wi::overflow_type &ovf,
+	       tree type, tree op0, tree op1)
+{
+  bool minus_p = (code == MINUS_EXPR);
+  const signop sgn = TYPE_SIGN (type);
+  const unsigned int prec = TYPE_PRECISION (type);
+
+  /* Combine the bounds, if any.  */
+  if (op0 && op1)
+    {
+      if (minus_p)
+	wi = wi::sub (wi::to_wide (op0), wi::to_wide (op1), sgn, &ovf);
+      else
+	wi = wi::add (wi::to_wide (op0), wi::to_wide (op1), sgn, &ovf);
+    }
+  else if (op0)
+    wi = wi::to_wide (op0);
+  else if (op1)
+    {
+      if (minus_p)
+	wi = wi::neg (wi::to_wide (op1), &ovf);
+      else
+	wi = wi::to_wide (op1);
+    }
+  else
+    wi = wi::shwi (0, prec);
+}
+
+/* Given a range in [WMIN, WMAX], adjust it for possible overflow and
+   put the result in VR.
+
+   TYPE is the type of the range.
+
+   MIN_OVF and MAX_OVF indicate what type of overflow, if any,
+   occurred while originally calculating WMIN or WMAX.  -1 indicates
+   underflow.  +1 indicates overflow.  0 indicates neither.  */
+
+static void
+set_value_range_with_overflow (value_range_kind &kind, tree &min, tree &max,
+			       tree type,
+			       const wide_int &wmin, const wide_int &wmax,
+			       wi::overflow_type min_ovf,
+			       wi::overflow_type max_ovf)
+{
+  const signop sgn = TYPE_SIGN (type);
+  const unsigned int prec = TYPE_PRECISION (type);
+
+  /* For one bit precision if max < min, then the swapped
+     range covers all values.  */
+  if (prec == 1 && wi::lt_p (wmax, wmin, sgn))
+    {
+      kind = VR_VARYING;
+      return;
+    }
+
+  if (TYPE_OVERFLOW_WRAPS (type))
+    {
+      /* If overflow wraps, truncate the values and adjust the
+	 range kind and bounds appropriately.  */
+      wide_int tmin = wide_int::from (wmin, prec, sgn);
+      wide_int tmax = wide_int::from (wmax, prec, sgn);
+      if ((min_ovf != wi::OVF_NONE) == (max_ovf != wi::OVF_NONE))
 	{
-	  if (wi::lt_p (val, min, sgn))
-	    min = val;
-	  else if (wi::gt_p (val, max, sgn))
-	    max = val;
-	}
-    }
-
-  if (vr0->max == vr0->min)
-    ;
-  else if (! sop)
-    {
-      val = vrp_int_const_binop (code, vr0->max, vr1->min, &sop);
-      if (! sop)
-	{
-	  if (wi::lt_p (val, min, sgn))
-	    min = val;
-	  else if (wi::gt_p (val, max, sgn))
-	    max = val;
+	  /* If the limits are swapped, we wrapped around and cover
+	     the entire range.  We have a similar check at the end of
+	     extract_range_from_binary_expr_1.  */
+	  if (wi::gt_p (tmin, tmax, sgn))
+	    kind = VR_VARYING;
+	  else
+	    {
+	      kind = VR_RANGE;
+	      /* No overflow or both overflow or underflow.  The
+		 range kind stays VR_RANGE.  */
+	      min = wide_int_to_tree (type, tmin);
+	      max = wide_int_to_tree (type, tmax);
+	    }
+	  return;
 	}
-    }
-
-  if (vr0->min == vr0->max || vr1->min == vr1->max)
-    ;
-  else if (! sop)
-    {
-      val = vrp_int_const_binop (code, vr0->max, vr1->max, &sop);
-      if (! sop)
+      else if ((min_ovf == wi::OVF_UNDERFLOW && max_ovf == wi::OVF_NONE)
+	       || (max_ovf == wi::OVF_OVERFLOW && min_ovf == wi::OVF_NONE))
 	{
-	  if (wi::lt_p (val, min, sgn))
-	    min = val;
-	  else if (wi::gt_p (val, max, sgn))
-	    max = val;
+	  /* Min underflow or max overflow.  The range kind
+	     changes to VR_ANTI_RANGE.  */
+	  bool covers = false;
+	  wide_int tem = tmin;
+	  tmin = tmax + 1;
+	  if (wi::cmp (tmin, tmax, sgn) < 0)
+	    covers = true;
+	  tmax = tem - 1;
+	  if (wi::cmp (tmax, tem, sgn) > 0)
+	    covers = true;
+	  /* If the anti-range would cover nothing, drop to varying.
+	     Likewise if the anti-range bounds are outside of the
+	     types values.  */
+	  if (covers || wi::cmp (tmin, tmax, sgn) > 0)
+	    {
+	      kind = VR_VARYING;
+	      return;
+	    }
+	  kind = VR_ANTI_RANGE;
+	  min = wide_int_to_tree (type, tmin);
+	  max = wide_int_to_tree (type, tmax);
+	  return;
 	}
-    }
-
-  /* If either operation overflowed, drop to VARYING.  */
-  if (sop)
-    {
-      set_value_range_to_varying (vr);
-      return;
-    }
-
-  /* If the new range has its limits swapped around (MIN > MAX),
-     then the operation caused one of them to wrap around, mark
-     the new range VARYING.  */
-  if (wi::gt_p (min, max, sgn))
-    {
-      set_value_range_to_varying (vr);
-      return;
-    }
-
-  /* We punt for [-INF, +INF].
-     We learn nothing when we have INF on both sides.
-     Note that we do accept [-INF, -INF] and [+INF, +INF].  */
-  if (wi::eq_p (min, wi::min_value (TYPE_PRECISION (type), sgn))
-      && wi::eq_p (max, wi::max_value (TYPE_PRECISION (type), sgn)))
-    {
-      set_value_range_to_varying (vr);
-      return;
-    }
-
-  set_value_range (vr, rtype,
-		   wide_int_to_tree (type, min),
-		   wide_int_to_tree (type, max), NULL);
+      else
+	{
+	  /* Other underflow and/or overflow, drop to VR_VARYING.  */
+	  kind = VR_VARYING;
+	  return;
+	}
+    }
+  else
+    {
+      /* If overflow does not wrap, saturate to the types min/max
+	 value.  */
+      wide_int type_min = wi::min_value (prec, sgn);
+      wide_int type_max = wi::max_value (prec, sgn);
+      kind = VR_RANGE;
+      if (min_ovf == wi::OVF_UNDERFLOW)
+	min = wide_int_to_tree (type, type_min);
+      else if (min_ovf == wi::OVF_OVERFLOW)
+	min = wide_int_to_tree (type, type_max);
+      else
+	min = wide_int_to_tree (type, wmin);
+
+      if (max_ovf == wi::OVF_UNDERFLOW)
+	max = wide_int_to_tree (type, type_min);
+      else if (max_ovf == wi::OVF_OVERFLOW)
+	max = wide_int_to_tree (type, type_max);
+      else
+	max = wide_int_to_tree (type, wmax);
+    }
 }
 
 /* Extract range information from a binary operation CODE based on
    the ranges of each of its operands *VR0 and *VR1 with resulting
    type EXPR_TYPE.  The resulting range is stored in *VR.  */
 
-static void
+void
 extract_range_from_binary_expr_1 (value_range *vr,
 				  enum tree_code code, tree expr_type,
-				  value_range *vr0_, value_range *vr1_)
+				  const value_range *vr0_,
+				  const value_range *vr1_)
 {
+  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;
-  enum value_range_type type;
+  value_range vrtem0, vrtem1;
+  enum value_range_kind type;
   tree min = NULL_TREE, max = NULL_TREE;
   int cmp;
 
@@ -1991,7 +1474,7 @@
     }
 
   /* 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;
@@ -2000,19 +1483,16 @@
      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
+     range, but then we also need to hack up vrp_union.  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;
@@ -2020,36 +1500,35 @@
 
   /* 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.kind () == 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_);
-	  vrp_meet (vr, &vrres);
+	  value_range vrres;
+	  extract_range_from_binary_expr_1 (&vrres, code, expr_type,					    &vrtem1, vr1_);
+	  vr->union_ (&vrres);
 	}
       return;
     }
   /* Likewise for X op ~[].  */
-  if (vr1.type == VR_ANTI_RANGE
+  if (vr1.kind () == 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;
 	  extract_range_from_binary_expr_1 (&vrres, code, expr_type,
 					    vr0_, &vrtem1);
-	  vrp_meet (vr, &vrres);
+	  vr->union_ (&vrres);
 	}
       return;
     }
 
   /* The type of the resulting value range defaults to VR0.TYPE.  */
-  type = vr0.type;
+  type = vr0.kind ();
 
   /* Refuse to operate on VARYING ranges, ranges of different kinds
      and symbolic ranges.  As an exception, we allow BIT_{AND,IOR}
@@ -2071,11 +1550,12 @@
       && code != PLUS_EXPR
       && code != MINUS_EXPR
       && code != RSHIFT_EXPR
-      && (vr0.type == VR_VARYING
-	  || vr1.type == VR_VARYING
-	  || vr0.type != vr1.type
-	  || symbolic_range_p (&vr0)
-	  || symbolic_range_p (&vr1)))
+      && code != POINTER_PLUS_EXPR
+      && (vr0.varying_p ()
+	  || vr1.varying_p ()
+	  || vr0.kind () != vr1.kind ()
+	  || vr0.symbolic_p ()
+	  || vr1.symbolic_p ()))
     {
       set_value_range_to_varying (vr);
       return;
@@ -2090,7 +1570,7 @@
 	     nullness, if both are non null, then the result is nonnull.
 	     If both are null, then the result is null. Otherwise they
 	     are varying.  */
-	  if (range_is_nonnull (&vr0) && range_is_nonnull (&vr1))
+	  if (!range_includes_zero_p (&vr0) && !range_includes_zero_p (&vr1))
 	    set_value_range_to_nonnull (vr, expr_type);
 	  else if (range_is_null (&vr0) && range_is_null (&vr1))
 	    set_value_range_to_null (vr, expr_type);
@@ -2101,7 +1581,8 @@
 	{
 	  /* For pointer types, we are really only interested in asserting
 	     whether the expression evaluates to non-NULL.  */
-	  if (range_is_nonnull (&vr0) || range_is_nonnull (&vr1))
+	  if (!range_includes_zero_p (&vr0)
+	      || !range_includes_zero_p (&vr1))
 	    set_value_range_to_nonnull (vr, expr_type);
 	  else if (range_is_null (&vr0) && range_is_null (&vr1))
 	    set_value_range_to_null (vr, expr_type);
@@ -2112,7 +1593,7 @@
 	{
 	  /* For pointer types, we are really only interested in asserting
 	     whether the expression evaluates to non-NULL.  */
-	  if (range_is_nonnull (&vr0) && range_is_nonnull (&vr1))
+	  if (!range_includes_zero_p (&vr0) && !range_includes_zero_p (&vr1))
 	    set_value_range_to_nonnull (vr, expr_type);
 	  else if (range_is_null (&vr0) || range_is_null (&vr1))
 	    set_value_range_to_null (vr, expr_type);
@@ -2129,22 +1610,36 @@
      range and see what we end up with.  */
   if (code == PLUS_EXPR || code == MINUS_EXPR)
     {
+      /* 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.varying_p ())
+	vr0.update (VR_RANGE,
+		    vrp_val_min (expr_type),
+		    vrp_val_max (expr_type));
+      if (vr1.varying_p ())
+	vr1.update (VR_RANGE,
+		    vrp_val_min (expr_type),
+		    vrp_val_max (expr_type));
+
       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;
       tree sym_max_op1 = NULL_TREE;
       bool neg_min_op0, neg_min_op1, neg_max_op0, neg_max_op1;
 
+      neg_min_op0 = neg_min_op1 = neg_max_op0 = neg_max_op1 = false;
+
       /* If we have a PLUS or MINUS with two VR_RANGEs, either constant or
 	 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.kind () == VR_RANGE && vr1.kind () == VR_RANGE
 	  && (TREE_CODE (min_op0) == INTEGER_CST
 	      || (sym_min_op0
 		  = get_single_symbol (min_op0, &neg_min_op0, &min_op0)))
@@ -2164,240 +1659,41 @@
 	      || (sym_max_op0 == sym_max_op1
 		  && neg_max_op0 == (minus_p ? neg_max_op1 : !neg_max_op1))))
 	{
-	  const signop sgn = TYPE_SIGN (expr_type);
-	  const unsigned int prec = TYPE_PRECISION (expr_type);
-	  wide_int type_min, type_max, wmin, wmax;
-	  int min_ovf = 0;
-	  int max_ovf = 0;
-
-	  /* Get the lower and upper bounds of the type.  */
-	  if (TYPE_OVERFLOW_WRAPS (expr_type))
-	    {
-	      type_min = wi::min_value (prec, sgn);
-	      type_max = wi::max_value (prec, sgn);
-	    }
-	  else
-	    {
-	      type_min = wi::to_wide (vrp_val_min (expr_type));
-	      type_max = wi::to_wide (vrp_val_max (expr_type));
-	    }
-
-	  /* Combine the lower bounds, if any.  */
-	  if (min_op0 && min_op1)
-	    {
-	      if (minus_p)
-		{
-		  wmin = wi::to_wide (min_op0) - wi::to_wide (min_op1);
-
-		  /* Check for overflow.  */
-		  if (wi::cmp (0, wi::to_wide (min_op1), sgn)
-		      != wi::cmp (wmin, wi::to_wide (min_op0), sgn))
-		    min_ovf = wi::cmp (wi::to_wide (min_op0),
-				       wi::to_wide (min_op1), sgn);
-		}
-	      else
-		{
-		  wmin = wi::to_wide (min_op0) + wi::to_wide (min_op1);
-
-		  /* Check for overflow.  */
-		  if (wi::cmp (wi::to_wide (min_op1), 0, sgn)
-		      != wi::cmp (wmin, wi::to_wide (min_op0), sgn))
-		    min_ovf = wi::cmp (wi::to_wide (min_op0), wmin, sgn);
-		}
-	    }
-	  else if (min_op0)
-	    wmin = wi::to_wide (min_op0);
-	  else if (min_op1)
-	    {
-	      if (minus_p)
-		{
-		  wmin = -wi::to_wide (min_op1);
-
-		  /* Check for overflow.  */
-		  if (sgn == SIGNED
-		      && wi::neg_p (wi::to_wide (min_op1))
-		      && wi::neg_p (wmin))
-		    min_ovf = 1;
-		  else if (sgn == UNSIGNED && wi::to_wide (min_op1) != 0)
-		    min_ovf = -1;
-		}
-	      else
-		wmin = wi::to_wide (min_op1);
-	    }
-	  else
-	    wmin = wi::shwi (0, prec);
-
-	  /* Combine the upper bounds, if any.  */
-	  if (max_op0 && max_op1)
-	    {
-	      if (minus_p)
-		{
-		  wmax = wi::to_wide (max_op0) - wi::to_wide (max_op1);
-
-		  /* Check for overflow.  */
-		  if (wi::cmp (0, wi::to_wide (max_op1), sgn)
-		      != wi::cmp (wmax, wi::to_wide (max_op0), sgn))
-		    max_ovf = wi::cmp (wi::to_wide (max_op0),
-				       wi::to_wide (max_op1), sgn);
-		}
-	      else
-		{
-		  wmax = wi::to_wide (max_op0) + wi::to_wide (max_op1);
-
-		  if (wi::cmp (wi::to_wide (max_op1), 0, sgn)
-		      != wi::cmp (wmax, wi::to_wide (max_op0), sgn))
-		    max_ovf = wi::cmp (wi::to_wide (max_op0), wmax, sgn);
-		}
-	    }
-	  else if (max_op0)
-	    wmax = wi::to_wide (max_op0);
-	  else if (max_op1)
-	    {
-	      if (minus_p)
-		{
-		  wmax = -wi::to_wide (max_op1);
-
-		  /* Check for overflow.  */
-		  if (sgn == SIGNED
-		      && wi::neg_p (wi::to_wide (max_op1))
-		      && wi::neg_p (wmax))
-		    max_ovf = 1;
-		  else if (sgn == UNSIGNED && wi::to_wide (max_op1) != 0)
-		    max_ovf = -1;
-		}
-	      else
-		wmax = wi::to_wide (max_op1);
-	    }
-	  else
-	    wmax = wi::shwi (0, prec);
-
-	  /* Check for type overflow.  */
-	  if (min_ovf == 0)
-	    {
-	      if (wi::cmp (wmin, type_min, sgn) == -1)
-		min_ovf = -1;
-	      else if (wi::cmp (wmin, type_max, sgn) == 1)
-		min_ovf = 1;
-	    }
-	  if (max_ovf == 0)
-	    {
-	      if (wi::cmp (wmax, type_min, sgn) == -1)
-		max_ovf = -1;
-	      else if (wi::cmp (wmax, type_max, sgn) == 1)
-		max_ovf = 1;
-	    }
+	  wide_int wmin, wmax;
+	  wi::overflow_type min_ovf = wi::OVF_NONE;
+	  wi::overflow_type max_ovf = wi::OVF_NONE;
+
+	  /* Build the bounds.  */
+	  combine_bound (code, wmin, min_ovf, expr_type, min_op0, min_op1);
+	  combine_bound (code, wmax, max_ovf, expr_type, max_op0, max_op1);
 
 	  /* If we have overflow for the constant part and the resulting
 	     range will be symbolic, drop to VR_VARYING.  */
-	  if ((min_ovf && sym_min_op0 != sym_min_op1)
-	      || (max_ovf && sym_max_op0 != sym_max_op1))
+	  if (((bool)min_ovf && sym_min_op0 != sym_min_op1)
+	      || ((bool)max_ovf && sym_max_op0 != sym_max_op1))
 	    {
 	      set_value_range_to_varying (vr);
 	      return;
 	    }
 
-	  if (TYPE_OVERFLOW_WRAPS (expr_type))
-	    {
-	      /* If overflow wraps, truncate the values and adjust the
-		 range kind and bounds appropriately.  */
-	      wide_int tmin = wide_int::from (wmin, prec, sgn);
-	      wide_int tmax = wide_int::from (wmax, prec, sgn);
-	      if (min_ovf == max_ovf)
-		{
-		  /* No overflow or both overflow or underflow.  The
-		     range kind stays VR_RANGE.  */
-		  min = wide_int_to_tree (expr_type, tmin);
-		  max = wide_int_to_tree (expr_type, tmax);
-		}
-	      else if ((min_ovf == -1 && max_ovf == 0)
-		       || (max_ovf == 1 && min_ovf == 0))
-		{
-		  /* Min underflow or max overflow.  The range kind
-		     changes to VR_ANTI_RANGE.  */
-		  bool covers = false;
-		  wide_int tem = tmin;
-		  type = VR_ANTI_RANGE;
-		  tmin = tmax + 1;
-		  if (wi::cmp (tmin, tmax, sgn) < 0)
-		    covers = true;
-		  tmax = tem - 1;
-		  if (wi::cmp (tmax, tem, sgn) > 0)
-		    covers = true;
-		  /* If the anti-range would cover nothing, drop to varying.
-		     Likewise if the anti-range bounds are outside of the
-		     types values.  */
-		  if (covers || wi::cmp (tmin, tmax, sgn) > 0)
-		    {
-		      set_value_range_to_varying (vr);
-		      return;
-		    }
-		  min = wide_int_to_tree (expr_type, tmin);
-		  max = wide_int_to_tree (expr_type, tmax);
-		}
-	      else
-		{
-		  /* Other underflow and/or overflow, drop to VR_VARYING.  */
-		  set_value_range_to_varying (vr);
-		  return;
-		}
-	    }
-	  else
+	  /* Adjust the range for possible overflow.  */
+	  min = NULL_TREE;
+	  max = NULL_TREE;
+	  set_value_range_with_overflow (type, min, max, expr_type,
+					 wmin, wmax, min_ovf, max_ovf);
+	  if (type == VR_VARYING)
 	    {
-	      /* If overflow does not wrap, saturate to the types min/max
-	         value.  */
-	      if (min_ovf == -1)
-		min = wide_int_to_tree (expr_type, type_min);
-	      else if (min_ovf == 1)
-		min = wide_int_to_tree (expr_type, type_max);
-	      else
-		min = wide_int_to_tree (expr_type, wmin);
-
-	      if (max_ovf == -1)
-		max = wide_int_to_tree (expr_type, type_min);
-	      else if (max_ovf == 1)
-		max = wide_int_to_tree (expr_type, type_max);
-	      else
-		max = wide_int_to_tree (expr_type, wmax);
+	      set_value_range_to_varying (vr);
+	      return;
 	    }
 
-	  /* If the result lower bound is constant, we're done;
-	     otherwise, build the symbolic lower bound.  */
-	  if (sym_min_op0 == sym_min_op1)
-	    ;
-	  else if (sym_min_op0)
-	    min = build_symbolic_expr (expr_type, sym_min_op0,
-				       neg_min_op0, min);
-	  else if (sym_min_op1)
-	    {
-	      /* We may not negate if that might introduce
-		 undefined overflow.  */
-	      if (! minus_p
-		  || neg_min_op1
-		  || TYPE_OVERFLOW_WRAPS (expr_type))
-		min = build_symbolic_expr (expr_type, sym_min_op1,
-					   neg_min_op1 ^ minus_p, min);
-	      else
-		min = NULL_TREE;
-	    }
-
-	  /* Likewise for the upper bound.  */
-	  if (sym_max_op0 == sym_max_op1)
-	    ;
-	  else if (sym_max_op0)
-	    max = build_symbolic_expr (expr_type, sym_max_op0,
-				       neg_max_op0, max);
-	  else if (sym_max_op1)
-	    {
-	      /* We may not negate if that might introduce
-		 undefined overflow.  */
-	      if (! minus_p
-		  || neg_max_op1
-		  || TYPE_OVERFLOW_WRAPS (expr_type))
-		max = build_symbolic_expr (expr_type, sym_max_op1,
-					   neg_max_op1 ^ minus_p, max);
-	      else
-		max = NULL_TREE;
-	    }
+	  /* Build the symbolic bounds if needed.  */
+	  adjust_symbolic_bound (min, code, expr_type,
+				 sym_min_op0, sym_min_op1,
+				 neg_min_op0, neg_min_op1);
+	  adjust_symbolic_bound (max, code, expr_type,
+				 sym_max_op0, sym_max_op1,
+				 neg_max_op0, neg_max_op1);
 	}
       else
 	{
@@ -2420,262 +1716,66 @@
   else if (code == MIN_EXPR
 	   || code == MAX_EXPR)
     {
-      if (vr0.type == VR_RANGE
-	  && !symbolic_range_p (&vr0))
-	{
-	  type = VR_RANGE;
-	  if (vr1.type == VR_RANGE
-	      && !symbolic_range_p (&vr1))
-	    {
-	      /* For operations that make the resulting range directly
-		 proportional to the original ranges, apply the operation to
-		 the same end of each range.  */
-	      min = int_const_binop (code, vr0.min, vr1.min);
-	      max = int_const_binop (code, vr0.max, vr1.max);
-	    }
-	  else if (code == MIN_EXPR)
-	    {
-	      min = vrp_val_min (expr_type);
-	      max = vr0.max;
-	    }
-	  else if (code == MAX_EXPR)
-	    {
-	      min = vr0.min;
-	      max = vrp_val_max (expr_type);
-	    }
-	}
-      else if (vr1.type == VR_RANGE
-	       && !symbolic_range_p (&vr1))
-	{
-	  type = VR_RANGE;
-	  if (code == MIN_EXPR)
-	    {
-	      min = vrp_val_min (expr_type);
-	      max = vr1.max;
-	    }
-	  else if (code == MAX_EXPR)
-	    {
-	      min = vr1.min;
-	      max = vrp_val_max (expr_type);
-	    }
-	}
+      wide_int wmin, wmax;
+      wide_int vr0_min, vr0_max;
+      wide_int vr1_min, vr1_max;
+      extract_range_into_wide_ints (&vr0, sign, prec, vr0_min, vr0_max);
+      extract_range_into_wide_ints (&vr1, sign, prec, vr1_min, vr1_max);
+      if (wide_int_range_min_max (wmin, wmax, code, sign, prec,
+				  vr0_min, vr0_max, vr1_min, vr1_max))
+	vr->update (VR_RANGE, wide_int_to_tree (expr_type, wmin),
+		    wide_int_to_tree (expr_type, wmax));
       else
-	{
-	  set_value_range_to_varying (vr);
-	  return;
-	}
+	set_value_range_to_varying (vr);
+      return;
     }
   else if (code == MULT_EXPR)
     {
-      /* Fancy code so that with unsigned, [-3,-1]*[-3,-1] does not
-	 drop to varying.  This test requires 2*prec bits if both
-	 operands are signed and 2*prec + 2 bits if either is not.  */
-
-      signop sign = TYPE_SIGN (expr_type);
-      unsigned int prec = TYPE_PRECISION (expr_type);
-
       if (!range_int_cst_p (&vr0)
 	  || !range_int_cst_p (&vr1))
 	{
 	  set_value_range_to_varying (vr);
 	  return;
 	}
-
-      if (TYPE_OVERFLOW_WRAPS (expr_type))
-	{
-	  typedef FIXED_WIDE_INT (WIDE_INT_MAX_PRECISION * 2) vrp_int;
-	  typedef generic_wide_int
-             <wi::extended_tree <WIDE_INT_MAX_PRECISION * 2> > vrp_int_cst;
-	  vrp_int sizem1 = wi::mask <vrp_int> (prec, false);
-	  vrp_int size = sizem1 + 1;
-
-	  /* Extend the values using the sign of the result to PREC2.
-	     From here on out, everthing is just signed math no matter
-	     what the input types were.  */
-          vrp_int min0 = vrp_int_cst (vr0.min);
-          vrp_int max0 = vrp_int_cst (vr0.max);
-          vrp_int min1 = vrp_int_cst (vr1.min);
-          vrp_int max1 = vrp_int_cst (vr1.max);
-	  /* Canonicalize the intervals.  */
-	  if (sign == UNSIGNED)
-	    {
-	      if (wi::ltu_p (size, min0 + max0))
-		{
-		  min0 -= size;
-		  max0 -= size;
-		}
-
-	      if (wi::ltu_p (size, min1 + max1))
-		{
-		  min1 -= size;
-		  max1 -= size;
-		}
-	    }
-
-	  vrp_int prod0 = min0 * min1;
-	  vrp_int prod1 = min0 * max1;
-	  vrp_int prod2 = max0 * min1;
-	  vrp_int prod3 = max0 * max1;
-
-	  /* Sort the 4 products so that min is in prod0 and max is in
-	     prod3.  */
-	  /* min0min1 > max0max1 */
-	  if (prod0 > prod3)
-	    std::swap (prod0, prod3);
-
-	  /* min0max1 > max0min1 */
-	  if (prod1 > prod2)
-	    std::swap (prod1, prod2);
-
-	  if (prod0 > prod1)
-	    std::swap (prod0, prod1);
-
-	  if (prod2 > prod3)
-	    std::swap (prod2, prod3);
-
-	  /* diff = max - min.  */
-	  prod2 = prod3 - prod0;
-	  if (wi::geu_p (prod2, sizem1))
-	    {
-	      /* the range covers all values.  */
-	      set_value_range_to_varying (vr);
-	      return;
-	    }
-
-	  /* The following should handle the wrapping and selecting
-	     VR_ANTI_RANGE for us.  */
-	  min = wide_int_to_tree (expr_type, prod0);
-	  max = wide_int_to_tree (expr_type, prod3);
-	  set_and_canonicalize_value_range (vr, VR_RANGE, min, max, NULL);
-	  return;
-	}
-
-      /* If we have an unsigned MULT_EXPR with two VR_ANTI_RANGEs,
-	 drop to VR_VARYING.  It would take more effort to compute a
-	 precise range for such a case.  For example, if we have
-	 op0 == 65536 and op1 == 65536 with their ranges both being
-	 ~[0,0] on a 32-bit machine, we would have op0 * op1 == 0, so
-	 we cannot claim that the product is in ~[0,0].  Note that we
-	 are guaranteed to have vr0.type == vr1.type at this
-	 point.  */
-      if (vr0.type == VR_ANTI_RANGE
-	  && !TYPE_OVERFLOW_UNDEFINED (expr_type))
-	{
-	  set_value_range_to_varying (vr);
-	  return;
-	}
-
-      extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
+      extract_range_from_multiplicative_op (vr, code, &vr0, &vr1);
       return;
     }
   else if (code == RSHIFT_EXPR
 	   || code == LSHIFT_EXPR)
     {
-      /* If we have a RSHIFT_EXPR with any shift values outside [0..prec-1],
-	 then drop to VR_VARYING.  Outside of this range we get undefined
-	 behavior from the shift operation.  We cannot even trust
-	 SHIFT_COUNT_TRUNCATED at this stage, because that applies to rtl
-	 shifts, and the operation at the tree level may be widened.  */
       if (range_int_cst_p (&vr1)
-	  && compare_tree_int (vr1.min, 0) >= 0
-	  && compare_tree_int (vr1.max, TYPE_PRECISION (expr_type)) == -1)
+	  && !wide_int_range_shift_undefined_p
+		(TYPE_SIGN (TREE_TYPE (vr1.min ())),
+		 prec,
+		 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))
-		{
-		  vr0.type = type = VR_RANGE;
-		  vr0.min = vrp_val_min (expr_type);
-		  vr0.max = vrp_val_max (expr_type);
-		}
-	      extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
-	      return;
-	    }
-	  /* We can map lshifts by constants to MULT_EXPR handling.  */
-	  else if (code == LSHIFT_EXPR
-		   && range_int_cst_singleton_p (&vr1))
-	    {
-	      bool saved_flag_wrapv;
-	      value_range vr1p = VR_INITIALIZER;
-	      vr1p.type = VR_RANGE;
-	      vr1p.min = (wide_int_to_tree
-			  (expr_type,
-			   wi::set_bit_in_zero (tree_to_shwi (vr1.min),
-						TYPE_PRECISION (expr_type))));
-	      vr1p.max = vr1p.min;
-	      /* We have to use a wrapping multiply though as signed overflow
-		 on lshifts is implementation defined in C89.  */
-	      saved_flag_wrapv = flag_wrapv;
-	      flag_wrapv = 1;
-	      extract_range_from_binary_expr_1 (vr, MULT_EXPR, expr_type,
-						&vr0, &vr1p);
-	      flag_wrapv = saved_flag_wrapv;
+	      if (vr0.kind () != VR_RANGE || vr0.symbolic_p ())
+		vr0.update (VR_RANGE,
+			    vrp_val_min (expr_type),
+			    vrp_val_max (expr_type));
+	      extract_range_from_multiplicative_op (vr, code, &vr0, &vr1);
 	      return;
 	    }
 	  else if (code == LSHIFT_EXPR
 		   && range_int_cst_p (&vr0))
 	    {
-	      int prec = TYPE_PRECISION (expr_type);
-	      int overflow_pos = prec;
-	      int bound_shift;
-	      wide_int low_bound, high_bound;
-	      bool uns = TYPE_UNSIGNED (expr_type);
-	      bool in_bounds = false;
-
-	      if (!uns)
-		overflow_pos -= 1;
-
-	      bound_shift = overflow_pos - tree_to_shwi (vr1.max);
-	      /* If bound_shift == HOST_BITS_PER_WIDE_INT, the llshift can
-		 overflow.  However, for that to happen, vr1.max needs to be
-		 zero, which means vr1 is a singleton range of zero, which
-		 means it should be handled by the previous LSHIFT_EXPR
-		 if-clause.  */
-	      wide_int bound = wi::set_bit_in_zero (bound_shift, prec);
-	      wide_int complement = ~(bound - 1);
-
-	      if (uns)
+	      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 ()),
+					 TYPE_OVERFLOW_UNDEFINED (expr_type)))
 		{
-		  low_bound = bound;
-		  high_bound = complement;
-		  if (wi::ltu_p (wi::to_wide (vr0.max), low_bound))
-		    {
-		      /* [5, 6] << [1, 2] == [10, 24].  */
-		      /* We're shifting out only zeroes, the value increases
-			 monotonically.  */
-		      in_bounds = true;
-		    }
-		  else if (wi::ltu_p (high_bound, wi::to_wide (vr0.min)))
-		    {
-		      /* [0xffffff00, 0xffffffff] << [1, 2]
-		         == [0xfffffc00, 0xfffffffe].  */
-		      /* We're shifting out only ones, the value decreases
-			 monotonically.  */
-		      in_bounds = true;
-		    }
-		}
-	      else
-		{
-		  /* [-1, 1] << [1, 2] == [-4, 4].  */
-		  low_bound = complement;
-		  high_bound = bound;
-		  if (wi::lts_p (wi::to_wide (vr0.max), high_bound)
-		      && wi::lts_p (low_bound, wi::to_wide (vr0.min)))
-		    {
-		      /* For non-negative numbers, we're shifting out only
-			 zeroes, the value increases monotonically.
-			 For negative numbers, we're shifting out only ones, the
-			 value decreases monotomically.  */
-		      in_bounds = true;
-		    }
-		}
-
-	      if (in_bounds)
-		{
-		  extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
+		  min = wide_int_to_tree (expr_type, res_lb);
+		  max = wide_int_to_tree (expr_type, res_ub);
+		  vr->set_and_canonicalize (VR_RANGE, min, max, NULL);
 		  return;
 		}
 	    }
@@ -2689,109 +1789,49 @@
 	   || code == EXACT_DIV_EXPR
 	   || code == ROUND_DIV_EXPR)
     {
-      if (vr0.type != VR_RANGE || symbolic_range_p (&vr0))
+      wide_int dividend_min, dividend_max, divisor_min, divisor_max;
+      wide_int wmin, wmax, extra_min, extra_max;
+      bool extra_range_p;
+
+      /* Special case explicit division by zero as undefined.  */
+      if (range_is_null (&vr1))
 	{
-	  /* For division, if op1 has VR_RANGE but op0 does not, something
-	     can be deduced just from that range.  Say [min, max] / [4, max]
-	     gives [min / 4, max / 4] range.  */
-	  if (vr1.type == VR_RANGE
-	      && !symbolic_range_p (&vr1)
-	      && range_includes_zero_p (vr1.min, vr1.max) == 0)
-	    {
-	      vr0.type = type = VR_RANGE;
-	      vr0.min = vrp_val_min (expr_type);
-	      vr0.max = vrp_val_max (expr_type);
-	    }
-	  else
-	    {
-	      set_value_range_to_varying (vr);
-	      return;
-	    }
+	  set_value_range_to_undefined (vr);
+	  return;
 	}
 
-      /* For divisions, if flag_non_call_exceptions is true, we must
-	 not eliminate a division by zero.  */
-      if (cfun->can_throw_non_call_exceptions
-	  && (vr1.type != VR_RANGE
-	      || range_includes_zero_p (vr1.min, vr1.max) != 0))
+      /* First, normalize ranges into constants we can handle.  Note
+	 that VR_ANTI_RANGE's of constants were already normalized
+	 before arriving here.
+
+	 NOTE: As a future improvement, we may be able to do better
+	 with mixed symbolic (anti-)ranges like [0, A].  See note in
+	 ranges_from_anti_range.  */
+      extract_range_into_wide_ints (&vr0, sign, prec,
+				    dividend_min, dividend_max);
+      extract_range_into_wide_ints (&vr1, sign, prec,
+				    divisor_min, divisor_max);
+      if (!wide_int_range_div (wmin, wmax, code, sign, prec,
+			       dividend_min, dividend_max,
+			       divisor_min, divisor_max,
+			       TYPE_OVERFLOW_UNDEFINED (expr_type),
+			       extra_range_p, extra_min, extra_max))
 	{
 	  set_value_range_to_varying (vr);
 	  return;
 	}
-
-      /* For divisions, if op0 is VR_RANGE, we can deduce a range
-	 even if op1 is VR_VARYING, VR_ANTI_RANGE, symbolic or can
-	 include 0.  */
-      if (vr0.type == VR_RANGE
-	  && (vr1.type != VR_RANGE
-	      || range_includes_zero_p (vr1.min, vr1.max) != 0))
+      set_value_range (vr, VR_RANGE,
+		       wide_int_to_tree (expr_type, wmin),
+		       wide_int_to_tree (expr_type, wmax), NULL);
+      if (extra_range_p)
 	{
-	  tree zero = build_int_cst (TREE_TYPE (vr0.min), 0);
-	  int cmp;
-
-	  min = NULL_TREE;
-	  max = NULL_TREE;
-	  if (TYPE_UNSIGNED (expr_type)
-	      || value_range_nonnegative_p (&vr1))
-	    {
-	      /* For unsigned division or when divisor is known
-		 to be non-negative, the range has to cover
-		 all numbers from 0 to max for positive max
-		 and all numbers from min to 0 for negative min.  */
-	      cmp = compare_values (vr0.max, zero);
-	      if (cmp == -1)
-		{
-		  /* When vr0.max < 0, vr1.min != 0 and value
-		     ranges for dividend and divisor are available.  */
-		  if (vr1.type == VR_RANGE
-		      && !symbolic_range_p (&vr0)
-		      && !symbolic_range_p (&vr1)
-		      && compare_values (vr1.min, zero) != 0)
-		    max = int_const_binop (code, vr0.max, vr1.min);
-		  else
-		    max = zero;
-		}
-	      else if (cmp == 0 || cmp == 1)
-		max = vr0.max;
-	      else
-		type = VR_VARYING;
-	      cmp = compare_values (vr0.min, zero);
-	      if (cmp == 1)
-		{
-		  /* For unsigned division when value ranges for dividend
-		     and divisor are available.  */
-		  if (vr1.type == VR_RANGE
-		      && !symbolic_range_p (&vr0)
-		      && !symbolic_range_p (&vr1)
-		      && compare_values (vr1.max, zero) != 0)
-		    min = int_const_binop (code, vr0.min, vr1.max);
-		  else
-		    min = zero;
-		}
-	      else if (cmp == 0 || cmp == -1)
-		min = vr0.min;
-	      else
-		type = VR_VARYING;
-	    }
-	  else
-	    {
-	      /* Otherwise the range is -max .. max or min .. -min
-		 depending on which bound is bigger in absolute value,
-		 as the division can change the sign.  */
-	      abs_extent_range (vr, vr0.min, vr0.max);
-	      return;
-	    }
-	  if (type == VR_VARYING)
-	    {
-	      set_value_range_to_varying (vr);
-	      return;
-	    }
+	  value_range extra_range;
+	  set_value_range (&extra_range, VR_RANGE,
+			   wide_int_to_tree (expr_type, extra_min),
+			   wide_int_to_tree (expr_type, extra_max), NULL);
+	  vr->union_ (&extra_range);
 	}
-      else if (!symbolic_range_p (&vr0) && !symbolic_range_p (&vr1))
-	{
-	  extract_range_from_multiplicative_op_1 (vr, code, &vr0, &vr1);
-	  return;
-	}
+      return;
     }
   else if (code == TRUNC_MOD_EXPR)
     {
@@ -2800,212 +1840,80 @@
 	  set_value_range_to_undefined (vr);
 	  return;
 	}
-      /* ABS (A % B) < ABS (B) and either
-	 0 <= A % B <= A or A <= A % B <= 0.  */
-      type = VR_RANGE;
-      signop sgn = TYPE_SIGN (expr_type);
-      unsigned int prec = TYPE_PRECISION (expr_type);
       wide_int wmin, wmax, tmp;
-      if (vr1.type == VR_RANGE && !symbolic_range_p (&vr1))
-	{
-	  wmax = wi::to_wide (vr1.max) - 1;
-	  if (sgn == SIGNED)
-	    {
-	      tmp = -1 - wi::to_wide (vr1.min);
-	      wmax = wi::smax (wmax, tmp);
-	    }
-	}
-      else
-	{
-	  wmax = wi::max_value (prec, sgn);
-	  /* X % INT_MIN may be INT_MAX.  */
-	  if (sgn == UNSIGNED)
-	    wmax = wmax - 1;
-	}
-
-      if (sgn == UNSIGNED)
-	wmin = wi::zero (prec);
-      else
-	{
-	  wmin = -wmax;
-	  if (vr0.type == VR_RANGE && TREE_CODE (vr0.min) == INTEGER_CST)
-	    {
-	      tmp = wi::to_wide (vr0.min);
-	      if (wi::gts_p (tmp, 0))
-		tmp = wi::zero (prec);
-	      wmin = wi::smax (wmin, tmp);
-	    }
-	}
-
-      if (vr0.type == VR_RANGE && TREE_CODE (vr0.max) == INTEGER_CST)
-	{
-	  tmp = wi::to_wide (vr0.max);
-	  if (sgn == SIGNED && wi::neg_p (tmp))
-	    tmp = wi::zero (prec);
-	  wmax = wi::min (wmax, tmp, sgn);
-	}
-
+      wide_int vr0_min, vr0_max, vr1_min, vr1_max;
+      extract_range_into_wide_ints (&vr0, sign, prec, vr0_min, vr0_max);
+      extract_range_into_wide_ints (&vr1, sign, prec, vr1_min, vr1_max);
+      wide_int_range_trunc_mod (wmin, wmax, sign, prec,
+				vr0_min, vr0_max, vr1_min, vr1_max);
       min = wide_int_to_tree (expr_type, wmin);
       max = wide_int_to_tree (expr_type, wmax);
+      set_value_range (vr, VR_RANGE, min, max, NULL);
+      return;
     }
   else if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR || code == BIT_XOR_EXPR)
     {
-      bool int_cst_range0, int_cst_range1;
       wide_int may_be_nonzero0, may_be_nonzero1;
       wide_int must_be_nonzero0, must_be_nonzero1;
-
-      int_cst_range0 = zero_nonzero_bits_from_vr (expr_type, &vr0,
-						  &may_be_nonzero0,
-						  &must_be_nonzero0);
-      int_cst_range1 = zero_nonzero_bits_from_vr (expr_type, &vr1,
-						  &may_be_nonzero1,
-						  &must_be_nonzero1);
-
-      if (code == BIT_AND_EXPR || code == BIT_IOR_EXPR)
+      wide_int wmin, wmax;
+      wide_int vr0_min, vr0_max, vr1_min, vr1_max;
+      vrp_set_zero_nonzero_bits (expr_type, &vr0,
+				 &may_be_nonzero0, &must_be_nonzero0);
+      vrp_set_zero_nonzero_bits (expr_type, &vr1,
+				 &may_be_nonzero1, &must_be_nonzero1);
+      extract_range_into_wide_ints (&vr0, sign, prec, vr0_min, vr0_max);
+      extract_range_into_wide_ints (&vr1, sign, prec, vr1_min, vr1_max);
+      if (code == BIT_AND_EXPR)
 	{
-	  value_range *vr0p = NULL, *vr1p = NULL;
-	  if (range_int_cst_singleton_p (&vr1))
-	    {
-	      vr0p = &vr0;
-	      vr1p = &vr1;
-	    }
-	  else if (range_int_cst_singleton_p (&vr0))
-	    {
-	      vr0p = &vr1;
-	      vr1p = &vr0;
-	    }
-	  /* For op & or | attempt to optimize:
-	     [x, y] op z into [x op z, y op z]
-	     if z is a constant which (for op | its bitwise not) has n
-	     consecutive least significant bits cleared followed by m 1
-	     consecutive bits set immediately above it and either
-	     m + n == precision, or (x >> (m + n)) == (y >> (m + n)).
-	     The least significant n bits of all the values in the range are
-	     cleared or set, the m bits above it are preserved and any bits
-	     above these are required to be the same for all values in the
-	     range.  */
-	  if (vr0p && range_int_cst_p (vr0p))
+	  if (wide_int_range_bit_and (wmin, wmax, sign, prec,
+				      vr0_min, vr0_max,
+				      vr1_min, vr1_max,
+				      must_be_nonzero0,
+				      may_be_nonzero0,
+				      must_be_nonzero1,
+				      may_be_nonzero1))
 	    {
-	      wide_int w = wi::to_wide (vr1p->min);
-	      int m = 0, n = 0;
-	      if (code == BIT_IOR_EXPR)
-		w = ~w;
-	      if (wi::eq_p (w, 0))
-		n = TYPE_PRECISION (expr_type);
-	      else
-		{
-		  n = wi::ctz (w);
-		  w = ~(w | wi::mask (n, false, w.get_precision ()));
-		  if (wi::eq_p (w, 0))
-		    m = TYPE_PRECISION (expr_type) - n;
-		  else
-		    m = wi::ctz (w) - n;
-		}
-	      wide_int mask = wi::mask (m + n, true, w.get_precision ());
-	      if ((mask & wi::to_wide (vr0p->min))
-		  == (mask & wi::to_wide (vr0p->max)))
-		{
-		  min = int_const_binop (code, vr0p->min, vr1p->min);
-		  max = int_const_binop (code, vr0p->max, vr1p->min);
-		}
+	      min = wide_int_to_tree (expr_type, wmin);
+	      max = wide_int_to_tree (expr_type, wmax);
+	      set_value_range (vr, VR_RANGE, min, max, NULL);
 	    }
-	}
-
-      type = VR_RANGE;
-      if (min && max)
-	/* Optimized above already.  */;
-      else if (code == BIT_AND_EXPR)
-	{
-	  min = wide_int_to_tree (expr_type,
-				  must_be_nonzero0 & must_be_nonzero1);
-	  wide_int wmax = may_be_nonzero0 & may_be_nonzero1;
-	  /* If both input ranges contain only negative values we can
-	     truncate the result range maximum to the minimum of the
-	     input range maxima.  */
-	  if (int_cst_range0 && int_cst_range1
-	      && tree_int_cst_sgn (vr0.max) < 0
-	      && tree_int_cst_sgn (vr1.max) < 0)
-	    {
-	      wmax = wi::min (wmax, wi::to_wide (vr0.max),
-			      TYPE_SIGN (expr_type));
-	      wmax = wi::min (wmax, wi::to_wide (vr1.max),
-			      TYPE_SIGN (expr_type));
-	    }
-	  /* If either input range contains only non-negative values
-	     we can truncate the result range maximum to the respective
-	     maximum of the input range.  */
-	  if (int_cst_range0 && tree_int_cst_sgn (vr0.min) >= 0)
-	    wmax = wi::min (wmax, wi::to_wide (vr0.max),
-			    TYPE_SIGN (expr_type));
-	  if (int_cst_range1 && tree_int_cst_sgn (vr1.min) >= 0)
-	    wmax = wi::min (wmax, wi::to_wide (vr1.max),
-			    TYPE_SIGN (expr_type));
-	  max = wide_int_to_tree (expr_type, wmax);
-	  cmp = compare_values (min, max);
-	  /* PR68217: In case of signed & sign-bit-CST should
-	     result in [-INF, 0] instead of [-INF, INF].  */
-	  if (cmp == -2 || cmp == 1)
-	    {
-	      wide_int sign_bit
-		= wi::set_bit_in_zero (TYPE_PRECISION (expr_type) - 1,
-				       TYPE_PRECISION (expr_type));
-	      if (!TYPE_UNSIGNED (expr_type)
-		  && ((int_cst_range0
-		       && value_range_constant_singleton (&vr0)
-		       && !wi::cmps (wi::to_wide (vr0.min), sign_bit))
-		      || (int_cst_range1
-			  && value_range_constant_singleton (&vr1)
-			  && !wi::cmps (wi::to_wide (vr1.min), sign_bit))))
-		{
-		  min = TYPE_MIN_VALUE (expr_type);
-		  max = build_int_cst (expr_type, 0);
-		}
-	    }
+	  else
+	    set_value_range_to_varying (vr);
+	  return;
 	}
       else if (code == BIT_IOR_EXPR)
 	{
-	  max = wide_int_to_tree (expr_type,
-				  may_be_nonzero0 | may_be_nonzero1);
-	  wide_int wmin = must_be_nonzero0 | must_be_nonzero1;
-	  /* If the input ranges contain only positive values we can
-	     truncate the minimum of the result range to the maximum
-	     of the input range minima.  */
-	  if (int_cst_range0 && int_cst_range1
-	      && tree_int_cst_sgn (vr0.min) >= 0
-	      && tree_int_cst_sgn (vr1.min) >= 0)
+	  if (wide_int_range_bit_ior (wmin, wmax, sign,
+				      vr0_min, vr0_max,
+				      vr1_min, vr1_max,
+				      must_be_nonzero0,
+				      may_be_nonzero0,
+				      must_be_nonzero1,
+				      may_be_nonzero1))
 	    {
-	      wmin = wi::max (wmin, wi::to_wide (vr0.min),
-			      TYPE_SIGN (expr_type));
-	      wmin = wi::max (wmin, wi::to_wide (vr1.min),
-			      TYPE_SIGN (expr_type));
+	      min = wide_int_to_tree (expr_type, wmin);
+	      max = wide_int_to_tree (expr_type, wmax);
+	      set_value_range (vr, VR_RANGE, min, max, NULL);
 	    }
-	  /* If either input range contains only negative values
-	     we can truncate the minimum of the result range to the
-	     respective minimum range.  */
-	  if (int_cst_range0 && tree_int_cst_sgn (vr0.max) < 0)
-	    wmin = wi::max (wmin, wi::to_wide (vr0.min),
-			    TYPE_SIGN (expr_type));
-	  if (int_cst_range1 && tree_int_cst_sgn (vr1.max) < 0)
-	    wmin = wi::max (wmin, wi::to_wide (vr1.min),
-			    TYPE_SIGN (expr_type));
-	  min = wide_int_to_tree (expr_type, wmin);
+	  else
+	    set_value_range_to_varying (vr);
+	  return;
 	}
       else if (code == BIT_XOR_EXPR)
 	{
-	  wide_int result_zero_bits = ((must_be_nonzero0 & must_be_nonzero1)
-				       | ~(may_be_nonzero0 | may_be_nonzero1));
-	  wide_int result_one_bits
-	    = (wi::bit_and_not (must_be_nonzero0, may_be_nonzero1)
-	       | wi::bit_and_not (must_be_nonzero1, may_be_nonzero0));
-	  max = wide_int_to_tree (expr_type, ~result_zero_bits);
-	  min = wide_int_to_tree (expr_type, result_one_bits);
-	  /* If the range has all positive or all negative values the
-	     result is better than VARYING.  */
-	  if (tree_int_cst_sgn (min) < 0
-	      || tree_int_cst_sgn (max) >= 0)
-	    ;
+	  if (wide_int_range_bit_xor (wmin, wmax, sign, prec,
+				      must_be_nonzero0,
+				      may_be_nonzero0,
+				      must_be_nonzero1,
+				      may_be_nonzero1))
+	    {
+	      min = wide_int_to_tree (expr_type, wmin);
+	      max = wide_int_to_tree (expr_type, wmax);
+	      set_value_range (vr, VR_RANGE, min, max, NULL);
+	    }
 	  else
-	    max = min = NULL_TREE;
+	    set_value_range_to_varying (vr);
+	  return;
 	}
     }
   else
@@ -3043,105 +1951,6 @@
     set_value_range (vr, type, min, max, NULL);
 }
 
-/* Extract range information from a binary expression OP0 CODE OP1 based on
-   the ranges of each of its operands with resulting type EXPR_TYPE.
-   The resulting range is stored in *VR.  */
-
-static void
-extract_range_from_binary_expr (value_range *vr,
-				enum tree_code code,
-				tree expr_type, tree op0, tree op1)
-{
-  value_range vr0 = VR_INITIALIZER;
-  value_range vr1 = VR_INITIALIZER;
-
-  /* Get value ranges for each operand.  For constant operands, create
-     a new value range with the operand to simplify processing.  */
-  if (TREE_CODE (op0) == SSA_NAME)
-    vr0 = *(get_value_range (op0));
-  else if (is_gimple_min_invariant (op0))
-    set_value_range_to_value (&vr0, op0, NULL);
-  else
-    set_value_range_to_varying (&vr0);
-
-  if (TREE_CODE (op1) == SSA_NAME)
-    vr1 = *(get_value_range (op1));
-  else if (is_gimple_min_invariant (op1))
-    set_value_range_to_value (&vr1, op1, NULL);
-  else
-    set_value_range_to_varying (&vr1);
-
-  extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &vr1);
-
-  /* Try harder for PLUS and MINUS if the range of one operand is symbolic
-     and based on the other operand, for example if it was deduced from a
-     symbolic comparison.  When a bound of the range of the first operand
-     is invariant, we set the corresponding bound of the new range to INF
-     in order to avoid recursing on the range of the second operand.  */
-  if (vr->type == VR_VARYING
-      && (code == PLUS_EXPR || code == MINUS_EXPR)
-      && TREE_CODE (op1) == SSA_NAME
-      && vr0.type == VR_RANGE
-      && symbolic_range_based_on_p (&vr0, op1))
-    {
-      const bool minus_p = (code == MINUS_EXPR);
-      value_range n_vr1 = VR_INITIALIZER;
-
-      /* Try with VR0 and [-INF, OP1].  */
-      if (is_gimple_min_invariant (minus_p ? vr0.max : vr0.min))
-	set_value_range (&n_vr1, VR_RANGE, vrp_val_min (expr_type), op1, NULL);
-
-      /* Try with VR0 and [OP1, +INF].  */
-      else if (is_gimple_min_invariant (minus_p ? vr0.min : vr0.max))
-	set_value_range (&n_vr1, VR_RANGE, op1, vrp_val_max (expr_type), NULL);
-
-      /* Try with VR0 and [OP1, OP1].  */
-      else
-	set_value_range (&n_vr1, VR_RANGE, op1, op1, NULL);
-
-      extract_range_from_binary_expr_1 (vr, code, expr_type, &vr0, &n_vr1);
-    }
-
-  if (vr->type == VR_VARYING
-      && (code == PLUS_EXPR || code == MINUS_EXPR)
-      && TREE_CODE (op0) == SSA_NAME
-      && vr1.type == VR_RANGE
-      && symbolic_range_based_on_p (&vr1, op0))
-    {
-      const bool minus_p = (code == MINUS_EXPR);
-      value_range n_vr0 = VR_INITIALIZER;
-
-      /* Try with [-INF, OP0] and VR1.  */
-      if (is_gimple_min_invariant (minus_p ? vr1.max : vr1.min))
-	set_value_range (&n_vr0, VR_RANGE, vrp_val_min (expr_type), op0, NULL);
-
-      /* Try with [OP0, +INF] and VR1.  */
-      else if (is_gimple_min_invariant (minus_p ? vr1.min : vr1.max))
-	set_value_range (&n_vr0, VR_RANGE, op0, vrp_val_max (expr_type), NULL);
-
-      /* Try with [OP0, OP0] and VR1.  */
-      else
-	set_value_range (&n_vr0, VR_RANGE, op0, op0, NULL);
-
-      extract_range_from_binary_expr_1 (vr, code, expr_type, &n_vr0, &vr1);
-    }
-
-  /* If we didn't derive a range for MINUS_EXPR, and
-     op1's range is ~[op0,op0] or vice-versa, then we
-     can derive a non-null range.  This happens often for
-     pointer subtraction.  */
-  if (vr->type == VR_VARYING
-      && code == MINUS_EXPR
-      && TREE_CODE (op0) == SSA_NAME
-      && ((vr0.type == VR_ANTI_RANGE
-	   && vr0.min == op1
-	   && vr0.min == vr0.max)
-	  || (vr1.type == VR_ANTI_RANGE
-	      && vr1.min == op0
-	      && vr1.min == vr1.max)))
-      set_value_range_to_nonnull (vr, TREE_TYPE (op0));
-}
-
 /* Extract range information from a unary operation CODE based on
    the range of its operand *VR0 with type OP0_TYPE with resulting type TYPE.
    The resulting range is stored in *VR.  */
@@ -3149,9 +1958,12 @@
 void
 extract_range_from_unary_expr (value_range *vr,
 			       enum tree_code code, tree type,
-			       value_range *vr0_, tree op0_type)
+			       const value_range *vr0_, tree op0_type)
 {
-  value_range vr0 = *vr0_, vrtem0 = VR_INITIALIZER, vrtem1 = VR_INITIALIZER;
+  signop sign = TYPE_SIGN (type);
+  unsigned int prec = TYPE_PRECISION (type);
+  value_range vr0 = *vr0_;
+  value_range vrtem0, vrtem1;
 
   /* VRP only operates on integral and pointer types.  */
   if (!(INTEGRAL_TYPE_P (op0_type)
@@ -3164,7 +1976,7 @@
     }
 
   /* If VR0 is UNDEFINED, so is the result.  */
-  if (vr0.type == VR_UNDEFINED)
+  if (vr0.undefined_p ())
     {
       set_value_range_to_undefined (vr);
       return;
@@ -3174,14 +1986,14 @@
   if (code == PAREN_EXPR || code == OBJ_TYPE_REF)
     {
       /* PAREN_EXPR and OBJ_TYPE_REF are simple copies.  */
-      copy_value_range (vr, &vr0);
+      vr->deep_copy (&vr0);
       return;
     }
   else if (code == NEGATE_EXPR)
     {
       /* -X is simply 0 - X, so re-use existing code that also handles
          anti-ranges fine.  */
-      value_range zero = VR_INITIALIZER;
+      value_range zero;
       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;
@@ -3190,7 +2002,7 @@
     {
       /* ~X is simply -1 - X, so re-use existing code that also handles
          anti-ranges fine.  */
-      value_range minusone = VR_INITIALIZER;
+      value_range minusone;
       set_value_range_to_value (&minusone, build_int_cst (type, -1), NULL);
       extract_range_from_binary_expr_1 (vr, MINUS_EXPR,
 					type, &minusone, &vr0);
@@ -3199,16 +2011,16 @@
 
   /* 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.kind () == 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;
 	  extract_range_from_unary_expr (&vrres, code, type,
 					 &vrtem1, op0_type);
-	  vrp_meet (vr, &vrres);
+	  vr->union_ (&vrres);
 	}
       return;
     }
@@ -3218,11 +2030,16 @@
       tree inner_type = op0_type;
       tree outer_type = type;
 
-      /* If the expression evaluates to a pointer, we are only interested in
-	 determining if it evaluates to NULL [0, 0] or non-NULL (~[0, 0]).  */
-      if (POINTER_TYPE_P (type))
+      /* If the expression involves a pointer, we are only interested in
+	 determining if it evaluates to NULL [0, 0] or non-NULL (~[0, 0]).
+
+	 This may lose precision when converting (char *)~[0,2] to
+	 int, because we'll forget that the pointer can also not be 1
+	 or 2.  In practice we don't care, as this is some idiot
+	 storing a magic constant to a pointer.  */
+      if (POINTER_TYPE_P (type) || POINTER_TYPE_P (op0_type))
 	{
-	  if (range_is_nonnull (&vr0))
+	  if (!range_includes_zero_p (&vr0))
 	    set_value_range_to_nonnull (vr, type);
 	  else if (range_is_null (&vr0))
 	    set_value_range_to_null (vr, type);
@@ -3231,156 +2048,52 @@
 	  return;
 	}
 
-      /* If VR0 is varying and we increase the type precision, assume
-	 a full range for the following transformation.  */
-      if (vr0.type == VR_VARYING
-	  && INTEGRAL_TYPE_P (inner_type)
-	  && TYPE_PRECISION (inner_type) < TYPE_PRECISION (outer_type))
+      /* The POINTER_TYPE_P code above will have dealt with all
+	 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.kind () != 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
+	 example, converting [SYM, SYM] from INT to LONG UNSIGNED,
+	 we can return: ~[0x8000000, 0xffffffff7fffffff].
+
+	 We were also failing to convert ~[0,0] from char* to unsigned,
+	 instead choosing to return VR_VARYING.  Now we return ~[0,0].  */
+      wide_int vr0_min, vr0_max, wmin, wmax;
+      signop inner_sign = TYPE_SIGN (inner_type);
+      signop outer_sign = TYPE_SIGN (outer_type);
+      unsigned inner_prec = TYPE_PRECISION (inner_type);
+      unsigned outer_prec = TYPE_PRECISION (outer_type);
+      extract_range_into_wide_ints (&vr0, inner_sign, inner_prec,
+				    vr0_min, vr0_max);
+      if (wide_int_range_convert (wmin, wmax,
+				  inner_sign, inner_prec,
+				  outer_sign, outer_prec,
+				  vr0_min, vr0_max))
 	{
-	  vr0.type = VR_RANGE;
-	  vr0.min = TYPE_MIN_VALUE (inner_type);
-	  vr0.max = TYPE_MAX_VALUE (inner_type);
+	  tree min = wide_int_to_tree (outer_type, wmin);
+	  tree max = wide_int_to_tree (outer_type, wmax);
+	  vr->set_and_canonicalize (VR_RANGE, min, max, NULL);
 	}
-
-      /* If VR0 is a constant range or anti-range and the conversion is
-	 not truncating we can convert the min and max values and
-	 canonicalize the resulting range.  Otherwise we can do the
-	 conversion if the size of the range is less than what the
-	 precision of the target type can represent and the range is
-	 not an anti-range.  */
-      if ((vr0.type == VR_RANGE
-	   || vr0.type == VR_ANTI_RANGE)
-	  && TREE_CODE (vr0.min) == INTEGER_CST
-	  && TREE_CODE (vr0.max) == INTEGER_CST
-	  && (TYPE_PRECISION (outer_type) >= TYPE_PRECISION (inner_type)
-	      || (vr0.type == VR_RANGE
-		  && integer_zerop (int_const_binop (RSHIFT_EXPR,
-		       int_const_binop (MINUS_EXPR, vr0.max, vr0.min),
-		         size_int (TYPE_PRECISION (outer_type)))))))
-	{
-	  tree new_min, new_max;
-	  new_min = force_fit_type (outer_type, wi::to_widest (vr0.min),
-				    0, false);
-	  new_max = force_fit_type (outer_type, wi::to_widest (vr0.max),
-				    0, false);
-	  set_and_canonicalize_value_range (vr, vr0.type,
-					    new_min, new_max, NULL);
-	  return;
-	}
-
-      set_value_range_to_varying (vr);
+      else
+	set_value_range_to_varying (vr);
       return;
     }
   else if (code == ABS_EXPR)
     {
-      tree min, max;
-      int cmp;
-
-      /* Pass through vr0 in the easy cases.  */
-      if (TYPE_UNSIGNED (type)
-	  || value_range_nonnegative_p (&vr0))
-	{
-	  copy_value_range (vr, &vr0);
-	  return;
-	}
-
-      /* For the remaining varying or symbolic ranges we can't do anything
-	 useful.  */
-      if (vr0.type == VR_VARYING
-	  || symbolic_range_p (&vr0))
-	{
-	  set_value_range_to_varying (vr);
-	  return;
-	}
-
-      /* -TYPE_MIN_VALUE = TYPE_MIN_VALUE with flag_wrapv so we can't get a
-         useful range.  */
-      if (!TYPE_OVERFLOW_UNDEFINED (type)
-	  && ((vr0.type == VR_RANGE
-	       && vrp_val_is_min (vr0.min))
-	      || (vr0.type == VR_ANTI_RANGE
-		  && !vrp_val_is_min (vr0.min))))
-	{
-	  set_value_range_to_varying (vr);
-	  return;
-	}
-
-      /* ABS_EXPR may flip the range around, if the original range
-	 included negative values.  */
-      if (!vrp_val_is_min (vr0.min))
-	min = fold_unary_to_constant (code, type, vr0.min);
-      else
-	min = TYPE_MAX_VALUE (type);
-
-      if (!vrp_val_is_min (vr0.max))
-	max = fold_unary_to_constant (code, type, vr0.max);
+      wide_int wmin, wmax;
+      wide_int vr0_min, vr0_max;
+      extract_range_into_wide_ints (&vr0, sign, prec, vr0_min, vr0_max);
+      if (wide_int_range_abs (wmin, wmax, sign, prec, vr0_min, vr0_max,
+			      TYPE_OVERFLOW_UNDEFINED (type)))
+	set_value_range (vr, VR_RANGE,
+			 wide_int_to_tree (type, wmin),
+			 wide_int_to_tree (type, wmax), NULL);
       else
-	max = TYPE_MAX_VALUE (type);
-
-      cmp = compare_values (min, max);
-
-      /* If a VR_ANTI_RANGEs contains zero, then we have
-	 ~[-INF, min(MIN, MAX)].  */
-      if (vr0.type == VR_ANTI_RANGE)
-	{
-	  if (range_includes_zero_p (vr0.min, vr0.max) == 1)
-	    {
-	      /* Take the lower of the two values.  */
-	      if (cmp != 1)
-		max = min;
-
-	      /* Create ~[-INF, min (abs(MIN), abs(MAX))]
-	         or ~[-INF + 1, min (abs(MIN), abs(MAX))] when
-		 flag_wrapv is set and the original anti-range doesn't include
-	         TYPE_MIN_VALUE, remember -TYPE_MIN_VALUE = TYPE_MIN_VALUE.  */
-	      if (TYPE_OVERFLOW_WRAPS (type))
-		{
-		  tree type_min_value = TYPE_MIN_VALUE (type);
-
-		  min = (vr0.min != type_min_value
-			 ? int_const_binop (PLUS_EXPR, type_min_value,
-					    build_int_cst (TREE_TYPE (type_min_value), 1))
-			 : type_min_value);
-		}
-	      else
-		min = TYPE_MIN_VALUE (type);
-	    }
-	  else
-	    {
-	      /* All else has failed, so create the range [0, INF], even for
-	         flag_wrapv since TYPE_MIN_VALUE is in the original
-	         anti-range.  */
-	      vr0.type = VR_RANGE;
-	      min = build_int_cst (type, 0);
-	      max = TYPE_MAX_VALUE (type);
-	    }
-	}
-
-      /* If the range contains zero then we know that the minimum value in the
-         range will be zero.  */
-      else if (range_includes_zero_p (vr0.min, vr0.max) == 1)
-	{
-	  if (cmp == 1)
-	    max = min;
-	  min = build_int_cst (type, 0);
-	}
-      else
-	{
-          /* If the range was reversed, swap MIN and MAX.  */
-	  if (cmp == 1)
-	    std::swap (min, max);
-	}
-
-      cmp = compare_values (min, max);
-      if (cmp == -2 || cmp == 1)
-	{
-	  /* If the new range has its limits swapped around (MIN > MAX),
-	     then the operation caused one of them to wrap around, mark
-	     the new range VARYING.  */
-	  set_value_range_to_varying (vr);
-	}
-      else
-	set_value_range (vr, vr0.type, min, max, NULL);
+	set_value_range_to_varying (vr);
       return;
     }
 
@@ -3389,1138 +2102,29 @@
   return;
 }
 
-
-/* Extract range information from a unary expression CODE OP0 based on
-   the range of its operand with resulting type TYPE.
-   The resulting range is stored in *VR.  */
-
-static void
-extract_range_from_unary_expr (value_range *vr, enum tree_code code,
-			       tree type, tree op0)
-{
-  value_range vr0 = VR_INITIALIZER;
-
-  /* Get value ranges for the operand.  For constant operands, create
-     a new value range with the operand to simplify processing.  */
-  if (TREE_CODE (op0) == SSA_NAME)
-    vr0 = *(get_value_range (op0));
-  else if (is_gimple_min_invariant (op0))
-    set_value_range_to_value (&vr0, op0, NULL);
-  else
-    set_value_range_to_varying (&vr0);
-
-  extract_range_from_unary_expr (vr, code, type, &vr0, TREE_TYPE (op0));
-}
-
-
-/* Extract range information from a conditional expression STMT based on
-   the ranges of each of its operands and the expression code.  */
-
-static void
-extract_range_from_cond_expr (value_range *vr, gassign *stmt)
-{
-  tree op0, op1;
-  value_range vr0 = VR_INITIALIZER;
-  value_range vr1 = VR_INITIALIZER;
-
-  /* Get value ranges for each operand.  For constant operands, create
-     a new value range with the operand to simplify processing.  */
-  op0 = gimple_assign_rhs2 (stmt);
-  if (TREE_CODE (op0) == SSA_NAME)
-    vr0 = *(get_value_range (op0));
-  else if (is_gimple_min_invariant (op0))
-    set_value_range_to_value (&vr0, op0, NULL);
-  else
-    set_value_range_to_varying (&vr0);
-
-  op1 = gimple_assign_rhs3 (stmt);
-  if (TREE_CODE (op1) == SSA_NAME)
-    vr1 = *(get_value_range (op1));
-  else if (is_gimple_min_invariant (op1))
-    set_value_range_to_value (&vr1, op1, NULL);
-  else
-    set_value_range_to_varying (&vr1);
-
-  /* The resulting value range is the union of the operand ranges */
-  copy_value_range (vr, &vr0);
-  vrp_meet (vr, &vr1);
-}
-
-
-/* Extract range information from a comparison expression EXPR based
-   on the range of its operand and the expression code.  */
-
-static void
-extract_range_from_comparison (value_range *vr, enum tree_code code,
-			       tree type, tree op0, tree op1)
-{
-  bool sop;
-  tree val;
-
-  val = vrp_evaluate_conditional_warnv_with_ops (code, op0, op1, false, &sop,
-  						 NULL);
-  if (val)
-    {
-      /* Since this expression was found on the RHS of an assignment,
-	 its type may be different from _Bool.  Convert VAL to EXPR's
-	 type.  */
-      val = fold_convert (type, val);
-      if (is_gimple_min_invariant (val))
-	set_value_range_to_value (vr, val, vr->equiv);
-      else
-	set_value_range (vr, VR_RANGE, val, val, vr->equiv);
-    }
-  else
-    /* The result of a comparison is always true or false.  */
-    set_value_range_to_truthvalue (vr, type);
-}
-
-/* Helper function for simplify_internal_call_using_ranges and
-   extract_range_basic.  Return true if OP0 SUBCODE OP1 for
-   SUBCODE {PLUS,MINUS,MULT}_EXPR is known to never overflow or
-   always overflow.  Set *OVF to true if it is known to always
-   overflow.  */
-
-static bool
-check_for_binary_op_overflow (enum tree_code subcode, tree type,
-			      tree op0, tree op1, bool *ovf)
-{
-  value_range vr0 = VR_INITIALIZER;
-  value_range vr1 = VR_INITIALIZER;
-  if (TREE_CODE (op0) == SSA_NAME)
-    vr0 = *get_value_range (op0);
-  else if (TREE_CODE (op0) == INTEGER_CST)
-    set_value_range_to_value (&vr0, op0, NULL);
-  else
-    set_value_range_to_varying (&vr0);
-
-  if (TREE_CODE (op1) == SSA_NAME)
-    vr1 = *get_value_range (op1);
-  else if (TREE_CODE (op1) == INTEGER_CST)
-    set_value_range_to_value (&vr1, op1, NULL);
-  else
-    set_value_range_to_varying (&vr1);
-
-  if (!range_int_cst_p (&vr0)
-      || TREE_OVERFLOW (vr0.min)
-      || TREE_OVERFLOW (vr0.max))
-    {
-      vr0.min = vrp_val_min (TREE_TYPE (op0));
-      vr0.max = vrp_val_max (TREE_TYPE (op0));
-    }
-  if (!range_int_cst_p (&vr1)
-      || TREE_OVERFLOW (vr1.min)
-      || TREE_OVERFLOW (vr1.max))
-    {
-      vr1.min = vrp_val_min (TREE_TYPE (op1));
-      vr1.max = vrp_val_max (TREE_TYPE (op1));
-    }
-  *ovf = arith_overflowed_p (subcode, type, vr0.min,
-			     subcode == MINUS_EXPR ? vr1.max : vr1.min);
-  if (arith_overflowed_p (subcode, type, vr0.max,
-			  subcode == MINUS_EXPR ? vr1.min : vr1.max) != *ovf)
-    return false;
-  if (subcode == MULT_EXPR)
-    {
-      if (arith_overflowed_p (subcode, type, vr0.min, vr1.max) != *ovf
-	  || arith_overflowed_p (subcode, type, vr0.max, vr1.min) != *ovf)
-	return false;
-    }
-  if (*ovf)
-    {
-      /* So far we found that there is an overflow on the boundaries.
-	 That doesn't prove that there is an overflow even for all values
-	 in between the boundaries.  For that compute widest_int range
-	 of the result and see if it doesn't overlap the range of
-	 type.  */
-      widest_int wmin, wmax;
-      widest_int w[4];
-      int i;
-      w[0] = wi::to_widest (vr0.min);
-      w[1] = wi::to_widest (vr0.max);
-      w[2] = wi::to_widest (vr1.min);
-      w[3] = wi::to_widest (vr1.max);
-      for (i = 0; i < 4; i++)
-	{
-	  widest_int wt;
-	  switch (subcode)
-	    {
-	    case PLUS_EXPR:
-	      wt = wi::add (w[i & 1], w[2 + (i & 2) / 2]);
-	      break;
-	    case MINUS_EXPR:
-	      wt = wi::sub (w[i & 1], w[2 + (i & 2) / 2]);
-	      break;
-	    case MULT_EXPR:
-	      wt = wi::mul (w[i & 1], w[2 + (i & 2) / 2]);
-	      break;
-	    default:
-	      gcc_unreachable ();
-	    }
-	  if (i == 0)
-	    {
-	      wmin = wt;
-	      wmax = wt;
-	    }
-	  else
-	    {
-	      wmin = wi::smin (wmin, wt);
-	      wmax = wi::smax (wmax, wt);
-	    }
-	}
-      /* The result of op0 CODE op1 is known to be in range
-	 [wmin, wmax].  */
-      widest_int wtmin = wi::to_widest (vrp_val_min (type));
-      widest_int wtmax = wi::to_widest (vrp_val_max (type));
-      /* If all values in [wmin, wmax] are smaller than
-	 [wtmin, wtmax] or all are larger than [wtmin, wtmax],
-	 the arithmetic operation will always overflow.  */
-      if (wmax < wtmin || wmin > wtmax)
-	return true;
-      return false;
-    }
-  return true;
-}
-
-/* Try to derive a nonnegative or nonzero range out of STMT relying
-   primarily on generic routines in fold in conjunction with range data.
-   Store the result in *VR */
-
-static void
-extract_range_basic (value_range *vr, gimple *stmt)
-{
-  bool sop;
-  tree type = gimple_expr_type (stmt);
-
-  if (is_gimple_call (stmt))
-    {
-      tree arg;
-      int mini, maxi, zerov = 0, prec;
-      enum tree_code subcode = ERROR_MARK;
-      combined_fn cfn = gimple_call_combined_fn (stmt);
-      scalar_int_mode mode;
-
-      switch (cfn)
-	{
-	case CFN_BUILT_IN_CONSTANT_P:
-	  /* If the call is __builtin_constant_p and the argument is a
-	     function parameter resolve it to false.  This avoids bogus
-	     array bound warnings.
-	     ???  We could do this as early as inlining is finished.  */
-	  arg = gimple_call_arg (stmt, 0);
-	  if (TREE_CODE (arg) == SSA_NAME
-	      && SSA_NAME_IS_DEFAULT_DEF (arg)
-	      && TREE_CODE (SSA_NAME_VAR (arg)) == PARM_DECL
-	      && cfun->after_inlining)
-	    {
-	      set_value_range_to_null (vr, type);
-	      return;
-	    }
-	  break;
-	  /* Both __builtin_ffs* and __builtin_popcount return
-	     [0, prec].  */
-	CASE_CFN_FFS:
-	CASE_CFN_POPCOUNT:
-	  arg = gimple_call_arg (stmt, 0);
-	  prec = TYPE_PRECISION (TREE_TYPE (arg));
-	  mini = 0;
-	  maxi = prec;
-	  if (TREE_CODE (arg) == SSA_NAME)
-	    {
-	      value_range *vr0 = get_value_range (arg);
-	      /* If arg is non-zero, then ffs or popcount
-		 are non-zero.  */
-	      if ((vr0->type == VR_RANGE
-		   && range_includes_zero_p (vr0->min, vr0->max) == 0)
-		  || (vr0->type == VR_ANTI_RANGE
-		      && range_includes_zero_p (vr0->min, vr0->max) == 1))
-		mini = 1;
-	      /* If some high bits are known to be zero,
-		 we can decrease the maximum.  */
-	      if (vr0->type == VR_RANGE
-		  && TREE_CODE (vr0->max) == INTEGER_CST
-		  && !operand_less_p (vr0->min,
-				      build_zero_cst (TREE_TYPE (vr0->min))))
-		maxi = tree_floor_log2 (vr0->max) + 1;
-	    }
-	  goto bitop_builtin;
-	  /* __builtin_parity* returns [0, 1].  */
-	CASE_CFN_PARITY:
-	  mini = 0;
-	  maxi = 1;
-	  goto bitop_builtin;
-	  /* __builtin_c[lt]z* return [0, prec-1], except for
-	     when the argument is 0, but that is undefined behavior.
-	     On many targets where the CLZ RTL or optab value is defined
-	     for 0 the value is prec, so include that in the range
-	     by default.  */
-	CASE_CFN_CLZ:
-	  arg = gimple_call_arg (stmt, 0);
-	  prec = TYPE_PRECISION (TREE_TYPE (arg));
-	  mini = 0;
-	  maxi = prec;
-	  mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg));
-	  if (optab_handler (clz_optab, mode) != CODE_FOR_nothing
-	      && CLZ_DEFINED_VALUE_AT_ZERO (mode, zerov)
-	      /* Handle only the single common value.  */
-	      && zerov != prec)
-	    /* Magic value to give up, unless vr0 proves
-	       arg is non-zero.  */
-	    mini = -2;
-	  if (TREE_CODE (arg) == SSA_NAME)
-	    {
-	      value_range *vr0 = get_value_range (arg);
-	      /* From clz of VR_RANGE minimum we can compute
-		 result maximum.  */
-	      if (vr0->type == VR_RANGE
-		  && TREE_CODE (vr0->min) == INTEGER_CST)
-		{
-		  maxi = prec - 1 - tree_floor_log2 (vr0->min);
-		  if (maxi != prec)
-		    mini = 0;
-		}
-	      else if (vr0->type == VR_ANTI_RANGE
-		       && integer_zerop (vr0->min))
-		{
-		  maxi = prec - 1;
-		  mini = 0;
-		}
-	      if (mini == -2)
-		break;
-	      /* From clz of VR_RANGE maximum we can compute
-		 result minimum.  */
-	      if (vr0->type == VR_RANGE
-		  && TREE_CODE (vr0->max) == INTEGER_CST)
-		{
-		  mini = prec - 1 - tree_floor_log2 (vr0->max);
-		  if (mini == prec)
-		    break;
-		}
-	    }
-	  if (mini == -2)
-	    break;
-	  goto bitop_builtin;
-	  /* __builtin_ctz* return [0, prec-1], except for
-	     when the argument is 0, but that is undefined behavior.
-	     If there is a ctz optab for this mode and
-	     CTZ_DEFINED_VALUE_AT_ZERO, include that in the range,
-	     otherwise just assume 0 won't be seen.  */
-	CASE_CFN_CTZ:
-	  arg = gimple_call_arg (stmt, 0);
-	  prec = TYPE_PRECISION (TREE_TYPE (arg));
-	  mini = 0;
-	  maxi = prec - 1;
-	  mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (arg));
-	  if (optab_handler (ctz_optab, mode) != CODE_FOR_nothing
-	      && CTZ_DEFINED_VALUE_AT_ZERO (mode, zerov))
-	    {
-	      /* Handle only the two common values.  */
-	      if (zerov == -1)
-		mini = -1;
-	      else if (zerov == prec)
-		maxi = prec;
-	      else
-		/* Magic value to give up, unless vr0 proves
-		   arg is non-zero.  */
-		mini = -2;
-	    }
-	  if (TREE_CODE (arg) == SSA_NAME)
-	    {
-	      value_range *vr0 = get_value_range (arg);
-	      /* If arg is non-zero, then use [0, prec - 1].  */
-	      if ((vr0->type == VR_RANGE
-		   && integer_nonzerop (vr0->min))
-		  || (vr0->type == VR_ANTI_RANGE
-		      && integer_zerop (vr0->min)))
-		{
-		  mini = 0;
-		  maxi = prec - 1;
-		}
-	      /* If some high bits are known to be zero,
-		 we can decrease the result maximum.  */
-	      if (vr0->type == VR_RANGE
-		  && TREE_CODE (vr0->max) == INTEGER_CST)
-		{
-		  maxi = tree_floor_log2 (vr0->max);
-		  /* For vr0 [0, 0] give up.  */
-		  if (maxi == -1)
-		    break;
-		}
-	    }
-	  if (mini == -2)
-	    break;
-	  goto bitop_builtin;
-	  /* __builtin_clrsb* returns [0, prec-1].  */
-	CASE_CFN_CLRSB:
-	  arg = gimple_call_arg (stmt, 0);
-	  prec = TYPE_PRECISION (TREE_TYPE (arg));
-	  mini = 0;
-	  maxi = prec - 1;
-	  goto bitop_builtin;
-	bitop_builtin:
-	  set_value_range (vr, VR_RANGE, build_int_cst (type, mini),
-			   build_int_cst (type, maxi), NULL);
-	  return;
-	case CFN_UBSAN_CHECK_ADD:
-	  subcode = PLUS_EXPR;
-	  break;
-	case CFN_UBSAN_CHECK_SUB:
-	  subcode = MINUS_EXPR;
-	  break;
-	case CFN_UBSAN_CHECK_MUL:
-	  subcode = MULT_EXPR;
-	  break;
-	case CFN_GOACC_DIM_SIZE:
-	case CFN_GOACC_DIM_POS:
-	  /* Optimizing these two internal functions helps the loop
-	     optimizer eliminate outer comparisons.  Size is [1,N]
-	     and pos is [0,N-1].  */
-	  {
-	    bool is_pos = cfn == CFN_GOACC_DIM_POS;
-	    int axis = oacc_get_ifn_dim_arg (stmt);
-	    int size = oacc_get_fn_dim_size (current_function_decl, axis);
-
-	    if (!size)
-	      /* If it's dynamic, the backend might know a hardware
-		 limitation.  */
-	      size = targetm.goacc.dim_limit (axis);
-
-	    tree type = TREE_TYPE (gimple_call_lhs (stmt));
-	    set_value_range (vr, VR_RANGE,
-			     build_int_cst (type, is_pos ? 0 : 1),
-			     size ? build_int_cst (type, size - is_pos)
-			          : vrp_val_max (type), NULL);
-	  }
-	  return;
-	case CFN_BUILT_IN_STRLEN:
-	  if (tree lhs = gimple_call_lhs (stmt))
-	    if (ptrdiff_type_node
-		&& (TYPE_PRECISION (ptrdiff_type_node)
-		    == TYPE_PRECISION (TREE_TYPE (lhs))))
-	      {
-		tree type = TREE_TYPE (lhs);
-		tree max = vrp_val_max (ptrdiff_type_node);
-		wide_int wmax = wi::to_wide (max, TYPE_PRECISION (TREE_TYPE (max)));
-		tree range_min = build_zero_cst (type);
-		tree range_max = wide_int_to_tree (type, wmax - 1);
-		set_value_range (vr, VR_RANGE, range_min, range_max, NULL);
-		return;
-	      }
-	  break;
-	default:
-	  break;
-	}
-      if (subcode != ERROR_MARK)
-	{
-	  bool saved_flag_wrapv = flag_wrapv;
-	  /* Pretend the arithmetics is wrapping.  If there is
-	     any overflow, we'll complain, but will actually do
-	     wrapping operation.  */
-	  flag_wrapv = 1;
-	  extract_range_from_binary_expr (vr, subcode, type,
-					  gimple_call_arg (stmt, 0),
-					  gimple_call_arg (stmt, 1));
-	  flag_wrapv = saved_flag_wrapv;
-
-	  /* If for both arguments vrp_valueize returned non-NULL,
-	     this should have been already folded and if not, it
-	     wasn't folded because of overflow.  Avoid removing the
-	     UBSAN_CHECK_* calls in that case.  */
-	  if (vr->type == VR_RANGE
-	      && (vr->min == vr->max
-		  || operand_equal_p (vr->min, vr->max, 0)))
-	    set_value_range_to_varying (vr);
-	  return;
-	}
-    }
-  /* Handle extraction of the two results (result of arithmetics and
-     a flag whether arithmetics overflowed) from {ADD,SUB,MUL}_OVERFLOW
-     internal function.  Similarly from ATOMIC_COMPARE_EXCHANGE.  */
-  else if (is_gimple_assign (stmt)
-	   && (gimple_assign_rhs_code (stmt) == REALPART_EXPR
-	       || gimple_assign_rhs_code (stmt) == IMAGPART_EXPR)
-	   && INTEGRAL_TYPE_P (type))
-    {
-      enum tree_code code = gimple_assign_rhs_code (stmt);
-      tree op = gimple_assign_rhs1 (stmt);
-      if (TREE_CODE (op) == code && TREE_CODE (TREE_OPERAND (op, 0)) == SSA_NAME)
-	{
-	  gimple *g = SSA_NAME_DEF_STMT (TREE_OPERAND (op, 0));
-	  if (is_gimple_call (g) && gimple_call_internal_p (g))
-	    {
-	      enum tree_code subcode = ERROR_MARK;
-	      switch (gimple_call_internal_fn (g))
-		{
-		case IFN_ADD_OVERFLOW:
-		  subcode = PLUS_EXPR;
-		  break;
-		case IFN_SUB_OVERFLOW:
-		  subcode = MINUS_EXPR;
-		  break;
-		case IFN_MUL_OVERFLOW:
-		  subcode = MULT_EXPR;
-		  break;
-		case IFN_ATOMIC_COMPARE_EXCHANGE:
-		  if (code == IMAGPART_EXPR)
-		    {
-		      /* This is the boolean return value whether compare and
-			 exchange changed anything or not.  */
-		      set_value_range (vr, VR_RANGE, build_int_cst (type, 0),
-				       build_int_cst (type, 1), NULL);
-		      return;
-		    }
-		  break;
-		default:
-		  break;
-		}
-	      if (subcode != ERROR_MARK)
-		{
-		  tree op0 = gimple_call_arg (g, 0);
-		  tree op1 = gimple_call_arg (g, 1);
-		  if (code == IMAGPART_EXPR)
-		    {
-		      bool ovf = false;
-		      if (check_for_binary_op_overflow (subcode, type,
-							op0, op1, &ovf))
-			set_value_range_to_value (vr,
-						  build_int_cst (type, ovf),
-						  NULL);
-		      else if (TYPE_PRECISION (type) == 1
-			       && !TYPE_UNSIGNED (type))
-			set_value_range_to_varying (vr);
-		      else
-			set_value_range (vr, VR_RANGE, build_int_cst (type, 0),
-					 build_int_cst (type, 1), NULL);
-		    }
-		  else if (types_compatible_p (type, TREE_TYPE (op0))
-			   && types_compatible_p (type, TREE_TYPE (op1)))
-		    {
-		      bool saved_flag_wrapv = flag_wrapv;
-		      /* Pretend the arithmetics is wrapping.  If there is
-			 any overflow, IMAGPART_EXPR will be set.  */
-		      flag_wrapv = 1;
-		      extract_range_from_binary_expr (vr, subcode, type,
-						      op0, op1);
-		      flag_wrapv = saved_flag_wrapv;
-		    }
-		  else
-		    {
-		      value_range vr0 = VR_INITIALIZER;
-		      value_range vr1 = VR_INITIALIZER;
-		      bool saved_flag_wrapv = flag_wrapv;
-		      /* Pretend the arithmetics is wrapping.  If there is
-			 any overflow, IMAGPART_EXPR will be set.  */
-		      flag_wrapv = 1;
-		      extract_range_from_unary_expr (&vr0, NOP_EXPR,
-						     type, op0);
-		      extract_range_from_unary_expr (&vr1, NOP_EXPR,
-						     type, op1);
-		      extract_range_from_binary_expr_1 (vr, subcode, type,
-							&vr0, &vr1);
-		      flag_wrapv = saved_flag_wrapv;
-		    }
-		  return;
-		}
-	    }
-	}
-    }
-  if (INTEGRAL_TYPE_P (type)
-      && gimple_stmt_nonnegative_warnv_p (stmt, &sop))
-    set_value_range_to_nonnegative (vr, type);
-  else if (vrp_stmt_computes_nonzero (stmt))
-    set_value_range_to_nonnull (vr, type);
-  else
-    set_value_range_to_varying (vr);
-}
-
-
-/* Try to compute a useful range out of assignment STMT and store it
-   in *VR.  */
-
-static void
-extract_range_from_assignment (value_range *vr, gassign *stmt)
-{
-  enum tree_code code = gimple_assign_rhs_code (stmt);
-
-  if (code == ASSERT_EXPR)
-    extract_range_from_assert (vr, gimple_assign_rhs1 (stmt));
-  else if (code == SSA_NAME)
-    extract_range_from_ssa_name (vr, gimple_assign_rhs1 (stmt));
-  else if (TREE_CODE_CLASS (code) == tcc_binary)
-    extract_range_from_binary_expr (vr, gimple_assign_rhs_code (stmt),
-				    gimple_expr_type (stmt),
-				    gimple_assign_rhs1 (stmt),
-				    gimple_assign_rhs2 (stmt));
-  else if (TREE_CODE_CLASS (code) == tcc_unary)
-    extract_range_from_unary_expr (vr, gimple_assign_rhs_code (stmt),
-				   gimple_expr_type (stmt),
-				   gimple_assign_rhs1 (stmt));
-  else if (code == COND_EXPR)
-    extract_range_from_cond_expr (vr, stmt);
-  else if (TREE_CODE_CLASS (code) == tcc_comparison)
-    extract_range_from_comparison (vr, gimple_assign_rhs_code (stmt),
-				   gimple_expr_type (stmt),
-				   gimple_assign_rhs1 (stmt),
-				   gimple_assign_rhs2 (stmt));
-  else if (get_gimple_rhs_class (code) == GIMPLE_SINGLE_RHS
-	   && is_gimple_min_invariant (gimple_assign_rhs1 (stmt)))
-    set_value_range_to_value (vr, gimple_assign_rhs1 (stmt), NULL);
-  else
-    set_value_range_to_varying (vr);
-
-  if (vr->type == VR_VARYING)
-    extract_range_basic (vr, stmt);
-}
-
-/* Given a range VR, a LOOP and a variable VAR, determine whether it
-   would be profitable to adjust VR using scalar evolution information
-   for VAR.  If so, update VR with the new limits.  */
-
-static void
-adjust_range_with_scev (value_range *vr, struct loop *loop,
-			gimple *stmt, tree var)
-{
-  tree init, step, chrec, tmin, tmax, min, max, type, tem;
-  enum ev_direction dir;
-
-  /* TODO.  Don't adjust anti-ranges.  An anti-range may provide
-     better opportunities than a regular range, but I'm not sure.  */
-  if (vr->type == VR_ANTI_RANGE)
-    return;
-
-  chrec = instantiate_parameters (loop, analyze_scalar_evolution (loop, var));
-
-  /* Like in PR19590, scev can return a constant function.  */
-  if (is_gimple_min_invariant (chrec))
-    {
-      set_value_range_to_value (vr, chrec, vr->equiv);
-      return;
-    }
-
-  if (TREE_CODE (chrec) != POLYNOMIAL_CHREC)
-    return;
-
-  init = initial_condition_in_loop_num (chrec, loop->num);
-  tem = op_with_constant_singleton_value_range (init);
-  if (tem)
-    init = tem;
-  step = evolution_part_in_loop_num (chrec, loop->num);
-  tem = op_with_constant_singleton_value_range (step);
-  if (tem)
-    step = tem;
-
-  /* If STEP is symbolic, we can't know whether INIT will be the
-     minimum or maximum value in the range.  Also, unless INIT is
-     a simple expression, compare_values and possibly other functions
-     in tree-vrp won't be able to handle it.  */
-  if (step == NULL_TREE
-      || !is_gimple_min_invariant (step)
-      || !valid_value_p (init))
-    return;
-
-  dir = scev_direction (chrec);
-  if (/* Do not adjust ranges if we do not know whether the iv increases
-	 or decreases,  ... */
-      dir == EV_DIR_UNKNOWN
-      /* ... or if it may wrap.  */
-      || scev_probably_wraps_p (NULL_TREE, init, step, stmt,
-				get_chrec_loop (chrec), true))
-    return;
-
-  type = TREE_TYPE (var);
-  if (POINTER_TYPE_P (type) || !TYPE_MIN_VALUE (type))
-    tmin = lower_bound_in_type (type, type);
-  else
-    tmin = TYPE_MIN_VALUE (type);
-  if (POINTER_TYPE_P (type) || !TYPE_MAX_VALUE (type))
-    tmax = upper_bound_in_type (type, type);
-  else
-    tmax = TYPE_MAX_VALUE (type);
-
-  /* Try to use estimated number of iterations for the loop to constrain the
-     final value in the evolution.  */
-  if (TREE_CODE (step) == INTEGER_CST
-      && is_gimple_val (init)
-      && (TREE_CODE (init) != SSA_NAME
-	  || get_value_range (init)->type == VR_RANGE))
-    {
-      widest_int nit;
-
-      /* We are only entering here for loop header PHI nodes, so using
-	 the number of latch executions is the correct thing to use.  */
-      if (max_loop_iterations (loop, &nit))
-	{
-	  value_range maxvr = VR_INITIALIZER;
-	  signop sgn = TYPE_SIGN (TREE_TYPE (step));
-	  bool overflow;
-
-	  widest_int wtmp = wi::mul (wi::to_widest (step), nit, sgn,
-				     &overflow);
-	  /* If the multiplication overflowed we can't do a meaningful
-	     adjustment.  Likewise if the result doesn't fit in the type
-	     of the induction variable.  For a signed type we have to
-	     check whether the result has the expected signedness which
-	     is that of the step as number of iterations is unsigned.  */
-	  if (!overflow
-	      && wi::fits_to_tree_p (wtmp, TREE_TYPE (init))
-	      && (sgn == UNSIGNED
-		  || wi::gts_p (wtmp, 0) == wi::gts_p (wi::to_wide (step), 0)))
-	    {
-	      tem = wide_int_to_tree (TREE_TYPE (init), wtmp);
-	      extract_range_from_binary_expr (&maxvr, PLUS_EXPR,
-					      TREE_TYPE (init), init, tem);
-	      /* Likewise if the addition did.  */
-	      if (maxvr.type == VR_RANGE)
-		{
-		  value_range initvr = VR_INITIALIZER;
-
-		  if (TREE_CODE (init) == SSA_NAME)
-		    initvr = *(get_value_range (init));
-		  else if (is_gimple_min_invariant (init))
-		    set_value_range_to_value (&initvr, init, NULL);
-		  else
-		    return;
-
-		  /* Check if init + nit * step overflows.  Though we checked
-		     scev {init, step}_loop doesn't wrap, it is not enough
-		     because the loop may exit immediately.  Overflow could
-		     happen in the plus expression in this case.  */
-		  if ((dir == EV_DIR_DECREASES
-		       && compare_values (maxvr.min, initvr.min) != -1)
-		      || (dir == EV_DIR_GROWS
-			  && compare_values (maxvr.max, initvr.max) != 1))
-		    return;
-
-		  tmin = maxvr.min;
-		  tmax = maxvr.max;
-		}
-	    }
-	}
-    }
-
-  if (vr->type == VR_VARYING || vr->type == VR_UNDEFINED)
-    {
-      min = tmin;
-      max = tmax;
-
-      /* For VARYING or UNDEFINED ranges, just about anything we get
-	 from scalar evolutions should be better.  */
-
-      if (dir == EV_DIR_DECREASES)
-	max = init;
-      else
-	min = init;
-    }
-  else if (vr->type == VR_RANGE)
-    {
-      min = vr->min;
-      max = vr->max;
-
-      if (dir == EV_DIR_DECREASES)
-	{
-	  /* INIT is the maximum value.  If INIT is lower than VR->MAX
-	     but no smaller than VR->MIN, set VR->MAX to INIT.  */
-	  if (compare_values (init, max) == -1)
-	    max = init;
-
-	  /* According to the loop information, the variable does not
-	     overflow.  */
-	  if (compare_values (min, tmin) == -1)
-	    min = tmin;
-
-	}
-      else
-	{
-	  /* If INIT is bigger than VR->MIN, set VR->MIN to INIT.  */
-	  if (compare_values (init, min) == 1)
-	    min = init;
-
-	  if (compare_values (tmax, max) == -1)
-	    max = tmax;
-	}
-    }
-  else
-    return;
-
-  /* If we just created an invalid range with the minimum
-     greater than the maximum, we fail conservatively.
-     This should happen only in unreachable
-     parts of code, or for invalid programs.  */
-  if (compare_values (min, max) == 1)
-    return;
-
-  /* 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);
-
-  set_value_range (vr, VR_RANGE, min, max, vr->equiv);
-}
-
-
-/* Given two numeric value ranges VR0, VR1 and a comparison code COMP:
-
-   - Return BOOLEAN_TRUE_NODE if VR0 COMP VR1 always returns true for
-     all the values in the ranges.
-
-   - Return BOOLEAN_FALSE_NODE if the comparison always returns false.
-
-   - Return NULL_TREE if it is not always possible to determine the
-     value of the comparison.
-
-   Also set *STRICT_OVERFLOW_P to indicate whether comparision evaluation
-   assumed signed overflow is undefined.  */
-
-
-static tree
-compare_ranges (enum tree_code comp, value_range *vr0, value_range *vr1,
-		bool *strict_overflow_p)
-{
-  /* VARYING or UNDEFINED ranges cannot be compared.  */
-  if (vr0->type == VR_VARYING
-      || vr0->type == VR_UNDEFINED
-      || vr1->type == VR_VARYING
-      || vr1->type == VR_UNDEFINED)
-    return NULL_TREE;
-
-  /* Anti-ranges need to be handled separately.  */
-  if (vr0->type == VR_ANTI_RANGE || vr1->type == VR_ANTI_RANGE)
-    {
-      /* If both are anti-ranges, then we cannot compute any
-	 comparison.  */
-      if (vr0->type == VR_ANTI_RANGE && vr1->type == VR_ANTI_RANGE)
-	return NULL_TREE;
-
-      /* These comparisons are never statically computable.  */
-      if (comp == GT_EXPR
-	  || comp == GE_EXPR
-	  || comp == LT_EXPR
-	  || comp == LE_EXPR)
-	return NULL_TREE;
-
-      /* Equality can be computed only between a range and an
-	 anti-range.  ~[VAL1, VAL2] == [VAL1, VAL2] is always false.  */
-      if (vr0->type == VR_RANGE)
-	{
-	  /* To simplify processing, make VR0 the anti-range.  */
-	  value_range *tmp = vr0;
-	  vr0 = vr1;
-	  vr1 = tmp;
-	}
-
-      gcc_assert (comp == NE_EXPR || comp == EQ_EXPR);
-
-      if (compare_values_warnv (vr0->min, vr1->min, strict_overflow_p) == 0
-	  && compare_values_warnv (vr0->max, vr1->max, strict_overflow_p) == 0)
-	return (comp == NE_EXPR) ? boolean_true_node : boolean_false_node;
-
-      return NULL_TREE;
-    }
-
-  /* Simplify processing.  If COMP is GT_EXPR or GE_EXPR, switch the
-     operands around and change the comparison code.  */
-  if (comp == GT_EXPR || comp == GE_EXPR)
-    {
-      comp = (comp == GT_EXPR) ? LT_EXPR : LE_EXPR;
-      std::swap (vr0, vr1);
-    }
-
-  if (comp == EQ_EXPR)
-    {
-      /* Equality may only be computed if both ranges represent
-	 exactly one value.  */
-      if (compare_values_warnv (vr0->min, vr0->max, strict_overflow_p) == 0
-	  && compare_values_warnv (vr1->min, vr1->max, strict_overflow_p) == 0)
-	{
-	  int cmp_min = compare_values_warnv (vr0->min, vr1->min,
-					      strict_overflow_p);
-	  int cmp_max = compare_values_warnv (vr0->max, vr1->max,
-					      strict_overflow_p);
-	  if (cmp_min == 0 && cmp_max == 0)
-	    return boolean_true_node;
-	  else if (cmp_min != -2 && cmp_max != -2)
-	    return boolean_false_node;
-	}
-      /* If [V0_MIN, V1_MAX] < [V1_MIN, V1_MAX] then V0 != V1.  */
-      else if (compare_values_warnv (vr0->min, vr1->max,
-				     strict_overflow_p) == 1
-	       || compare_values_warnv (vr1->min, vr0->max,
-					strict_overflow_p) == 1)
-	return boolean_false_node;
-
-      return NULL_TREE;
-    }
-  else if (comp == NE_EXPR)
-    {
-      int cmp1, cmp2;
-
-      /* If VR0 is completely to the left or completely to the right
-	 of VR1, they are always different.  Notice that we need to
-	 make sure that both comparisons yield similar results to
-	 avoid comparing values that cannot be compared at
-	 compile-time.  */
-      cmp1 = compare_values_warnv (vr0->max, vr1->min, strict_overflow_p);
-      cmp2 = compare_values_warnv (vr0->min, vr1->max, strict_overflow_p);
-      if ((cmp1 == -1 && cmp2 == -1) || (cmp1 == 1 && cmp2 == 1))
-	return boolean_true_node;
-
-      /* If VR0 and VR1 represent a single value and are identical,
-	 return false.  */
-      else if (compare_values_warnv (vr0->min, vr0->max,
-				     strict_overflow_p) == 0
-	       && compare_values_warnv (vr1->min, vr1->max,
-					strict_overflow_p) == 0
-	       && compare_values_warnv (vr0->min, vr1->min,
-					strict_overflow_p) == 0
-	       && compare_values_warnv (vr0->max, vr1->max,
-					strict_overflow_p) == 0)
-	return boolean_false_node;
-
-      /* Otherwise, they may or may not be different.  */
-      else
-	return NULL_TREE;
-    }
-  else if (comp == LT_EXPR || comp == LE_EXPR)
-    {
-      int tst;
-
-      /* If VR0 is to the left of VR1, return true.  */
-      tst = compare_values_warnv (vr0->max, vr1->min, strict_overflow_p);
-      if ((comp == LT_EXPR && tst == -1)
-	  || (comp == LE_EXPR && (tst == -1 || tst == 0)))
-	return boolean_true_node;
-
-      /* If VR0 is to the right of VR1, return false.  */
-      tst = compare_values_warnv (vr0->min, vr1->max, strict_overflow_p);
-      if ((comp == LT_EXPR && (tst == 0 || tst == 1))
-	  || (comp == LE_EXPR && tst == 1))
-	return boolean_false_node;
-
-      /* Otherwise, we don't know.  */
-      return NULL_TREE;
-    }
-
-  gcc_unreachable ();
-}
-
-
-/* Given a value range VR, a value VAL and a comparison code COMP, return
-   BOOLEAN_TRUE_NODE if VR COMP VAL always returns true for all the
-   values in VR.  Return BOOLEAN_FALSE_NODE if the comparison
-   always returns false.  Return NULL_TREE if it is not always
-   possible to determine the value of the comparison.  Also set
-   *STRICT_OVERFLOW_P to indicate whether comparision evaluation
-   assumed signed overflow is undefined.  */
-
-static tree
-compare_range_with_value (enum tree_code comp, value_range *vr, tree val,
-			  bool *strict_overflow_p)
-{
-  if (vr->type == VR_VARYING || vr->type == VR_UNDEFINED)
-    return NULL_TREE;
-
-  /* Anti-ranges need to be handled separately.  */
-  if (vr->type == VR_ANTI_RANGE)
-    {
-      /* For anti-ranges, the only predicates that we can compute at
-	 compile time are equality and inequality.  */
-      if (comp == GT_EXPR
-	  || comp == GE_EXPR
-	  || comp == LT_EXPR
-	  || comp == LE_EXPR)
-	return NULL_TREE;
-
-      /* ~[VAL_1, VAL_2] OP VAL is known if VAL_1 <= VAL <= VAL_2.  */
-      if (value_inside_range (val, vr->min, vr->max) == 1)
-	return (comp == NE_EXPR) ? boolean_true_node : boolean_false_node;
-
-      return NULL_TREE;
-    }
-
-  if (comp == EQ_EXPR)
-    {
-      /* EQ_EXPR may only be computed if VR represents exactly
-	 one value.  */
-      if (compare_values_warnv (vr->min, vr->max, strict_overflow_p) == 0)
-	{
-	  int cmp = compare_values_warnv (vr->min, val, strict_overflow_p);
-	  if (cmp == 0)
-	    return boolean_true_node;
-	  else if (cmp == -1 || cmp == 1 || cmp == 2)
-	    return boolean_false_node;
-	}
-      else if (compare_values_warnv (val, vr->min, strict_overflow_p) == -1
-	       || compare_values_warnv (vr->max, val, strict_overflow_p) == -1)
-	return boolean_false_node;
-
-      return NULL_TREE;
-    }
-  else if (comp == NE_EXPR)
-    {
-      /* If VAL is not inside VR, then they are always different.  */
-      if (compare_values_warnv (vr->max, val, strict_overflow_p) == -1
-	  || compare_values_warnv (vr->min, val, strict_overflow_p) == 1)
-	return boolean_true_node;
-
-      /* If VR represents exactly one value equal to VAL, then return
-	 false.  */
-      if (compare_values_warnv (vr->min, vr->max, strict_overflow_p) == 0
-	  && compare_values_warnv (vr->min, val, strict_overflow_p) == 0)
-	return boolean_false_node;
-
-      /* Otherwise, they may or may not be different.  */
-      return NULL_TREE;
-    }
-  else if (comp == LT_EXPR || comp == LE_EXPR)
-    {
-      int tst;
-
-      /* If VR is to the left of VAL, return true.  */
-      tst = compare_values_warnv (vr->max, val, strict_overflow_p);
-      if ((comp == LT_EXPR && tst == -1)
-	  || (comp == LE_EXPR && (tst == -1 || tst == 0)))
-	return boolean_true_node;
-
-      /* If VR is to the right of VAL, return false.  */
-      tst = compare_values_warnv (vr->min, val, strict_overflow_p);
-      if ((comp == LT_EXPR && (tst == 0 || tst == 1))
-	  || (comp == LE_EXPR && tst == 1))
-	return boolean_false_node;
-
-      /* Otherwise, we don't know.  */
-      return NULL_TREE;
-    }
-  else if (comp == GT_EXPR || comp == GE_EXPR)
-    {
-      int tst;
-
-      /* If VR is to the right of VAL, return true.  */
-      tst = compare_values_warnv (vr->min, val, strict_overflow_p);
-      if ((comp == GT_EXPR && tst == 1)
-	  || (comp == GE_EXPR && (tst == 0 || tst == 1)))
-	return boolean_true_node;
-
-      /* If VR is to the left of VAL, return false.  */
-      tst = compare_values_warnv (vr->max, val, strict_overflow_p);
-      if ((comp == GT_EXPR && (tst == -1 || tst == 0))
-	  || (comp == GE_EXPR && tst == -1))
-	return boolean_false_node;
-
-      /* Otherwise, we don't know.  */
-      return NULL_TREE;
-    }
-
-  gcc_unreachable ();
-}
-
-
 /* Debugging dumps.  */
 
 void dump_value_range (FILE *, const value_range *);
-void debug_value_range (value_range *);
+void debug_value_range (const value_range *);
 void dump_all_value_ranges (FILE *);
-void debug_all_value_ranges (void);
 void dump_vr_equiv (FILE *, bitmap);
 void debug_vr_equiv (bitmap);
 
-
-/* Dump value range VR to FILE.  */
-
 void
 dump_value_range (FILE *file, const value_range *vr)
 {
-  if (vr == NULL)
+  if (!vr)
     fprintf (file, "[]");
-  else if (vr->type == VR_UNDEFINED)
-    fprintf (file, "UNDEFINED");
-  else if (vr->type == VR_RANGE || vr->type == VR_ANTI_RANGE)
-    {
-      tree type = TREE_TYPE (vr->min);
-
-      fprintf (file, "%s[", (vr->type == VR_ANTI_RANGE) ? "~" : "");
-
-      if (INTEGRAL_TYPE_P (type)
-	  && !TYPE_UNSIGNED (type)
-	  && vrp_val_is_min (vr->min))
-	fprintf (file, "-INF");
-      else
-	print_generic_expr (file, vr->min);
-
-      fprintf (file, ", ");
-
-      if (INTEGRAL_TYPE_P (type)
-	  && vrp_val_is_max (vr->max))
-	fprintf (file, "+INF");
-      else
-	print_generic_expr (file, vr->max);
-
-      fprintf (file, "]");
-
-      if (vr->equiv)
-	{
-	  bitmap_iterator bi;
-	  unsigned i, c = 0;
-
-	  fprintf (file, "  EQUIVALENCES: { ");
-
-	  EXECUTE_IF_SET_IN_BITMAP (vr->equiv, 0, i, bi)
-	    {
-	      print_generic_expr (file, ssa_name (i));
-	      fprintf (file, " ");
-	      c++;
-	    }
-
-	  fprintf (file, "} (%u elements)", c);
-	}
-    }
-  else if (vr->type == VR_VARYING)
-    fprintf (file, "VARYING");
   else
-    fprintf (file, "INVALID RANGE");
+    vr->dump (file);
 }
 
-
 /* Dump value range VR to stderr.  */
 
 DEBUG_FUNCTION void
-debug_value_range (value_range *vr)
-{
-  dump_value_range (stderr, vr);
-  fprintf (stderr, "\n");
-}
-
-
-/* Dump value ranges of all SSA_NAMEs to FILE.  */
-
-void
-dump_all_value_ranges (FILE *file)
+debug_value_range (const value_range *vr)
 {
-  size_t i;
-
-  for (i = 0; i < num_vr_values; i++)
-    {
-      if (vr_value[i])
-	{
-	  print_generic_expr (file, ssa_name (i));
-	  fprintf (file, ": ");
-	  dump_value_range (file, vr_value[i]);
-	  fprintf (file, "\n");
-	}
-    }
-
-  fprintf (file, "\n");
-}
-
-
-/* Dump all value ranges to stderr.  */
-
-DEBUG_FUNCTION void
-debug_all_value_ranges (void)
-{
-  dump_all_value_ranges (stderr);
+  vr->dump ();
 }
 
 
@@ -4571,7 +2175,7 @@
    describes the inferred range.  Return true if a range could be
    inferred.  */
 
-static bool
+bool
 infer_value_range (gimple *stmt, tree op, tree_code *comp_code_p, tree *val_p)
 {
   *val_p = NULL_TREE;
@@ -4690,9 +2294,15 @@
   assert_info info;
   info.comp_code = comp_code;
   info.name = name;
+  if (TREE_OVERFLOW_P (val))
+    val = drop_tree_overflow (val);
   info.val = val;
   info.expr = expr;
   asserts.safe_push (info);
+  if (dump_enabled_p ())
+    dump_printf (MSG_NOTE | MSG_PRIORITY_INTERNALS,
+		 "Adding assert for %T from %T %s %T\n",
+		 name, expr, op_symbol_code (comp_code), val);
 }
 
 /* If NAME doesn't have an ASSERT_EXPR registered for asserting
@@ -5006,7 +2616,7 @@
    {ADD,SUB}_OVERFLOW sequences later in the optimizer pipeline.  But
    the alternate range representation is often useful within VRP.  */
 
-static bool
+bool
 overflow_comparison_p (tree_code code, tree name, tree val,
 		       bool use_equiv_p, tree *new_cst)
 {
@@ -5092,16 +2702,6 @@
 	  tmp = build1 (NOP_EXPR, TREE_TYPE (name), name3);
 	  if (cst2 != NULL_TREE)
 	    tmp = build2 (PLUS_EXPR, TREE_TYPE (name), tmp, cst2);
-
-	  if (dump_file)
-	    {
-	      fprintf (dump_file, "Adding assert for ");
-	      print_generic_expr (dump_file, name3);
-	      fprintf (dump_file, " from ");
-	      print_generic_expr (dump_file, tmp);
-	      fprintf (dump_file, "\n");
-	    }
-
 	  add_assert_info (asserts, name3, tmp, comp_code, val);
 	}
 
@@ -5119,16 +2719,6 @@
 	    tmp = build1 (NOP_EXPR, TREE_TYPE (name), tmp);
 	  if (cst2 != NULL_TREE)
 	    tmp = build2 (PLUS_EXPR, TREE_TYPE (name), tmp, cst2);
-
-	  if (dump_file)
-	    {
-	      fprintf (dump_file, "Adding assert for ");
-	      print_generic_expr (dump_file, name2);
-	      fprintf (dump_file, " from ");
-	      print_generic_expr (dump_file, tmp);
-	      fprintf (dump_file, "\n");
-	    }
-
 	  add_assert_info (asserts, name2, tmp, comp_code, val);
 	}
     }
@@ -5251,16 +2841,6 @@
 		  cst = fold_build2 (MINUS_EXPR, TREE_TYPE (name2), cst,
 				     build_int_cst (TREE_TYPE (name2), 1));
 		}
-
-	      if (dump_file)
-		{
-		  fprintf (dump_file, "Adding assert for ");
-		  print_generic_expr (dump_file, name2);
-		  fprintf (dump_file, " from ");
-		  print_generic_expr (dump_file, tmp);
-		  fprintf (dump_file, "\n");
-		}
-
 	      add_assert_info (asserts, name2, tmp, new_comp_code, cst);
 	    }
 	}
@@ -5325,18 +2905,7 @@
 	    }
 
 	  if (new_val)
-	    {
-	      if (dump_file)
-		{
-		  fprintf (dump_file, "Adding assert for ");
-		  print_generic_expr (dump_file, name2);
-		  fprintf (dump_file, " from ");
-		  print_generic_expr (dump_file, tmp);
-		  fprintf (dump_file, "\n");
-		}
-
-	      add_assert_info (asserts, name2, tmp, new_comp_code, new_val);
-	    }
+	    add_assert_info (asserts, name2, tmp, new_comp_code, new_val);
 	}
 
       /* Add asserts for NAME cmp CST and NAME being defined as
@@ -5564,16 +3133,6 @@
 			maxv2 = maxv - minv;
 		      }
 		    new_val = wide_int_to_tree (type, maxv2);
-
-		    if (dump_file)
-		      {
-			fprintf (dump_file, "Adding assert for ");
-			print_generic_expr (dump_file, names[i]);
-			fprintf (dump_file, " from ");
-			print_generic_expr (dump_file, tmp);
-			fprintf (dump_file, "\n");
-		      }
-
 		    add_assert_info (asserts, names[i], tmp, LE_EXPR, new_val);
 		  }
 	    }
@@ -5670,10 +3229,10 @@
    Such comparison can yield assertions like
      X >= XX...X00...0
      X <= XX...X11...1
-   in case of COND_OP being NE_EXPR or
+   in case of COND_OP being EQ_EXPR or
      X < XX...X00...0
      X > XX...X11...1
-   in case of EQ_EXPR.  */
+   in case of NE_EXPR.  */
 
 static bool
 is_masked_range_test (tree name, tree valt, enum tree_code cond_code,
@@ -5693,6 +3252,10 @@
 
   wi::tree_to_wide_ref mask = wi::to_wide (maskt);
   wide_int inv_mask = ~mask;
+  /* Must have been removed by now so don't bother optimizing.  */
+  if (mask == 0 || inv_mask == 0)
+    return false;
+
   /* Assume VALT is INTEGER_CST.  */
   wi::tree_to_wide_ref val = wi::to_wide (valt);
 
@@ -5733,9 +3296,6 @@
   *low = wide_int_to_tree (type, val);
   *high = wide_int_to_tree (type, val | inv_mask);
 
-  if (wi::neg_p (val, TYPE_SIGN (type)))
-    std::swap (*low, *high);
-
   return true;
 }
 
@@ -5743,7 +3303,7 @@
    the condition COND contributing to the conditional jump pointed to by
    SI.  */
 
-static void
+void
 register_edge_assert_for (tree name, edge e,
 			  enum tree_code cond_code, tree cond_op0,
 			  tree cond_op1, vec<assert_info> &asserts)
@@ -5955,7 +3515,7 @@
   for (idx = 0; idx < n; ++idx)
     {
       ci[idx].expr = gimple_switch_label (last, idx);
-      ci[idx].bb = label_to_block (CASE_LABEL (ci[idx].expr));
+      ci[idx].bb = label_to_block (cfun, CASE_LABEL (ci[idx].expr));
     }
   edge default_edge = find_edge (bb, ci[0].bb);
   qsort (ci, n, sizeof (struct case_info), compare_case_labels);
@@ -6655,6 +4215,35 @@
   BITMAP_FREE (need_assert_for);
 }
 
+class vrp_prop : public ssa_propagation_engine
+{
+ public:
+  enum ssa_prop_result visit_stmt (gimple *, edge *, tree *) FINAL OVERRIDE;
+  enum ssa_prop_result visit_phi (gphi *) FINAL OVERRIDE;
+
+  void vrp_initialize (void);
+  void vrp_finalize (bool);
+  void check_all_array_refs (void);
+  void check_array_ref (location_t, tree, bool);
+  void check_mem_ref (location_t, tree, bool);
+  void search_for_addr_array (tree, location_t);
+
+  class vr_values vr_values;
+  /* Temporary delegator to minimize code churn.  */
+  value_range *get_value_range (const_tree op)
+    { return vr_values.get_value_range (op); }
+  void set_defs_to_varying (gimple *stmt)
+    { return vr_values.set_defs_to_varying (stmt); }
+  void extract_range_from_stmt (gimple *stmt, edge *taken_edge_p,
+				tree *output_p, value_range *vr)
+    { vr_values.extract_range_from_stmt (stmt, taken_edge_p, output_p, vr); }
+  bool update_value_range (const_tree op, value_range *vr)
+    { return vr_values.update_value_range (op, vr); }
+  void extract_range_basic (value_range *vr, gimple *stmt)
+    { vr_values.extract_range_basic (vr, stmt); }
+  void extract_range_from_phi_node (gphi *phi, value_range *vr)
+    { vr_values.extract_range_from_phi_node (phi, vr); }
+};
 /* Checks one ARRAY_REF in REF, located at LOCUS. Ignores flexible arrays
    and "struct" hacks. If VRP can determine that the
    array subscript is a constant, check if it is outside valid
@@ -6662,10 +4251,11 @@
    non-overlapping with valid range.
    IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside a ADDR_EXPR.  */
 
-static void
-check_array_ref (location_t location, tree ref, bool ignore_off_by_one)
+void
+vrp_prop::check_array_ref (location_t location, tree ref,
+			   bool ignore_off_by_one)
 {
-  value_range *vr = NULL;
+  const value_range *vr = NULL;
   tree low_sub, up_sub;
   tree low_bound, up_bound, up_bound_p1;
 
@@ -6675,54 +4265,85 @@
   low_sub = up_sub = TREE_OPERAND (ref, 1);
   up_bound = array_ref_up_bound (ref);
 
-  /* Can not check flexible arrays.  */
   if (!up_bound
-      || TREE_CODE (up_bound) != INTEGER_CST)
-    return;
-
-  /* Accesses to trailing arrays via pointers may access storage
-     beyond the types array bounds.  */
-  if (warn_array_bounds < 2
-      && array_at_struct_end_p (ref))
-    return;
+      || TREE_CODE (up_bound) != INTEGER_CST
+      || (warn_array_bounds < 2
+	  && array_at_struct_end_p (ref)))
+    {
+      /* Accesses to trailing arrays via pointers may access storage
+	 beyond the types array bounds.  For such arrays, or for flexible
+	 array members, as well as for other arrays of an unknown size,
+	 replace the upper bound with a more permissive one that assumes
+	 the size of the largest object is PTRDIFF_MAX.  */
+      tree eltsize = array_ref_element_size (ref);
+
+      if (TREE_CODE (eltsize) != INTEGER_CST
+	  || integer_zerop (eltsize))
+	{
+	  up_bound = NULL_TREE;
+	  up_bound_p1 = NULL_TREE;
+	}
+      else
+	{
+	  tree maxbound = TYPE_MAX_VALUE (ptrdiff_type_node);
+	  tree arg = TREE_OPERAND (ref, 0);
+	  poly_int64 off;
+
+	  if (get_addr_base_and_unit_offset (arg, &off) && known_gt (off, 0))
+	    maxbound = wide_int_to_tree (sizetype,
+					 wi::sub (wi::to_wide (maxbound),
+						  off));
+	  else
+	    maxbound = fold_convert (sizetype, maxbound);
+
+	  up_bound_p1 = int_const_binop (TRUNC_DIV_EXPR, maxbound, eltsize);
+
+	  up_bound = int_const_binop (MINUS_EXPR, up_bound_p1,
+				      build_int_cst (ptrdiff_type_node, 1));
+	}
+    }
+  else
+    up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound,
+				   build_int_cst (TREE_TYPE (up_bound), 1));
 
   low_bound = array_ref_low_bound (ref);
-  up_bound_p1 = int_const_binop (PLUS_EXPR, up_bound,
-				 build_int_cst (TREE_TYPE (up_bound), 1));
+
+  tree artype = TREE_TYPE (TREE_OPERAND (ref, 0));
+
+  bool warned = false;
 
   /* Empty array.  */
-  if (tree_int_cst_equal (low_bound, up_bound_p1))
-    {
-      warning_at (location, OPT_Warray_bounds,
-		  "array subscript is above array bounds");
-      TREE_NO_WARNING (ref) = 1;
-    }
+  if (up_bound && tree_int_cst_equal (low_bound, up_bound_p1))
+    warned = warning_at (location, OPT_Warray_bounds,
+			 "array subscript %E is above array bounds of %qT",
+			 low_bound, artype);
 
   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->kind () == VR_RANGE ? vr->max () : vr->min ();
+          up_sub = vr->kind () == VR_RANGE ? vr->min () : vr->max ();
         }
     }
 
-  if (vr && vr->type == VR_ANTI_RANGE)
-    {
-      if (TREE_CODE (up_sub) == INTEGER_CST
+  if (vr && vr->kind () == VR_ANTI_RANGE)
+    {
+      if (up_bound
+	  && TREE_CODE (up_sub) == INTEGER_CST
           && (ignore_off_by_one
 	      ? tree_int_cst_lt (up_bound, up_sub)
 	      : tree_int_cst_le (up_bound, up_sub))
           && TREE_CODE (low_sub) == INTEGER_CST
           && tree_int_cst_le (low_sub, low_bound))
-        {
-          warning_at (location, OPT_Warray_bounds,
-		      "array subscript is outside array bounds");
-          TREE_NO_WARNING (ref) = 1;
-        }
-    }
-  else if (TREE_CODE (up_sub) == INTEGER_CST
+	warned = warning_at (location, OPT_Warray_bounds,
+			     "array subscript [%E, %E] is outside "
+			     "array bounds of %qT",
+			     low_sub, up_sub, artype);
+    }
+  else if (up_bound
+	   && TREE_CODE (up_sub) == INTEGER_CST
 	   && (ignore_off_by_one
 	       ? !tree_int_cst_le (up_sub, up_bound_p1)
 	       : !tree_int_cst_le (up_sub, up_bound)))
@@ -6733,9 +4354,9 @@
 	  dump_generic_expr (MSG_NOTE, TDF_SLIM, ref);
 	  fprintf (dump_file, "\n");
 	}
-      warning_at (location, OPT_Warray_bounds,
-		  "array subscript is above array bounds");
-      TREE_NO_WARNING (ref) = 1;
+      warned = warning_at (location, OPT_Warray_bounds,
+			   "array subscript %E is above array bounds of %qT",
+			   up_sub, artype);
     }
   else if (TREE_CODE (low_sub) == INTEGER_CST
            && tree_int_cst_lt (low_sub, low_bound))
@@ -6746,8 +4367,286 @@
 	  dump_generic_expr (MSG_NOTE, TDF_SLIM, ref);
 	  fprintf (dump_file, "\n");
 	}
+      warned = warning_at (location, OPT_Warray_bounds,
+			   "array subscript %E is below array bounds of %qT",
+			   low_sub, artype);
+    }
+
+  if (warned)
+    {
+      ref = TREE_OPERAND (ref, 0);
+
+      if (DECL_P (ref))
+	inform (DECL_SOURCE_LOCATION (ref), "while referencing %qD", ref);
+
+      TREE_NO_WARNING (ref) = 1;
+    }
+}
+
+/* Checks one MEM_REF in REF, located at LOCATION, for out-of-bounds
+   references to string constants.  If VRP can determine that the array
+   subscript is a constant, check if it is outside valid range.
+   If the array subscript is a RANGE, warn if it is non-overlapping
+   with valid range.
+   IGNORE_OFF_BY_ONE is true if the MEM_REF is inside an ADDR_EXPR
+   (used to allow one-past-the-end indices for code that takes
+   the address of the just-past-the-end element of an array).  */
+
+void
+vrp_prop::check_mem_ref (location_t location, tree ref,
+			 bool ignore_off_by_one)
+{
+  if (TREE_NO_WARNING (ref))
+    return;
+
+  tree arg = TREE_OPERAND (ref, 0);
+  /* The constant and variable offset of the reference.  */
+  tree cstoff = TREE_OPERAND (ref, 1);
+  tree varoff = NULL_TREE;
+
+  const offset_int maxobjsize = tree_to_shwi (max_object_size ());
+
+  /* The array or string constant bounds in bytes.  Initially set
+     to [-MAXOBJSIZE - 1, MAXOBJSIZE]  until a tighter bound is
+     determined.  */
+  offset_int arrbounds[2] = { -maxobjsize - 1, maxobjsize };
+
+  /* The minimum and maximum intermediate offset.  For a reference
+     to be valid, not only does the final offset/subscript must be
+     in bounds but all intermediate offsets should be as well.
+     GCC may be able to deal gracefully with such out-of-bounds
+     offsets so the checking is only enbaled at -Warray-bounds=2
+     where it may help detect bugs in uses of the intermediate
+     offsets that could otherwise not be detectable.  */
+  offset_int ioff = wi::to_offset (fold_convert (ptrdiff_type_node, cstoff));
+  offset_int extrema[2] = { 0, wi::abs (ioff) };
+
+  /* The range of the byte offset into the reference.  */
+  offset_int offrange[2] = { 0, 0 };
+
+  const value_range *vr = NULL;
+
+  /* Determine the offsets and increment OFFRANGE for the bounds of each.
+     The loop computes the the range of the final offset for expressions
+     such as (A + i0 + ... + iN)[CSTOFF] where i0 through iN are SSA_NAMEs
+     in some range.  */
+  while (TREE_CODE (arg) == SSA_NAME)
+    {
+      gimple *def = SSA_NAME_DEF_STMT (arg);
+      if (!is_gimple_assign (def))
+	break;
+
+      tree_code code = gimple_assign_rhs_code (def);
+      if (code == POINTER_PLUS_EXPR)
+	{
+	  arg = gimple_assign_rhs1 (def);
+	  varoff = gimple_assign_rhs2 (def);
+	}
+      else if (code == ASSERT_EXPR)
+	{
+	  arg = TREE_OPERAND (gimple_assign_rhs1 (def), 0);
+	  continue;
+	}
+      else
+	return;
+
+      /* VAROFF should always be a SSA_NAME here (and not even
+	 INTEGER_CST) but there's no point in taking chances.  */
+      if (TREE_CODE (varoff) != SSA_NAME)
+	break;
+
+      vr = get_value_range (varoff);
+      if (!vr || vr->undefined_p () || vr->varying_p ())
+	break;
+
+      if (!vr->constant_p ())
+        break;
+
+      if (vr->kind () == VR_RANGE)
+	{
+	  if (tree_int_cst_lt (vr->min (), vr->max ()))
+	    {
+	      offset_int min
+		= wi::to_offset (fold_convert (ptrdiff_type_node, vr->min ()));
+	      offset_int max
+		= wi::to_offset (fold_convert (ptrdiff_type_node, vr->max ()));
+	      if (min < max)
+		{
+		  offrange[0] += min;
+		  offrange[1] += max;
+		}
+	      else
+		{
+		  offrange[0] += max;
+		  offrange[1] += min;
+		}
+	    }
+	  else
+	    {
+	      /* Conservatively add [-MAXOBJSIZE -1, MAXOBJSIZE]
+		 to OFFRANGE.  */
+	      offrange[0] += arrbounds[0];
+	      offrange[1] += arrbounds[1];
+	    }
+	}
+      else
+	{
+	  /* For an anti-range, analogously to the above, conservatively
+	     add [-MAXOBJSIZE -1, MAXOBJSIZE] to OFFRANGE.  */
+	  offrange[0] += arrbounds[0];
+	  offrange[1] += arrbounds[1];
+	}
+
+      /* Keep track of the minimum and maximum offset.  */
+      if (offrange[1] < 0 && offrange[1] < extrema[0])
+	extrema[0] = offrange[1];
+      if (offrange[0] > 0 && offrange[0] > extrema[1])
+	extrema[1] = offrange[0];
+
+      if (offrange[0] < arrbounds[0])
+	offrange[0] = arrbounds[0];
+
+      if (offrange[1] > arrbounds[1])
+	offrange[1] = arrbounds[1];
+    }
+
+  if (TREE_CODE (arg) == ADDR_EXPR)
+    {
+      arg = TREE_OPERAND (arg, 0);
+      if (TREE_CODE (arg) != STRING_CST
+	  && TREE_CODE (arg) != VAR_DECL)
+	return;
+    }
+  else
+    return;
+
+  /* The type of the object being referred to.  It can be an array,
+     string literal, or a non-array type when the MEM_REF represents
+     a reference/subscript via a pointer to an object that is not
+     an element of an array.  References to members of structs and
+     unions are excluded because MEM_REF doesn't make it possible
+     to identify the member where the reference originated.
+     Incomplete types are excluded as well because their size is
+     not known.  */
+  tree reftype = TREE_TYPE (arg);
+  if (POINTER_TYPE_P (reftype)
+      || !COMPLETE_TYPE_P (reftype)
+      || TREE_CODE (TYPE_SIZE_UNIT (reftype)) != INTEGER_CST
+      || RECORD_OR_UNION_TYPE_P (reftype))
+    return;
+
+  offset_int eltsize;
+  if (TREE_CODE (reftype) == ARRAY_TYPE)
+    {
+      eltsize = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (reftype)));
+
+      if (tree dom = TYPE_DOMAIN (reftype))
+	{
+	  tree bnds[] = { TYPE_MIN_VALUE (dom), TYPE_MAX_VALUE (dom) };
+	  if (array_at_struct_end_p (arg)
+	      || !bnds[0] || !bnds[1])
+	    {
+	      arrbounds[0] = 0;
+	      arrbounds[1] = wi::lrshift (maxobjsize, wi::floor_log2 (eltsize));
+	    }
+	  else
+	    {
+	      arrbounds[0] = wi::to_offset (bnds[0]) * eltsize;
+	      arrbounds[1] = (wi::to_offset (bnds[1]) + 1) * eltsize;
+	    }
+	}
+      else
+	{
+	  arrbounds[0] = 0;
+	  arrbounds[1] = wi::lrshift (maxobjsize, wi::floor_log2 (eltsize));
+	}
+
+      if (TREE_CODE (ref) == MEM_REF)
+	{
+	  /* For MEM_REF determine a tighter bound of the non-array
+	     element type.  */
+	  tree eltype = TREE_TYPE (reftype);
+	  while (TREE_CODE (eltype) == ARRAY_TYPE)
+	    eltype = TREE_TYPE (eltype);
+	  eltsize = wi::to_offset (TYPE_SIZE_UNIT (eltype));
+	}
+    }
+  else
+    {
+      eltsize = 1;
+      arrbounds[0] = 0;
+      arrbounds[1] = wi::to_offset (TYPE_SIZE_UNIT (reftype));
+    }
+
+  offrange[0] += ioff;
+  offrange[1] += ioff;
+
+  /* Compute the more permissive upper bound when IGNORE_OFF_BY_ONE
+     is set (when taking the address of the one-past-last element
+     of an array) but always use the stricter bound in diagnostics. */
+  offset_int ubound = arrbounds[1];
+  if (ignore_off_by_one)
+    ubound += 1;
+
+  if (offrange[0] >= ubound || offrange[1] < arrbounds[0])
+    {
+      /* Treat a reference to a non-array object as one to an array
+	 of a single element.  */
+      if (TREE_CODE (reftype) != ARRAY_TYPE)
+	reftype = build_array_type_nelts (reftype, 1);
+
+      if (TREE_CODE (ref) == MEM_REF)
+	{
+	  /* Extract the element type out of MEM_REF and use its size
+	     to compute the index to print in the diagnostic; arrays
+	     in MEM_REF don't mean anything.   */
+	  tree type = TREE_TYPE (ref);
+	  while (TREE_CODE (type) == ARRAY_TYPE)
+	    type = TREE_TYPE (type);
+	  tree size = TYPE_SIZE_UNIT (type);
+	  offrange[0] = offrange[0] / wi::to_offset (size);
+	  offrange[1] = offrange[1] / wi::to_offset (size);
+	}
+      else
+	{
+	  /* For anything other than MEM_REF, compute the index to
+	     print in the diagnostic as the offset over element size.  */
+	  offrange[0] = offrange[0] / eltsize;
+	  offrange[1] = offrange[1] / eltsize;
+	}
+
+      bool warned;
+      if (offrange[0] == offrange[1])
+	warned = warning_at (location, OPT_Warray_bounds,
+			     "array subscript %wi is outside array bounds "
+			     "of %qT",
+			     offrange[0].to_shwi (), reftype);
+      else
+	warned = warning_at (location, OPT_Warray_bounds,
+			     "array subscript [%wi, %wi] is outside "
+			     "array bounds of %qT",
+			     offrange[0].to_shwi (),
+			     offrange[1].to_shwi (), reftype);
+      if (warned && DECL_P (arg))
+	inform (DECL_SOURCE_LOCATION (arg), "while referencing %qD", arg);
+
+      TREE_NO_WARNING (ref) = 1;
+      return;
+    }
+
+  if (warn_array_bounds < 2)
+    return;
+
+  /* At level 2 check also intermediate offsets.  */
+  int i = 0;
+  if (extrema[i] < -arrbounds[1] || extrema[i = 1] > ubound)
+    {
+      HOST_WIDE_INT tmpidx = extrema[i].to_shwi () / eltsize.to_shwi ();
+
       warning_at (location, OPT_Warray_bounds,
-		  "array subscript is below array bounds");
+		  "intermediate array offset %wi is outside array bounds "
+		  "of %qT",
+		  tmpidx,  reftype);
       TREE_NO_WARNING (ref) = 1;
     }
 }
@@ -6755,69 +4654,84 @@
 /* Searches if the expr T, located at LOCATION computes
    address of an ARRAY_REF, and call check_array_ref on it.  */
 
-static void
-search_for_addr_array (tree t, location_t location)
+void
+vrp_prop::search_for_addr_array (tree t, location_t location)
 {
-  /* Check each ARRAY_REFs in the reference chain. */
+  /* Check each ARRAY_REF and MEM_REF in the reference chain. */
   do
     {
       if (TREE_CODE (t) == ARRAY_REF)
 	check_array_ref (location, t, true /*ignore_off_by_one*/);
+      else if (TREE_CODE (t) == MEM_REF)
+	check_mem_ref (location, t, true /*ignore_off_by_one*/);
 
       t = TREE_OPERAND (t, 0);
     }
-  while (handled_component_p (t));
-
-  if (TREE_CODE (t) == MEM_REF
-      && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR
-      && !TREE_NO_WARNING (t))
-    {
-      tree tem = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
-      tree low_bound, up_bound, el_sz;
-      offset_int idx;
-      if (TREE_CODE (TREE_TYPE (tem)) != ARRAY_TYPE
-	  || TREE_CODE (TREE_TYPE (TREE_TYPE (tem))) == ARRAY_TYPE
-	  || !TYPE_DOMAIN (TREE_TYPE (tem)))
-	return;
-
-      low_bound = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (tem)));
-      up_bound = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (tem)));
-      el_sz = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (tem)));
-      if (!low_bound
-	  || TREE_CODE (low_bound) != INTEGER_CST
-	  || !up_bound
-	  || TREE_CODE (up_bound) != INTEGER_CST
-	  || !el_sz
-	  || TREE_CODE (el_sz) != INTEGER_CST)
-	return;
-
-      idx = mem_ref_offset (t);
-      idx = wi::sdiv_trunc (idx, wi::to_offset (el_sz));
-      if (idx < 0)
+  while (handled_component_p (t) || TREE_CODE (t) == MEM_REF);
+
+  if (TREE_CODE (t) != MEM_REF
+      || TREE_CODE (TREE_OPERAND (t, 0)) != ADDR_EXPR
+      || TREE_NO_WARNING (t))
+    return;
+
+  tree tem = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
+  tree low_bound, up_bound, el_sz;
+  if (TREE_CODE (TREE_TYPE (tem)) != ARRAY_TYPE
+      || TREE_CODE (TREE_TYPE (TREE_TYPE (tem))) == ARRAY_TYPE
+      || !TYPE_DOMAIN (TREE_TYPE (tem)))
+    return;
+
+  low_bound = TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (tem)));
+  up_bound = TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (tem)));
+  el_sz = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (tem)));
+  if (!low_bound
+      || TREE_CODE (low_bound) != INTEGER_CST
+      || !up_bound
+      || TREE_CODE (up_bound) != INTEGER_CST
+      || !el_sz
+      || TREE_CODE (el_sz) != INTEGER_CST)
+    return;
+
+  offset_int idx;
+  if (!mem_ref_offset (t).is_constant (&idx))
+    return;
+
+  bool warned = false;
+  idx = wi::sdiv_trunc (idx, wi::to_offset (el_sz));
+  if (idx < 0)
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
 	{
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	    {
-	      fprintf (dump_file, "Array bound warning for ");
-	      dump_generic_expr (MSG_NOTE, TDF_SLIM, t);
-	      fprintf (dump_file, "\n");
-	    }
-	  warning_at (location, OPT_Warray_bounds,
-		      "array subscript is below array bounds");
-	  TREE_NO_WARNING (t) = 1;
+	  fprintf (dump_file, "Array bound warning for ");
+	  dump_generic_expr (MSG_NOTE, TDF_SLIM, t);
+	  fprintf (dump_file, "\n");
 	}
-      else if (idx > (wi::to_offset (up_bound)
-		      - wi::to_offset (low_bound) + 1))
+      warned = warning_at (location, OPT_Warray_bounds,
+			   "array subscript %wi is below "
+			   "array bounds of %qT",
+			   idx.to_shwi (), TREE_TYPE (tem));
+    }
+  else if (idx > (wi::to_offset (up_bound)
+		  - wi::to_offset (low_bound) + 1))
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
 	{
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	    {
-	      fprintf (dump_file, "Array bound warning for ");
-	      dump_generic_expr (MSG_NOTE, TDF_SLIM, t);
-	      fprintf (dump_file, "\n");
-	    }
-	  warning_at (location, OPT_Warray_bounds,
-		      "array subscript is above array bounds");
-	  TREE_NO_WARNING (t) = 1;
+	  fprintf (dump_file, "Array bound warning for ");
+	  dump_generic_expr (MSG_NOTE, TDF_SLIM, t);
+	  fprintf (dump_file, "\n");
 	}
+      warned = warning_at (location, OPT_Warray_bounds,
+			   "array subscript %wu is above "
+			   "array bounds of %qT",
+			   idx.to_uhwi (), TREE_TYPE (tem));
+    }
+
+  if (warned)
+    {
+      if (DECL_P (t))
+	inform (DECL_SOURCE_LOCATION (t), "while referencing %qD", t);
+
+      TREE_NO_WARNING (t) = 1;
     }
 }
 
@@ -6837,64 +4751,85 @@
   if (EXPR_HAS_LOCATION (t))
     location = EXPR_LOCATION (t);
   else
-    {
-      location_t *locp = (location_t *) wi->info;
-      location = *locp;
-    }
+    location = gimple_location (wi->stmt);
 
   *walk_subtree = TRUE;
 
+  vrp_prop *vrp_prop = (class vrp_prop *)wi->info;
   if (TREE_CODE (t) == ARRAY_REF)
-    check_array_ref (location, t, false /*ignore_off_by_one*/);
-
+    vrp_prop->check_array_ref (location, t, false /*ignore_off_by_one*/);
+  else if (TREE_CODE (t) == MEM_REF)
+    vrp_prop->check_mem_ref (location, t, false /*ignore_off_by_one*/);
   else if (TREE_CODE (t) == ADDR_EXPR)
     {
-      search_for_addr_array (t, location);
+      vrp_prop->search_for_addr_array (t, location);
       *walk_subtree = FALSE;
     }
 
   return NULL_TREE;
 }
 
+/* A dom_walker subclass for use by vrp_prop::check_all_array_refs,
+   to walk over all statements of all reachable BBs and call
+   check_array_bounds on them.  */
+
+class check_array_bounds_dom_walker : public dom_walker
+{
+ public:
+  check_array_bounds_dom_walker (vrp_prop *prop)
+    : dom_walker (CDI_DOMINATORS,
+		  /* Discover non-executable edges, preserving EDGE_EXECUTABLE
+		     flags, so that we can merge in information on
+		     non-executable edges from vrp_folder .  */
+		  REACHABLE_BLOCKS_PRESERVING_FLAGS),
+      m_prop (prop) {}
+  ~check_array_bounds_dom_walker () {}
+
+  edge before_dom_children (basic_block) FINAL OVERRIDE;
+
+ private:
+  vrp_prop *m_prop;
+};
+
+/* Implementation of dom_walker::before_dom_children.
+
+   Walk over all statements of BB and call check_array_bounds on them,
+   and determine if there's a unique successor edge.  */
+
+edge
+check_array_bounds_dom_walker::before_dom_children (basic_block bb)
+{
+  gimple_stmt_iterator si;
+  for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
+    {
+      gimple *stmt = gsi_stmt (si);
+      struct walk_stmt_info wi;
+      if (!gimple_has_location (stmt)
+	  || is_gimple_debug (stmt))
+	continue;
+
+      memset (&wi, 0, sizeof (wi));
+
+      wi.info = m_prop;
+
+      walk_gimple_op (stmt, check_array_bounds, &wi);
+    }
+
+  /* Determine if there's a unique successor edge, and if so, return
+     that back to dom_walker, ensuring that we don't visit blocks that
+     became unreachable during the VRP propagation
+     (PR tree-optimization/83312).  */
+  return find_taken_edge (bb, NULL_TREE);
+}
+
 /* Walk over all statements of all reachable BBs and call check_array_bounds
    on them.  */
 
-static void
-check_all_array_refs (void)
+void
+vrp_prop::check_all_array_refs ()
 {
-  basic_block bb;
-  gimple_stmt_iterator si;
-
-  FOR_EACH_BB_FN (bb, cfun)
-    {
-      edge_iterator ei;
-      edge e;
-      bool executable = false;
-
-      /* Skip blocks that were found to be unreachable.  */
-      FOR_EACH_EDGE (e, ei, bb->preds)
-	executable |= !!(e->flags & EDGE_EXECUTABLE);
-      if (!executable)
-	continue;
-
-      for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
-	{
-	  gimple *stmt = gsi_stmt (si);
-	  struct walk_stmt_info wi;
-	  if (!gimple_has_location (stmt)
-	      || is_gimple_debug (stmt))
-	    continue;
-
-	  memset (&wi, 0, sizeof (wi));
-
-	  location_t loc = gimple_location (stmt);
-	  wi.info = &loc;
-
-	  walk_gimple_op (gsi_stmt (si),
-			  check_array_bounds,
-			  &wi);
-	}
-    }
+  check_array_bounds_dom_walker w (this);
+  w.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
 }
 
 /* Return true if all imm uses of VAR are either in STMT, or
@@ -6939,10 +4874,9 @@
    var is the x_3 var from ASSERT_EXPR, we can clear low 5 bits
    from the non-zero bitmask.  */
 
-static void
-maybe_set_nonzero_bits (basic_block bb, tree var)
+void
+maybe_set_nonzero_bits (edge e, tree var)
 {
-  edge e = single_pred_edge (bb);
   basic_block cond_bb = e->src;
   gimple *stmt = last_stmt (cond_bb);
   tree cst;
@@ -7057,7 +4991,7 @@
 		    set_range_info (var, SSA_NAME_RANGE_TYPE (lhs),
 				    SSA_NAME_RANGE_INFO (lhs)->get_min (),
 				    SSA_NAME_RANGE_INFO (lhs)->get_max ());
-		    maybe_set_nonzero_bits (bb, var);
+		    maybe_set_nonzero_bits (single_pred_edge (bb), var);
 		  }
 	      }
 
@@ -7089,10 +5023,9 @@
       }
 }
 
-
 /* Return true if STMT is interesting for VRP.  */
 
-static bool
+bool
 stmt_interesting_for_vrp (gimple *stmt)
 {
   if (gimple_code (stmt) == GIMPLE_PHI)
@@ -7138,22 +5071,10 @@
   return false;
 }
 
-/* Initialize VRP lattice.  */
-
-static void
-vrp_initialize_lattice ()
-{
-  values_propagated = false;
-  num_vr_values = num_ssa_names;
-  vr_value = XCNEWVEC (value_range *, num_vr_values);
-  vr_phi_edge_counts = XCNEWVEC (int, num_ssa_names);
-  bitmap_obstack_initialize (&vrp_equiv_obstack);
-}
-
 /* Initialization required by ssa_propagate engine.  */
 
-static void
-vrp_initialize ()
+void
+vrp_prop::vrp_initialize ()
 {
   basic_block bb;
 
@@ -7194,595 +5115,6 @@
     }
 }
 
-/* Return the singleton value-range for NAME or NAME.  */
-
-static inline tree
-vrp_valueize (tree name)
-{
-  if (TREE_CODE (name) == SSA_NAME)
-    {
-      value_range *vr = get_value_range (name);
-      if (vr->type == VR_RANGE
-	  && (TREE_CODE (vr->min) == SSA_NAME
-	      || is_gimple_min_invariant (vr->min))
-	  && vrp_operand_equal_p (vr->min, vr->max))
-	return vr->min;
-    }
-  return name;
-}
-
-/* Return the singleton value-range for NAME if that is a constant
-   but signal to not follow SSA edges.  */
-
-static inline tree
-vrp_valueize_1 (tree name)
-{
-  if (TREE_CODE (name) == SSA_NAME)
-    {
-      /* If the definition may be simulated again we cannot follow
-         this SSA edge as the SSA propagator does not necessarily
-	 re-visit the use.  */
-      gimple *def_stmt = SSA_NAME_DEF_STMT (name);
-      if (!gimple_nop_p (def_stmt)
-	  && prop_simulate_again_p (def_stmt))
-	return NULL_TREE;
-      value_range *vr = get_value_range (name);
-      if (range_int_cst_singleton_p (vr))
-	return vr->min;
-    }
-  return name;
-}
-
-/* Visit assignment STMT.  If it produces an interesting range, record
-   the range in VR and set LHS to OUTPUT_P.  */
-
-static void
-vrp_visit_assignment_or_call (gimple *stmt, tree *output_p, value_range *vr)
-{
-  tree lhs;
-  enum gimple_code code = gimple_code (stmt);
-  lhs = gimple_get_lhs (stmt);
-  *output_p = NULL_TREE;
-
-  /* We only keep track of ranges in integral and pointer types.  */
-  if (TREE_CODE (lhs) == SSA_NAME
-      && ((INTEGRAL_TYPE_P (TREE_TYPE (lhs))
-	   /* It is valid to have NULL MIN/MAX values on a type.  See
-	      build_range_type.  */
-	   && TYPE_MIN_VALUE (TREE_TYPE (lhs))
-	   && TYPE_MAX_VALUE (TREE_TYPE (lhs)))
-	  || POINTER_TYPE_P (TREE_TYPE (lhs))))
-    {
-      *output_p = lhs;
-
-      /* Try folding the statement to a constant first.  */
-      tree tem = gimple_fold_stmt_to_constant_1 (stmt, vrp_valueize,
-						 vrp_valueize_1);
-      if (tem)
-	{
-	  if (TREE_CODE (tem) == SSA_NAME
-	      && (SSA_NAME_IS_DEFAULT_DEF (tem)
-		  || ! prop_simulate_again_p (SSA_NAME_DEF_STMT (tem))))
-	    {
-	      extract_range_from_ssa_name (vr, tem);
-	      return;
-	    }
-	  else if (is_gimple_min_invariant (tem))
-	    {
-	      set_value_range_to_value (vr, tem, NULL);
-	      return;
-	    }
-	}
-      /* Then dispatch to value-range extracting functions.  */
-      if (code == GIMPLE_CALL)
-	extract_range_basic (vr, stmt);
-      else
-	extract_range_from_assignment (vr, as_a <gassign *> (stmt));
-    }
-}
-
-/* Helper that gets the value range of the SSA_NAME with version I
-   or a symbolic range containing the SSA_NAME only if the value range
-   is varying or undefined.  */
-
-static inline value_range
-get_vr_for_comparison (int i)
-{
-  value_range vr = *get_value_range (ssa_name (i));
-
-  /* If name N_i does not have a valid range, use N_i as its own
-     range.  This allows us to compare against names that may
-     have N_i in their ranges.  */
-  if (vr.type == VR_VARYING || vr.type == VR_UNDEFINED)
-    {
-      vr.type = VR_RANGE;
-      vr.min = ssa_name (i);
-      vr.max = ssa_name (i);
-    }
-
-  return vr;
-}
-
-/* Compare all the value ranges for names equivalent to VAR with VAL
-   using comparison code COMP.  Return the same value returned by
-   compare_range_with_value, including the setting of
-   *STRICT_OVERFLOW_P.  */
-
-static tree
-compare_name_with_value (enum tree_code comp, tree var, tree val,
-			 bool *strict_overflow_p, bool use_equiv_p)
-{
-  bitmap_iterator bi;
-  unsigned i;
-  bitmap e;
-  tree retval, t;
-  int used_strict_overflow;
-  bool sop;
-  value_range equiv_vr;
-
-  /* Get the set of equivalences for VAR.  */
-  e = get_value_range (var)->equiv;
-
-  /* Start at -1.  Set it to 0 if we do a comparison without relying
-     on overflow, or 1 if all comparisons rely on overflow.  */
-  used_strict_overflow = -1;
-
-  /* Compare vars' value range with val.  */
-  equiv_vr = get_vr_for_comparison (SSA_NAME_VERSION (var));
-  sop = false;
-  retval = compare_range_with_value (comp, &equiv_vr, val, &sop);
-  if (retval)
-    used_strict_overflow = sop ? 1 : 0;
-
-  /* If the equiv set is empty we have done all work we need to do.  */
-  if (e == NULL)
-    {
-      if (retval
-	  && used_strict_overflow > 0)
-	*strict_overflow_p = true;
-      return retval;
-    }
-
-  EXECUTE_IF_SET_IN_BITMAP (e, 0, i, bi)
-    {
-      tree name = ssa_name (i);
-      if (! name)
-	continue;
-
-      if (! use_equiv_p
-	  && ! SSA_NAME_IS_DEFAULT_DEF (name)
-	  && prop_simulate_again_p (SSA_NAME_DEF_STMT (name)))
-	continue;
-
-      equiv_vr = get_vr_for_comparison (i);
-      sop = false;
-      t = compare_range_with_value (comp, &equiv_vr, val, &sop);
-      if (t)
-	{
-	  /* If we get different answers from different members
-	     of the equivalence set this check must be in a dead
-	     code region.  Folding it to a trap representation
-	     would be correct here.  For now just return don't-know.  */
-	  if (retval != NULL
-	      && t != retval)
-	    {
-	      retval = NULL_TREE;
-	      break;
-	    }
-	  retval = t;
-
-	  if (!sop)
-	    used_strict_overflow = 0;
-	  else if (used_strict_overflow < 0)
-	    used_strict_overflow = 1;
-	}
-    }
-
-  if (retval
-      && used_strict_overflow > 0)
-    *strict_overflow_p = true;
-
-  return retval;
-}
-
-
-/* Given a comparison code COMP and names N1 and N2, compare all the
-   ranges equivalent to N1 against all the ranges equivalent to N2
-   to determine the value of N1 COMP N2.  Return the same value
-   returned by compare_ranges.  Set *STRICT_OVERFLOW_P to indicate
-   whether we relied on undefined signed overflow in the comparison.  */
-
-
-static tree
-compare_names (enum tree_code comp, tree n1, tree n2,
-	       bool *strict_overflow_p)
-{
-  tree t, retval;
-  bitmap e1, e2;
-  bitmap_iterator bi1, bi2;
-  unsigned i1, i2;
-  int used_strict_overflow;
-  static bitmap_obstack *s_obstack = NULL;
-  static bitmap s_e1 = NULL, s_e2 = NULL;
-
-  /* Compare the ranges of every name equivalent to N1 against the
-     ranges of every name equivalent to N2.  */
-  e1 = get_value_range (n1)->equiv;
-  e2 = get_value_range (n2)->equiv;
-
-  /* Use the fake bitmaps if e1 or e2 are not available.  */
-  if (s_obstack == NULL)
-    {
-      s_obstack = XNEW (bitmap_obstack);
-      bitmap_obstack_initialize (s_obstack);
-      s_e1 = BITMAP_ALLOC (s_obstack);
-      s_e2 = BITMAP_ALLOC (s_obstack);
-    }
-  if (e1 == NULL)
-    e1 = s_e1;
-  if (e2 == NULL)
-    e2 = s_e2;
-
-  /* Add N1 and N2 to their own set of equivalences to avoid
-     duplicating the body of the loop just to check N1 and N2
-     ranges.  */
-  bitmap_set_bit (e1, SSA_NAME_VERSION (n1));
-  bitmap_set_bit (e2, SSA_NAME_VERSION (n2));
-
-  /* If the equivalence sets have a common intersection, then the two
-     names can be compared without checking their ranges.  */
-  if (bitmap_intersect_p (e1, e2))
-    {
-      bitmap_clear_bit (e1, SSA_NAME_VERSION (n1));
-      bitmap_clear_bit (e2, SSA_NAME_VERSION (n2));
-
-      return (comp == EQ_EXPR || comp == GE_EXPR || comp == LE_EXPR)
-	     ? boolean_true_node
-	     : boolean_false_node;
-    }
-
-  /* Start at -1.  Set it to 0 if we do a comparison without relying
-     on overflow, or 1 if all comparisons rely on overflow.  */
-  used_strict_overflow = -1;
-
-  /* Otherwise, compare all the equivalent ranges.  First, add N1 and
-     N2 to their own set of equivalences to avoid duplicating the body
-     of the loop just to check N1 and N2 ranges.  */
-  EXECUTE_IF_SET_IN_BITMAP (e1, 0, i1, bi1)
-    {
-      if (! ssa_name (i1))
-	continue;
-
-      value_range vr1 = get_vr_for_comparison (i1);
-
-      t = retval = NULL_TREE;
-      EXECUTE_IF_SET_IN_BITMAP (e2, 0, i2, bi2)
-	{
-	  if (! ssa_name (i2))
-	    continue;
-
-	  bool sop = false;
-
-	  value_range vr2 = get_vr_for_comparison (i2);
-
-	  t = compare_ranges (comp, &vr1, &vr2, &sop);
-	  if (t)
-	    {
-	      /* If we get different answers from different members
-		 of the equivalence set this check must be in a dead
-		 code region.  Folding it to a trap representation
-		 would be correct here.  For now just return don't-know.  */
-	      if (retval != NULL
-		  && t != retval)
-		{
-		  bitmap_clear_bit (e1, SSA_NAME_VERSION (n1));
-		  bitmap_clear_bit (e2, SSA_NAME_VERSION (n2));
-		  return NULL_TREE;
-		}
-	      retval = t;
-
-	      if (!sop)
-		used_strict_overflow = 0;
-	      else if (used_strict_overflow < 0)
-		used_strict_overflow = 1;
-	    }
-	}
-
-      if (retval)
-	{
-	  bitmap_clear_bit (e1, SSA_NAME_VERSION (n1));
-	  bitmap_clear_bit (e2, SSA_NAME_VERSION (n2));
-	  if (used_strict_overflow > 0)
-	    *strict_overflow_p = true;
-	  return retval;
-	}
-    }
-
-  /* None of the equivalent ranges are useful in computing this
-     comparison.  */
-  bitmap_clear_bit (e1, SSA_NAME_VERSION (n1));
-  bitmap_clear_bit (e2, SSA_NAME_VERSION (n2));
-  return NULL_TREE;
-}
-
-/* Helper function for vrp_evaluate_conditional_warnv & other
-   optimizers.  */
-
-static tree
-vrp_evaluate_conditional_warnv_with_ops_using_ranges (enum tree_code code,
-						      tree op0, tree op1,
-						      bool * strict_overflow_p)
-{
-  value_range *vr0, *vr1;
-
-  vr0 = (TREE_CODE (op0) == SSA_NAME) ? get_value_range (op0) : NULL;
-  vr1 = (TREE_CODE (op1) == SSA_NAME) ? get_value_range (op1) : NULL;
-
-  tree res = NULL_TREE;
-  if (vr0 && vr1)
-    res = compare_ranges (code, vr0, vr1, strict_overflow_p);
-  if (!res && vr0)
-    res = compare_range_with_value (code, vr0, op1, strict_overflow_p);
-  if (!res && vr1)
-    res = (compare_range_with_value
-	    (swap_tree_comparison (code), vr1, op0, strict_overflow_p));
-  return res;
-}
-
-/* Helper function for vrp_evaluate_conditional_warnv. */
-
-static tree
-vrp_evaluate_conditional_warnv_with_ops (enum tree_code code, tree op0,
-					 tree op1, bool use_equiv_p,
-					 bool *strict_overflow_p, bool *only_ranges)
-{
-  tree ret;
-  if (only_ranges)
-    *only_ranges = true;
-
-  /* We only deal with integral and pointer types.  */
-  if (!INTEGRAL_TYPE_P (TREE_TYPE (op0))
-      && !POINTER_TYPE_P (TREE_TYPE (op0)))
-    return NULL_TREE;
-
-  /* If OP0 CODE OP1 is an overflow comparison, if it can be expressed
-     as a simple equality test, then prefer that over its current form
-     for evaluation.
-
-     An overflow test which collapses to an equality test can always be
-     expressed as a comparison of one argument against zero.  Overflow
-     occurs when the chosen argument is zero and does not occur if the
-     chosen argument is not zero.  */
-  tree x;
-  if (overflow_comparison_p (code, op0, op1, use_equiv_p, &x))
-    {
-      wide_int max = wi::max_value (TYPE_PRECISION (TREE_TYPE (op0)), UNSIGNED);
-      /* B = A - 1; if (A < B) -> B = A - 1; if (A == 0)
-         B = A - 1; if (A > B) -> B = A - 1; if (A != 0)
-         B = A + 1; if (B < A) -> B = A + 1; if (B == 0)
-         B = A + 1; if (B > A) -> B = A + 1; if (B != 0) */
-      if (integer_zerop (x))
-	{
-	  op1 = x;
-	  code = (code == LT_EXPR || code == LE_EXPR) ? EQ_EXPR : NE_EXPR;
-	}
-      /* B = A + 1; if (A > B) -> B = A + 1; if (B == 0)
-         B = A + 1; if (A < B) -> B = A + 1; if (B != 0)
-         B = A - 1; if (B > A) -> B = A - 1; if (A == 0)
-         B = A - 1; if (B < A) -> B = A - 1; if (A != 0) */
-      else if (wi::to_wide (x) == max - 1)
-	{
-	  op0 = op1;
-	  op1 = wide_int_to_tree (TREE_TYPE (op0), 0);
-	  code = (code == GT_EXPR || code == GE_EXPR) ? EQ_EXPR : NE_EXPR;
-	}
-    }
-
-  if ((ret = vrp_evaluate_conditional_warnv_with_ops_using_ranges
-	       (code, op0, op1, strict_overflow_p)))
-    return ret;
-  if (only_ranges)
-    *only_ranges = false;
-  /* Do not use compare_names during propagation, it's quadratic.  */
-  if (TREE_CODE (op0) == SSA_NAME && TREE_CODE (op1) == SSA_NAME
-      && use_equiv_p)
-    return compare_names (code, op0, op1, strict_overflow_p);
-  else if (TREE_CODE (op0) == SSA_NAME)
-    return compare_name_with_value (code, op0, op1,
-				    strict_overflow_p, use_equiv_p);
-  else if (TREE_CODE (op1) == SSA_NAME)
-    return compare_name_with_value (swap_tree_comparison (code), op1, op0,
-				    strict_overflow_p, use_equiv_p);
-  return NULL_TREE;
-}
-
-/* Given (CODE OP0 OP1) within STMT, try to simplify it based on value range
-   information.  Return NULL if the conditional can not be evaluated.
-   The ranges of all the names equivalent with the operands in COND
-   will be used when trying to compute the value.  If the result is
-   based on undefined signed overflow, issue a warning if
-   appropriate.  */
-
-static tree
-vrp_evaluate_conditional (tree_code code, tree op0, tree op1, gimple *stmt)
-{
-  bool sop;
-  tree ret;
-  bool only_ranges;
-
-  /* Some passes and foldings leak constants with overflow flag set
-     into the IL.  Avoid doing wrong things with these and bail out.  */
-  if ((TREE_CODE (op0) == INTEGER_CST
-       && TREE_OVERFLOW (op0))
-      || (TREE_CODE (op1) == INTEGER_CST
-	  && TREE_OVERFLOW (op1)))
-    return NULL_TREE;
-
-  sop = false;
-  ret = vrp_evaluate_conditional_warnv_with_ops (code, op0, op1, true, &sop,
-  						 &only_ranges);
-
-  if (ret && sop)
-    {
-      enum warn_strict_overflow_code wc;
-      const char* warnmsg;
-
-      if (is_gimple_min_invariant (ret))
-	{
-	  wc = WARN_STRICT_OVERFLOW_CONDITIONAL;
-	  warnmsg = G_("assuming signed overflow does not occur when "
-		       "simplifying conditional to constant");
-	}
-      else
-	{
-	  wc = WARN_STRICT_OVERFLOW_COMPARISON;
-	  warnmsg = G_("assuming signed overflow does not occur when "
-		       "simplifying conditional");
-	}
-
-      if (issue_strict_overflow_warning (wc))
-	{
-	  location_t location;
-
-	  if (!gimple_has_location (stmt))
-	    location = input_location;
-	  else
-	    location = gimple_location (stmt);
-	  warning_at (location, OPT_Wstrict_overflow, "%s", warnmsg);
-	}
-    }
-
-  if (warn_type_limits
-      && ret && only_ranges
-      && TREE_CODE_CLASS (code) == tcc_comparison
-      && TREE_CODE (op0) == SSA_NAME)
-    {
-      /* If the comparison is being folded and the operand on the LHS
-	 is being compared against a constant value that is outside of
-	 the natural range of OP0's type, then the predicate will
-	 always fold regardless of the value of OP0.  If -Wtype-limits
-	 was specified, emit a warning.  */
-      tree type = TREE_TYPE (op0);
-      value_range *vr0 = get_value_range (op0);
-
-      if (vr0->type == VR_RANGE
-	  && INTEGRAL_TYPE_P (type)
-	  && vrp_val_is_min (vr0->min)
-	  && vrp_val_is_max (vr0->max)
-	  && is_gimple_min_invariant (op1))
-	{
-	  location_t location;
-
-	  if (!gimple_has_location (stmt))
-	    location = input_location;
-	  else
-	    location = gimple_location (stmt);
-
-	  warning_at (location, OPT_Wtype_limits,
-		      integer_zerop (ret)
-		      ? G_("comparison always false "
-                           "due to limited range of data type")
-		      : G_("comparison always true "
-                           "due to limited range of data type"));
-	}
-    }
-
-  return ret;
-}
-
-
-/* Visit conditional statement STMT.  If we can determine which edge
-   will be taken out of STMT's basic block, record it in
-   *TAKEN_EDGE_P.  Otherwise, set *TAKEN_EDGE_P to NULL.  */
-
-static void
-vrp_visit_cond_stmt (gcond *stmt, edge *taken_edge_p)
-{
-  tree val;
-
-  *taken_edge_p = NULL;
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      tree use;
-      ssa_op_iter i;
-
-      fprintf (dump_file, "\nVisiting conditional with predicate: ");
-      print_gimple_stmt (dump_file, stmt, 0);
-      fprintf (dump_file, "\nWith known ranges\n");
-
-      FOR_EACH_SSA_TREE_OPERAND (use, stmt, i, SSA_OP_USE)
-	{
-	  fprintf (dump_file, "\t");
-	  print_generic_expr (dump_file, use);
-	  fprintf (dump_file, ": ");
-	  dump_value_range (dump_file, vr_value[SSA_NAME_VERSION (use)]);
-	}
-
-      fprintf (dump_file, "\n");
-    }
-
-  /* Compute the value of the predicate COND by checking the known
-     ranges of each of its operands.
-
-     Note that we cannot evaluate all the equivalent ranges here
-     because those ranges may not yet be final and with the current
-     propagation strategy, we cannot determine when the value ranges
-     of the names in the equivalence set have changed.
-
-     For instance, given the following code fragment
-
-        i_5 = PHI <8, i_13>
-	...
-     	i_14 = ASSERT_EXPR <i_5, i_5 != 0>
-	if (i_14 == 1)
-	  ...
-
-     Assume that on the first visit to i_14, i_5 has the temporary
-     range [8, 8] because the second argument to the PHI function is
-     not yet executable.  We derive the range ~[0, 0] for i_14 and the
-     equivalence set { i_5 }.  So, when we visit 'if (i_14 == 1)' for
-     the first time, since i_14 is equivalent to the range [8, 8], we
-     determine that the predicate is always false.
-
-     On the next round of propagation, i_13 is determined to be
-     VARYING, which causes i_5 to drop down to VARYING.  So, another
-     visit to i_14 is scheduled.  In this second visit, we compute the
-     exact same range and equivalence set for i_14, namely ~[0, 0] and
-     { i_5 }.  But we did not have the previous range for i_5
-     registered, so vrp_visit_assignment thinks that the range for
-     i_14 has not changed.  Therefore, the predicate 'if (i_14 == 1)'
-     is not visited again, which stops propagation from visiting
-     statements in the THEN clause of that if().
-
-     To properly fix this we would need to keep the previous range
-     value for the names in the equivalence set.  This way we would've
-     discovered that from one visit to the other i_5 changed from
-     range [8, 8] to VR_VARYING.
-
-     However, fixing this apparent limitation may not be worth the
-     additional checking.  Testing on several code bases (GCC, DLV,
-     MICO, TRAMP3D and SPEC2000) showed that doing this results in
-     4 more predicates folded in SPEC.  */
-
-  bool sop;
-  val = vrp_evaluate_conditional_warnv_with_ops (gimple_cond_code (stmt),
-						 gimple_cond_lhs (stmt),
-						 gimple_cond_rhs (stmt),
-						 false, &sop, NULL);
-  if (val)
-    *taken_edge_p = find_taken_edge (gimple_bb (stmt), val);
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "\nPredicate evaluates to: ");
-      if (val == NULL_TREE)
-	fprintf (dump_file, "DON'T KNOW\n");
-      else
-	print_generic_stmt (dump_file, val);
-    }
-}
-
 /* Searches the case label vector VEC for the index *IDX of the CASE_LABEL
    that includes the value VAL.  The search is restricted to the range
    [START_IDX, n - 1] where n is the size of VEC.
@@ -7796,7 +5128,7 @@
    If VAL is larger than any CASE_LABEL, n is placed on IDX and false is
    returned. */
 
-static bool
+bool
 find_case_label_index (gswitch *stmt, size_t start_idx, tree val, size_t *idx)
 {
   size_t n = gimple_switch_num_labels (stmt);
@@ -7846,7 +5178,7 @@
    then MAX_IDX < MIN_IDX.
    Returns true if the default label is not needed. */
 
-static bool
+bool
 find_case_label_range (gswitch *stmt, tree min, tree max, size_t *min_idx,
 		       size_t *max_idx)
 {
@@ -7897,201 +5229,6 @@
     }
 }
 
-/* Searches the case label vector VEC for the ranges of CASE_LABELs that are
-   used in range VR.  The indices are placed in MIN_IDX1, MAX_IDX, MIN_IDX2 and
-   MAX_IDX2.  If the ranges of CASE_LABELs are empty then MAX_IDX1 < MIN_IDX1.
-   Returns true if the default label is not needed.  */
-
-static bool
-find_case_label_ranges (gswitch *stmt, value_range *vr, size_t *min_idx1,
-			size_t *max_idx1, size_t *min_idx2,
-			size_t *max_idx2)
-{
-  size_t i, j, k, l;
-  unsigned int n = gimple_switch_num_labels (stmt);
-  bool take_default;
-  tree case_low, case_high;
-  tree min = vr->min, max = vr->max;
-
-  gcc_checking_assert (vr->type == VR_RANGE || vr->type == VR_ANTI_RANGE);
-
-  take_default = !find_case_label_range (stmt, min, max, &i, &j);
-
-  /* Set second range to emtpy.  */
-  *min_idx2 = 1;
-  *max_idx2 = 0;
-
-  if (vr->type == VR_RANGE)
-    {
-      *min_idx1 = i;
-      *max_idx1 = j;
-      return !take_default;
-    }
-
-  /* Set first range to all case labels.  */
-  *min_idx1 = 1;
-  *max_idx1 = n - 1;
-
-  if (i > j)
-    return false;
-
-  /* Make sure all the values of case labels [i , j] are contained in
-     range [MIN, MAX].  */
-  case_low = CASE_LOW (gimple_switch_label (stmt, i));
-  case_high = CASE_HIGH (gimple_switch_label (stmt, j));
-  if (tree_int_cst_compare (case_low, min) < 0)
-    i += 1;
-  if (case_high != NULL_TREE
-      && tree_int_cst_compare (max, case_high) < 0)
-    j -= 1;
-
-  if (i > j)
-    return false;
-
-  /* If the range spans case labels [i, j], the corresponding anti-range spans
-     the labels [1, i - 1] and [j + 1, n -  1].  */
-  k = j + 1;
-  l = n - 1;
-  if (k > l)
-    {
-      k = 1;
-      l = 0;
-    }
-
-  j = i - 1;
-  i = 1;
-  if (i > j)
-    {
-      i = k;
-      j = l;
-      k = 1;
-      l = 0;
-    }
-
-  *min_idx1 = i;
-  *max_idx1 = j;
-  *min_idx2 = k;
-  *max_idx2 = l;
-  return false;
-}
-
-/* Visit switch statement STMT.  If we can determine which edge
-   will be taken out of STMT's basic block, record it in
-   *TAKEN_EDGE_P.  Otherwise, *TAKEN_EDGE_P set to NULL.  */
-
-static void
-vrp_visit_switch_stmt (gswitch *stmt, edge *taken_edge_p)
-{
-  tree op, val;
-  value_range *vr;
-  size_t i = 0, j = 0, k, l;
-  bool take_default;
-
-  *taken_edge_p = NULL;
-  op = gimple_switch_index (stmt);
-  if (TREE_CODE (op) != SSA_NAME)
-    return;
-
-  vr = get_value_range (op);
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "\nVisiting switch expression with operand ");
-      print_generic_expr (dump_file, op);
-      fprintf (dump_file, " with known range ");
-      dump_value_range (dump_file, vr);
-      fprintf (dump_file, "\n");
-    }
-
-  if ((vr->type != VR_RANGE
-       && vr->type != VR_ANTI_RANGE)
-      || symbolic_range_p (vr))
-    return;
-
-  /* Find the single edge that is taken from the switch expression.  */
-  take_default = !find_case_label_ranges (stmt, vr, &i, &j, &k, &l);
-
-  /* Check if the range spans no CASE_LABEL. If so, we only reach the default
-     label */
-  if (j < i)
-    {
-      gcc_assert (take_default);
-      val = gimple_switch_default_label (stmt);
-    }
-  else
-    {
-      /* Check if labels with index i to j and maybe the default label
-	 are all reaching the same label.  */
-
-      val = gimple_switch_label (stmt, i);
-      if (take_default
-	  && CASE_LABEL (gimple_switch_default_label (stmt))
-	  != CASE_LABEL (val))
-	{
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	    fprintf (dump_file, "  not a single destination for this "
-		     "range\n");
-	  return;
-	}
-      for (++i; i <= j; ++i)
-        {
-          if (CASE_LABEL (gimple_switch_label (stmt, i)) != CASE_LABEL (val))
-	    {
-	      if (dump_file && (dump_flags & TDF_DETAILS))
-		fprintf (dump_file, "  not a single destination for this "
-			 "range\n");
-	      return;
-	    }
-        }
-      for (; k <= l; ++k)
-        {
-          if (CASE_LABEL (gimple_switch_label (stmt, k)) != CASE_LABEL (val))
-	    {
-	      if (dump_file && (dump_flags & TDF_DETAILS))
-		fprintf (dump_file, "  not a single destination for this "
-			 "range\n");
-	      return;
-	    }
-        }
-    }
-
-  *taken_edge_p = find_edge (gimple_bb (stmt),
-			     label_to_block (CASE_LABEL (val)));
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "  will take edge to ");
-      print_generic_stmt (dump_file, CASE_LABEL (val));
-    }
-}
-
-
-/* Evaluate statement STMT.  If the statement produces a useful range,
-   set VR and corepsponding OUTPUT_P.
-
-   If STMT is a conditional branch and we can determine its truth
-   value, the taken edge is recorded in *TAKEN_EDGE_P.  */
-
-static void
-extract_range_from_stmt (gimple *stmt, edge *taken_edge_p,
-			 tree *output_p, value_range *vr)
-{
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "\nVisiting statement:\n");
-      print_gimple_stmt (dump_file, stmt, 0, dump_flags);
-    }
-
-  if (!stmt_interesting_for_vrp (stmt))
-    gcc_assert (stmt_ends_bb_p (stmt));
-  else if (is_gimple_assign (stmt) || is_gimple_call (stmt))
-    vrp_visit_assignment_or_call (stmt, output_p, vr);
-  else if (gimple_code (stmt) == GIMPLE_COND)
-    vrp_visit_cond_stmt (as_a <gcond *> (stmt), taken_edge_p);
-  else if (gimple_code (stmt) == GIMPLE_SWITCH)
-    vrp_visit_switch_stmt (as_a <gswitch *> (stmt), taken_edge_p);
-}
-
 /* Evaluate statement STMT.  If the statement produces a useful range,
    return SSA_PROP_INTERESTING and record the SSA name with the
    interesting range into *OUTPUT_P.
@@ -8101,11 +5238,11 @@
 
    If STMT produces a varying value, return SSA_PROP_VARYING.  */
 
-static enum ssa_prop_result
-vrp_visit_stmt (gimple *stmt, edge *taken_edge_p, tree *output_p)
+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;
   extract_range_from_stmt (stmt, taken_edge_p, output_p, &vr);
 
   if (*output_p)
@@ -8121,7 +5258,7 @@
 	      fprintf (dump_file, "\n");
 	    }
 
-	  if (vr.type == VR_VARYING)
+	  if (vr.varying_p ())
 	    return SSA_PROP_VARYING;
 
 	  return SSA_PROP_INTERESTING;
@@ -8174,17 +5311,14 @@
 		   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;
 		extract_range_basic (&new_vr, use_stmt);
-		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))
+		const value_range *old_vr = get_value_range (use_lhs);
+		if (*old_vr != new_vr)
 		  res = SSA_PROP_INTERESTING;
 		else
 		  res = SSA_PROP_NOT_INTERESTING;
-		BITMAP_FREE (new_vr.equiv);
+		new_vr.equiv_clear ();
 		if (res == SSA_PROP_INTERESTING)
 		  {
 		    *output_p = lhs;
@@ -8212,9 +5346,9 @@
    possible such range.  The resulting range is not canonicalized.  */
 
 static void
-union_ranges (enum value_range_type *vr0type,
+union_ranges (enum value_range_kind *vr0type,
 	      tree *vr0min, tree *vr0max,
-	      enum value_range_type vr1type,
+	      enum value_range_kind vr1type,
 	      tree vr1min, tree vr1max)
 {
   bool mineq = vrp_operand_equal_p (*vr0min, vr1min);
@@ -8456,9 +5590,9 @@
 	  if (TREE_CODE (*vr0min) == INTEGER_CST)
 	    {
 	      *vr0type = vr1type;
-	      *vr0min = vr1min;
 	      *vr0max = int_const_binop (MINUS_EXPR, *vr0min,
 					 build_int_cst (TREE_TYPE (*vr0min), 1));
+	      *vr0min = vr1min;
 	    }
 	  else
 	    goto give_up;
@@ -8483,9 +5617,9 @@
    possible such range.  The resulting range is not canonicalized.  */
 
 static void
-intersect_ranges (enum value_range_type *vr0type,
+intersect_ranges (enum value_range_kind *vr0type,
 		  tree *vr0min, tree *vr0max,
-		  enum value_range_type vr1type,
+		  enum value_range_kind vr1type,
 		  tree vr1min, tree vr1max)
 {
   bool mineq = vrp_operand_equal_p (*vr0min, vr1min);
@@ -8674,11 +5808,14 @@
 		   && vrp_val_is_max (vr1max))
 	    ;
 	  /* Choose the anti-range if it is ~[0,0], that range is special
-	     enough to special case when vr1's range is relatively wide.  */
+	     enough to special case when vr1's range is relatively wide.
+	     At least for types bigger than int - this covers pointers
+	     and arguments to functions like ctz.  */
 	  else if (*vr0min == *vr0max
 		   && integer_zerop (*vr0min)
-		   && (TYPE_PRECISION (TREE_TYPE (*vr0min))
-		       == TYPE_PRECISION (ptr_type_node))
+		   && ((TYPE_PRECISION (TREE_TYPE (*vr0min))
+			>= TYPE_PRECISION (integer_type_node))
+		       || POINTER_TYPE_P (TREE_TYPE (*vr0min)))
 		   && TREE_CODE (vr1max) == INTEGER_CST
 		   && TREE_CODE (vr1min) == INTEGER_CST
 		   && (wi::clz (wi::to_wide (vr1max) - wi::to_wide (vr1min))
@@ -8792,33 +5929,29 @@
       *vr0min = vr1min;
       *vr0max = vr1max;
     }
-
-  return;
 }
 
 
 /* Intersect the two value-ranges *VR0 and *VR1 and store the result
    in *VR0.  This may not be the smallest possible such range.  */
 
-static void
-vrp_intersect_ranges_1 (value_range *vr0, value_range *vr1)
+void
+value_range::intersect_helper (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)
-    {
-      copy_value_range (vr0, vr1);
+  if (vr0->varying_p ())
+    {
+      vr0->deep_copy (vr1);
       return;
     }
 
   /* 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;
@@ -8826,51 +5959,56 @@
 
   /* 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_kind vr0type = vr0->kind ();
+  tree vr0min = vr0->min ();
+  tree vr0max = vr0->max ();
+  intersect_ranges (&vr0type, &vr0min, &vr0max,
+		    vr1->kind (), vr1->min (), vr1->max ());
   /* 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->set_and_canonicalize (vr0type, vr0min, vr0max, vr0->m_equiv);
   /* 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)
-    {
-      vr0->equiv = BITMAP_ALLOC (&vrp_equiv_obstack);
-      bitmap_copy (vr0->equiv, vr1->equiv);
+  if (vr0->m_equiv && vr1->m_equiv && vr0->m_equiv != vr1->m_equiv)
+    bitmap_ior_into (vr0->m_equiv, vr1->m_equiv);
+  else if (vr1->m_equiv && !vr0->m_equiv)
+    {
+      /* All equivalence bitmaps are allocated from the same obstack.  So
+	 we can use the obstack associated with VR to allocate vr0->equiv.  */
+      vr0->m_equiv = BITMAP_ALLOC (vr1->m_equiv->obstack);
+      bitmap_copy (m_equiv, vr1->m_equiv);
     }
 }
 
 void
-vrp_intersect_ranges (value_range *vr0, value_range *vr1)
+value_range::intersect (const value_range *other)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "Intersecting\n  ");
-      dump_value_range (dump_file, vr0);
+      dump_value_range (dump_file, this);
       fprintf (dump_file, "\nand\n  ");
-      dump_value_range (dump_file, vr1);
+      dump_value_range (dump_file, other);
       fprintf (dump_file, "\n");
     }
-  vrp_intersect_ranges_1 (vr0, vr1);
+  intersect_helper (this, other);
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "to\n  ");
-      dump_value_range (dump_file, vr0);
+      dump_value_range (dump_file, this);
       fprintf (dump_file, "\n");
     }
 }
@@ -8879,325 +6017,102 @@
    VR1, store in VR0 a range that contains both VR0 and VR1.  This
    may not be the smallest possible such range.  */
 
-static void
-vrp_meet_1 (value_range *vr0, const value_range *vr1)
+void
+value_range::union_helper (value_range *vr0, const value_range *vr1)
 {
-  value_range saved;
-
-  if (vr0->type == VR_UNDEFINED)
-    {
-      set_value_range (vr0, vr1->type, 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->undefined_p ())
+    {
+      vr0->deep_copy (vr1);
+      return;
+    }
+
+  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_kind vr0type = vr0->kind ();
+  tree vr0min = vr0->min ();
+  tree vr0max = vr0->max ();
+  union_ranges (&vr0type, &vr0min, &vr0max,
+		vr1->kind (), vr1->min (), vr1->max ());
+  *vr0 = value_range (vr0type, vr0min, vr0max);
+  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
-	 anti-range.  FIXME, all this nonsense about distinguishing
-	 anti-ranges from ranges is necessary because of the odd
-	 semantics of range_includes_zero_p and friends.  */
-      if (((saved.type == VR_RANGE
-	    && range_includes_zero_p (saved.min, saved.max) == 0)
-	   || (saved.type == VR_ANTI_RANGE
-	       && range_includes_zero_p (saved.min, saved.max) == 1))
-	  && ((vr1->type == VR_RANGE
-	       && range_includes_zero_p (vr1->min, vr1->max) == 0)
-	      || (vr1->type == VR_ANTI_RANGE
-		  && range_includes_zero_p (vr1->min, vr1->max) == 1)))
+	 anti-range.  */
+      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);
+	  if (vr0->m_equiv)
+	    bitmap_clear (vr0->m_equiv);
 	  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->set_and_canonicalize (vr0->kind (), vr0->min (), vr0->max (),
+			     vr0->equiv ());
+  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->m_equiv && vr1->m_equiv && vr0->m_equiv != vr1->m_equiv)
+    bitmap_and_into (vr0->m_equiv, vr1->m_equiv);
+  else if (vr0->m_equiv && !vr1->m_equiv)
+    bitmap_clear (vr0->m_equiv);
 }
 
 void
-vrp_meet (value_range *vr0, const value_range *vr1)
+value_range::union_ (const value_range *other)
 {
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "Meeting\n  ");
-      dump_value_range (dump_file, vr0);
+      dump_value_range (dump_file, this);
       fprintf (dump_file, "\nand\n  ");
-      dump_value_range (dump_file, vr1);
+      dump_value_range (dump_file, other);
       fprintf (dump_file, "\n");
     }
-  vrp_meet_1 (vr0, vr1);
+  union_helper (this, other);
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "to\n  ");
-      dump_value_range (dump_file, vr0);
+      dump_value_range (dump_file, this);
       fprintf (dump_file, "\n");
     }
 }
 
-
-/* Visit all arguments for PHI node PHI that flow through executable
-   edges.  If a valid value range can be derived from all the incoming
-   value ranges, set a new range in VR_RESULT.  */
-
-static void
-extract_range_from_phi_node (gphi *phi, value_range *vr_result)
-{
-  size_t i;
-  tree lhs = PHI_RESULT (phi);
-  value_range *lhs_vr = get_value_range (lhs);
-  bool first = true;
-  int edges, old_edges;
-  struct loop *l;
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "\nVisiting PHI node: ");
-      print_gimple_stmt (dump_file, phi, 0, dump_flags);
-    }
-
-  bool may_simulate_backedge_again = false;
-  edges = 0;
-  for (i = 0; i < gimple_phi_num_args (phi); i++)
-    {
-      edge e = gimple_phi_arg_edge (phi, i);
-
-      if (dump_file && (dump_flags & TDF_DETAILS))
-	{
-	  fprintf (dump_file,
-	      "    Argument #%d (%d -> %d %sexecutable)\n",
-	      (int) i, e->src->index, e->dest->index,
-	      (e->flags & EDGE_EXECUTABLE) ? "" : "not ");
-	}
-
-      if (e->flags & EDGE_EXECUTABLE)
-	{
-	  tree arg = PHI_ARG_DEF (phi, i);
-	  value_range vr_arg;
-
-	  ++edges;
-
-	  if (TREE_CODE (arg) == SSA_NAME)
-	    {
-	      /* See if we are eventually going to change one of the args.  */
-	      gimple *def_stmt = SSA_NAME_DEF_STMT (arg);
-	      if (! gimple_nop_p (def_stmt)
-		  && prop_simulate_again_p (def_stmt)
-		  && e->flags & EDGE_DFS_BACK)
-		may_simulate_backedge_again = true;
-
-	      vr_arg = *(get_value_range (arg));
-	      /* Do not allow equivalences or symbolic ranges to leak in from
-		 backedges.  That creates invalid equivalencies.
-		 See PR53465 and PR54767.  */
-	      if (e->flags & EDGE_DFS_BACK)
-		{
-		  if (vr_arg.type == VR_RANGE
-		      || vr_arg.type == VR_ANTI_RANGE)
-		    {
-		      vr_arg.equiv = NULL;
-		      if (symbolic_range_p (&vr_arg))
-			{
-			  vr_arg.type = VR_VARYING;
-			  vr_arg.min = NULL_TREE;
-			  vr_arg.max = NULL_TREE;
-			}
-		    }
-		}
-	      else
-		{
-		  /* If the non-backedge arguments range is VR_VARYING then
-		     we can still try recording a simple equivalence.  */
-		  if (vr_arg.type == VR_VARYING)
-		    {
-		      vr_arg.type = VR_RANGE;
-		      vr_arg.min = arg;
-		      vr_arg.max = arg;
-		      vr_arg.equiv = NULL;
-		    }
-		}
-	    }
-	  else
-	    {
-	      if (TREE_OVERFLOW_P (arg))
-		arg = drop_tree_overflow (arg);
-
-	      vr_arg.type = VR_RANGE;
-	      vr_arg.min = arg;
-	      vr_arg.max = arg;
-	      vr_arg.equiv = NULL;
-	    }
-
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	    {
-	      fprintf (dump_file, "\t");
-	      print_generic_expr (dump_file, arg, dump_flags);
-	      fprintf (dump_file, ": ");
-	      dump_value_range (dump_file, &vr_arg);
-	      fprintf (dump_file, "\n");
-	    }
-
-	  if (first)
-	    copy_value_range (vr_result, &vr_arg);
-	  else
-	    vrp_meet (vr_result, &vr_arg);
-	  first = false;
-
-	  if (vr_result->type == VR_VARYING)
-	    break;
-	}
-    }
-
-  if (vr_result->type == VR_VARYING)
-    goto varying;
-  else if (vr_result->type == VR_UNDEFINED)
-    goto update_range;
-
-  old_edges = vr_phi_edge_counts[SSA_NAME_VERSION (lhs)];
-  vr_phi_edge_counts[SSA_NAME_VERSION (lhs)] = edges;
-
-  /* To prevent infinite iterations in the algorithm, derive ranges
-     when the new value is slightly bigger or smaller than the
-     previous one.  We don't do this if we have seen a new executable
-     edge; this helps us avoid an infinity for conditionals
-     which are not in a loop.  If the old value-range was VR_UNDEFINED
-     use the updated range and iterate one more time.  If we will not
-     simulate this PHI again via the backedge allow us to iterate.  */
-  if (edges > 0
-      && gimple_phi_num_args (phi) > 1
-      && edges == old_edges
-      && lhs_vr->type != VR_UNDEFINED
-      && may_simulate_backedge_again)
-    {
-      /* Compare old and new ranges, fall back to varying if the
-         values are not comparable.  */
-      int cmp_min = compare_values (lhs_vr->min, vr_result->min);
-      if (cmp_min == -2)
-	goto varying;
-      int cmp_max = compare_values (lhs_vr->max, vr_result->max);
-      if (cmp_max == -2)
-	goto varying;
-
-      /* For non VR_RANGE or for pointers fall back to varying if
-	 the range changed.  */
-      if ((lhs_vr->type != VR_RANGE || vr_result->type != VR_RANGE
-	   || POINTER_TYPE_P (TREE_TYPE (lhs)))
-	  && (cmp_min != 0 || cmp_max != 0))
-	goto varying;
-
-      /* If the new minimum is larger than the previous one
-	 retain the old value.  If the new minimum value is smaller
-	 than the previous one and not -INF go all the way to -INF + 1.
-	 In the first case, to avoid infinite bouncing between different
-	 minimums, and in the other case to avoid iterating millions of
-	 times to reach -INF.  Going to -INF + 1 also lets the following
-	 iteration compute whether there will be any overflow, at the
-	 expense of one additional iteration.  */
-      if (cmp_min < 0)
-	vr_result->min = lhs_vr->min;
-      else if (cmp_min > 0
-	       && !vrp_val_is_min (vr_result->min))
-	vr_result->min
-	  = int_const_binop (PLUS_EXPR,
-			     vrp_val_min (TREE_TYPE (vr_result->min)),
-			     build_int_cst (TREE_TYPE (vr_result->min), 1));
-
-      /* Similarly for the maximum value.  */
-      if (cmp_max > 0)
-	vr_result->max = lhs_vr->max;
-      else if (cmp_max < 0
-	       && !vrp_val_is_max (vr_result->max))
-	vr_result->max
-	  = int_const_binop (MINUS_EXPR,
-			     vrp_val_max (TREE_TYPE (vr_result->min)),
-			     build_int_cst (TREE_TYPE (vr_result->min), 1));
-
-      /* If we dropped either bound to +-INF then if this is a loop
-	 PHI node SCEV may known more about its value-range.  */
-      if (cmp_min > 0 || cmp_min < 0
-	   || cmp_max < 0 || cmp_max > 0)
-	goto scev_check;
-
-      goto infinite_check;
-    }
-
-  goto update_range;
-
-varying:
-  set_value_range_to_varying (vr_result);
-
-scev_check:
-  /* If this is a loop PHI node SCEV may known more about its value-range.
-     scev_check can be reached from two paths, one is a fall through from above
-     "varying" label, the other is direct goto from code block which tries to
-     avoid infinite simulation.  */
-  if ((l = loop_containing_stmt (phi))
-      && l->header == gimple_bb (phi))
-    adjust_range_with_scev (vr_result, l, phi, lhs);
-
-infinite_check:
-  /* If we will end up with a (-INF, +INF) range, set it to
-     VARYING.  Same if the previous max value was invalid for
-     the type and we end up with vr_result.min > vr_result.max.  */
-  if ((vr_result->type == VR_RANGE || vr_result->type == VR_ANTI_RANGE)
-      && !((vrp_val_is_max (vr_result->max) && vrp_val_is_min (vr_result->min))
-	   || compare_values (vr_result->min, vr_result->max) > 0))
-    ;
-  else
-    set_value_range_to_varying (vr_result);
-
-  /* If the new range is different than the previous value, keep
-     iterating.  */
-update_range:
-  return;
-}
-
 /* Visit all arguments for PHI node PHI that flow through executable
    edges.  If a valid value range can be derived from all the incoming
    value ranges, set a new range for the LHS of PHI.  */
 
-static enum ssa_prop_result
-vrp_visit_phi_node (gphi *phi)
+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;
   extract_range_from_phi_node (phi, &vr_result);
   if (update_value_range (lhs, &vr_result))
     {
@@ -9210,7 +6125,7 @@
 	  fprintf (dump_file, "\n");
 	}
 
-      if (vr_result.type == VR_VARYING)
+      if (vr_result.varying_p ())
 	return SSA_PROP_VARYING;
 
       return SSA_PROP_INTERESTING;
@@ -9220,1259 +6135,31 @@
   return SSA_PROP_NOT_INTERESTING;
 }
 
-/* Simplify boolean operations if the source is known
-   to be already a boolean.  */
-static bool
-simplify_truth_ops_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
-{
-  enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
-  tree lhs, op0, op1;
-  bool need_conversion;
-
-  /* We handle only !=/== case here.  */
-  gcc_assert (rhs_code == EQ_EXPR || rhs_code == NE_EXPR);
-
-  op0 = gimple_assign_rhs1 (stmt);
-  if (!op_with_boolean_value_range_p (op0))
-    return false;
-
-  op1 = gimple_assign_rhs2 (stmt);
-  if (!op_with_boolean_value_range_p (op1))
-    return false;
-
-  /* Reduce number of cases to handle to NE_EXPR.  As there is no
-     BIT_XNOR_EXPR we cannot replace A == B with a single statement.  */
-  if (rhs_code == EQ_EXPR)
-    {
-      if (TREE_CODE (op1) == INTEGER_CST)
-	op1 = int_const_binop (BIT_XOR_EXPR, op1,
-			       build_int_cst (TREE_TYPE (op1), 1));
-      else
-	return false;
-    }
-
-  lhs = gimple_assign_lhs (stmt);
-  need_conversion
-    = !useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (op0));
-
-  /* Make sure to not sign-extend a 1-bit 1 when converting the result.  */
-  if (need_conversion
-      && !TYPE_UNSIGNED (TREE_TYPE (op0))
-      && TYPE_PRECISION (TREE_TYPE (op0)) == 1
-      && TYPE_PRECISION (TREE_TYPE (lhs)) > 1)
-    return false;
-
-  /* For A != 0 we can substitute A itself.  */
-  if (integer_zerop (op1))
-    gimple_assign_set_rhs_with_ops (gsi,
-				    need_conversion
-				    ? NOP_EXPR : TREE_CODE (op0), op0);
-  /* For A != B we substitute A ^ B.  Either with conversion.  */
-  else if (need_conversion)
-    {
-      tree tem = make_ssa_name (TREE_TYPE (op0));
-      gassign *newop
-	= gimple_build_assign (tem, BIT_XOR_EXPR, op0, op1);
-      gsi_insert_before (gsi, newop, GSI_SAME_STMT);
-      if (INTEGRAL_TYPE_P (TREE_TYPE (tem))
-	  && TYPE_PRECISION (TREE_TYPE (tem)) > 1)
-	set_range_info (tem, VR_RANGE,
-			wi::zero (TYPE_PRECISION (TREE_TYPE (tem))),
-			wi::one (TYPE_PRECISION (TREE_TYPE (tem))));
-      gimple_assign_set_rhs_with_ops (gsi, NOP_EXPR, tem);
-    }
-  /* Or without.  */
-  else
-    gimple_assign_set_rhs_with_ops (gsi, BIT_XOR_EXPR, op0, op1);
-  update_stmt (gsi_stmt (*gsi));
-  fold_stmt (gsi, follow_single_use_edges);
-
-  return true;
-}
-
-/* Simplify a division or modulo operator to a right shift or bitwise and
-   if the first operand is unsigned or is greater than zero and the second
-   operand is an exact power of two.  For TRUNC_MOD_EXPR op0 % op1 with
-   constant op1 (op1min = op1) or with op1 in [op1min, op1max] range,
-   optimize it into just op0 if op0's range is known to be a subset of
-   [-op1min + 1, op1min - 1] for signed and [0, op1min - 1] for unsigned
-   modulo.  */
-
-static bool
-simplify_div_or_mod_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
-{
-  enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
-  tree val = NULL;
-  tree op0 = gimple_assign_rhs1 (stmt);
-  tree op1 = gimple_assign_rhs2 (stmt);
-  tree op0min = NULL_TREE, op0max = NULL_TREE;
-  tree op1min = op1;
-  value_range *vr = NULL;
-
-  if (TREE_CODE (op0) == INTEGER_CST)
-    {
-      op0min = op0;
-      op0max = op0;
-    }
-  else
-    {
-      vr = get_value_range (op0);
-      if (range_int_cst_p (vr))
-	{
-	  op0min = vr->min;
-	  op0max = vr->max;
-	}
-    }
-
-  if (rhs_code == TRUNC_MOD_EXPR
-      && TREE_CODE (op1) == SSA_NAME)
-    {
-      value_range *vr1 = get_value_range (op1);
-      if (range_int_cst_p (vr1))
-	op1min = vr1->min;
-    }
-  if (rhs_code == TRUNC_MOD_EXPR
-      && TREE_CODE (op1min) == INTEGER_CST
-      && tree_int_cst_sgn (op1min) == 1
-      && op0max
-      && tree_int_cst_lt (op0max, op1min))
-    {
-      if (TYPE_UNSIGNED (TREE_TYPE (op0))
-	  || tree_int_cst_sgn (op0min) >= 0
-	  || tree_int_cst_lt (fold_unary (NEGATE_EXPR, TREE_TYPE (op1min), op1min),
-			      op0min))
-	{
-	  /* If op0 already has the range op0 % op1 has,
-	     then TRUNC_MOD_EXPR won't change anything.  */
-	  gimple_assign_set_rhs_from_tree (gsi, op0);
-	  return true;
-	}
-    }
-
-  if (TREE_CODE (op0) != SSA_NAME)
-    return false;
-
-  if (!integer_pow2p (op1))
-    {
-      /* X % -Y can be only optimized into X % Y either if
-	 X is not INT_MIN, or Y is not -1.  Fold it now, as after
-	 remove_range_assertions the range info might be not available
-	 anymore.  */
-      if (rhs_code == TRUNC_MOD_EXPR
-	  && fold_stmt (gsi, follow_single_use_edges))
-	return true;
-      return false;
-    }
-
-  if (TYPE_UNSIGNED (TREE_TYPE (op0)))
-    val = integer_one_node;
-  else
-    {
-      bool sop = false;
-
-      val = compare_range_with_value (GE_EXPR, vr, integer_zero_node, &sop);
-
-      if (val
-	  && sop
-	  && integer_onep (val)
-	  && issue_strict_overflow_warning (WARN_STRICT_OVERFLOW_MISC))
-	{
-	  location_t location;
-
-	  if (!gimple_has_location (stmt))
-	    location = input_location;
-	  else
-	    location = gimple_location (stmt);
-	  warning_at (location, OPT_Wstrict_overflow,
-		      "assuming signed overflow does not occur when "
-		      "simplifying %</%> or %<%%%> to %<>>%> or %<&%>");
-	}
-    }
-
-  if (val && integer_onep (val))
-    {
-      tree t;
-
-      if (rhs_code == TRUNC_DIV_EXPR)
-	{
-	  t = build_int_cst (integer_type_node, tree_log2 (op1));
-	  gimple_assign_set_rhs_code (stmt, RSHIFT_EXPR);
-	  gimple_assign_set_rhs1 (stmt, op0);
-	  gimple_assign_set_rhs2 (stmt, t);
-	}
-      else
-	{
-	  t = build_int_cst (TREE_TYPE (op1), 1);
-	  t = int_const_binop (MINUS_EXPR, op1, t);
-	  t = fold_convert (TREE_TYPE (op0), t);
-
-	  gimple_assign_set_rhs_code (stmt, BIT_AND_EXPR);
-	  gimple_assign_set_rhs1 (stmt, op0);
-	  gimple_assign_set_rhs2 (stmt, t);
-	}
-
-      update_stmt (stmt);
-      fold_stmt (gsi, follow_single_use_edges);
-      return true;
-    }
-
-  return false;
-}
-
-/* Simplify a min or max if the ranges of the two operands are
-   disjoint.   Return true if we do simplify.  */
-
-static bool
-simplify_min_or_max_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
-{
-  tree op0 = gimple_assign_rhs1 (stmt);
-  tree op1 = gimple_assign_rhs2 (stmt);
-  bool sop = false;
-  tree val;
-
-  val = (vrp_evaluate_conditional_warnv_with_ops_using_ranges
-	 (LE_EXPR, op0, op1, &sop));
-  if (!val)
-    {
-      sop = false;
-      val = (vrp_evaluate_conditional_warnv_with_ops_using_ranges
-	     (LT_EXPR, op0, op1, &sop));
-    }
-
-  if (val)
-    {
-      if (sop && issue_strict_overflow_warning (WARN_STRICT_OVERFLOW_MISC))
-	{
-	  location_t location;
-
-	  if (!gimple_has_location (stmt))
-	    location = input_location;
-	  else
-	    location = gimple_location (stmt);
-	  warning_at (location, OPT_Wstrict_overflow,
-		      "assuming signed overflow does not occur when "
-		      "simplifying %<min/max (X,Y)%> to %<X%> or %<Y%>");
-	}
-
-      /* VAL == TRUE -> OP0 < or <= op1
-	 VAL == FALSE -> OP0 > or >= op1.  */
-      tree res = ((gimple_assign_rhs_code (stmt) == MAX_EXPR)
-		  == integer_zerop (val)) ? op0 : op1;
-      gimple_assign_set_rhs_from_tree (gsi, res);
-      return true;
-    }
-
-  return false;
-}
-
-/* If the operand to an ABS_EXPR is >= 0, then eliminate the
-   ABS_EXPR.  If the operand is <= 0, then simplify the
-   ABS_EXPR into a NEGATE_EXPR.  */
-
-static bool
-simplify_abs_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
-{
-  tree op = gimple_assign_rhs1 (stmt);
-  value_range *vr = get_value_range (op);
-
-  if (vr)
-    {
-      tree val = NULL;
-      bool sop = false;
-
-      val = compare_range_with_value (LE_EXPR, vr, integer_zero_node, &sop);
-      if (!val)
-	{
-	  /* The range is neither <= 0 nor > 0.  Now see if it is
-	     either < 0 or >= 0.  */
-	  sop = false;
-	  val = compare_range_with_value (LT_EXPR, vr, integer_zero_node,
-					  &sop);
-	}
-
-      if (val)
-	{
-	  if (sop && issue_strict_overflow_warning (WARN_STRICT_OVERFLOW_MISC))
-	    {
-	      location_t location;
-
-	      if (!gimple_has_location (stmt))
-		location = input_location;
-	      else
-		location = gimple_location (stmt);
-	      warning_at (location, OPT_Wstrict_overflow,
-			  "assuming signed overflow does not occur when "
-			  "simplifying %<abs (X)%> to %<X%> or %<-X%>");
-	    }
-
-	  gimple_assign_set_rhs1 (stmt, op);
-	  if (integer_zerop (val))
-	    gimple_assign_set_rhs_code (stmt, SSA_NAME);
-	  else
-	    gimple_assign_set_rhs_code (stmt, NEGATE_EXPR);
-	  update_stmt (stmt);
-	  fold_stmt (gsi, follow_single_use_edges);
-	  return true;
-	}
-    }
-
-  return false;
-}
-
-/* Optimize away redundant BIT_AND_EXPR and BIT_IOR_EXPR.
-   If all the bits that are being cleared by & are already
-   known to be zero from VR, or all the bits that are being
-   set by | are already known to be one from VR, the bit
-   operation is redundant.  */
-
-static bool
-simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
-{
-  tree op0 = gimple_assign_rhs1 (stmt);
-  tree op1 = gimple_assign_rhs2 (stmt);
-  tree op = NULL_TREE;
-  value_range vr0 = VR_INITIALIZER;
-  value_range vr1 = VR_INITIALIZER;
-  wide_int may_be_nonzero0, may_be_nonzero1;
-  wide_int must_be_nonzero0, must_be_nonzero1;
-  wide_int mask;
-
-  if (TREE_CODE (op0) == SSA_NAME)
-    vr0 = *(get_value_range (op0));
-  else if (is_gimple_min_invariant (op0))
-    set_value_range_to_value (&vr0, op0, NULL);
-  else
-    return false;
-
-  if (TREE_CODE (op1) == SSA_NAME)
-    vr1 = *(get_value_range (op1));
-  else if (is_gimple_min_invariant (op1))
-    set_value_range_to_value (&vr1, op1, NULL);
-  else
-    return false;
-
-  if (!zero_nonzero_bits_from_vr (TREE_TYPE (op0), &vr0, &may_be_nonzero0,
-				  &must_be_nonzero0))
-    return false;
-  if (!zero_nonzero_bits_from_vr (TREE_TYPE (op1), &vr1, &may_be_nonzero1,
-				  &must_be_nonzero1))
-    return false;
-
-  switch (gimple_assign_rhs_code (stmt))
-    {
-    case BIT_AND_EXPR:
-      mask = wi::bit_and_not (may_be_nonzero0, must_be_nonzero1);
-      if (mask == 0)
-	{
-	  op = op0;
-	  break;
-	}
-      mask = wi::bit_and_not (may_be_nonzero1, must_be_nonzero0);
-      if (mask == 0)
-	{
-	  op = op1;
-	  break;
-	}
-      break;
-    case BIT_IOR_EXPR:
-      mask = wi::bit_and_not (may_be_nonzero0, must_be_nonzero1);
-      if (mask == 0)
-	{
-	  op = op1;
-	  break;
-	}
-      mask = wi::bit_and_not (may_be_nonzero1, must_be_nonzero0);
-      if (mask == 0)
-	{
-	  op = op0;
-	  break;
-	}
-      break;
-    default:
-      gcc_unreachable ();
-    }
-
-  if (op == NULL_TREE)
-    return false;
-
-  gimple_assign_set_rhs_with_ops (gsi, TREE_CODE (op), op);
-  update_stmt (gsi_stmt (*gsi));
-  return true;
-}
-
-/* We are comparing trees OP0 and OP1 using COND_CODE.  OP0 has
-   a known value range VR.
-
-   If there is one and only one value which will satisfy the
-   conditional, then return that value.  Else return NULL.
-
-   If signed overflow must be undefined for the value to satisfy
-   the conditional, then set *STRICT_OVERFLOW_P to true.  */
-
-static tree
-test_for_singularity (enum tree_code cond_code, tree op0,
-		      tree op1, value_range *vr)
-{
-  tree min = NULL;
-  tree max = NULL;
-
-  /* Extract minimum/maximum values which satisfy the conditional as it was
-     written.  */
-  if (cond_code == LE_EXPR || cond_code == LT_EXPR)
-    {
-      min = TYPE_MIN_VALUE (TREE_TYPE (op0));
-
-      max = op1;
-      if (cond_code == LT_EXPR)
-	{
-	  tree one = build_int_cst (TREE_TYPE (op0), 1);
-	  max = fold_build2 (MINUS_EXPR, TREE_TYPE (op0), max, one);
-	  /* Signal to compare_values_warnv this expr doesn't overflow.  */
-	  if (EXPR_P (max))
-	    TREE_NO_WARNING (max) = 1;
-	}
-    }
-  else if (cond_code == GE_EXPR || cond_code == GT_EXPR)
-    {
-      max = TYPE_MAX_VALUE (TREE_TYPE (op0));
-
-      min = op1;
-      if (cond_code == GT_EXPR)
-	{
-	  tree one = build_int_cst (TREE_TYPE (op0), 1);
-	  min = fold_build2 (PLUS_EXPR, TREE_TYPE (op0), min, one);
-	  /* Signal to compare_values_warnv this expr doesn't overflow.  */
-	  if (EXPR_P (min))
-	    TREE_NO_WARNING (min) = 1;
-	}
-    }
-
-  /* Now refine the minimum and maximum values using any
-     value range information we have for op0.  */
-  if (min && max)
-    {
-      if (compare_values (vr->min, min) == 1)
-	min = vr->min;
-      if (compare_values (vr->max, max) == -1)
-	max = vr->max;
-
-      /* If the new min/max values have converged to a single value,
-	 then there is only one value which can satisfy the condition,
-	 return that value.  */
-      if (operand_equal_p (min, max, 0) && is_gimple_min_invariant (min))
-	return min;
-    }
-  return NULL;
-}
-
-/* Return whether the value range *VR fits in an integer type specified
-   by PRECISION and UNSIGNED_P.  */
-
-static bool
-range_fits_type_p (value_range *vr, unsigned dest_precision, signop dest_sgn)
-{
-  tree src_type;
-  unsigned src_precision;
-  widest_int tem;
-  signop src_sgn;
-
-  /* We can only handle integral and pointer types.  */
-  src_type = TREE_TYPE (vr->min);
-  if (!INTEGRAL_TYPE_P (src_type)
-      && !POINTER_TYPE_P (src_type))
-    return false;
-
-  /* An extension is fine unless VR is SIGNED and dest_sgn is UNSIGNED,
-     and so is an identity transform.  */
-  src_precision = TYPE_PRECISION (TREE_TYPE (vr->min));
-  src_sgn = TYPE_SIGN (src_type);
-  if ((src_precision < dest_precision
-       && !(dest_sgn == UNSIGNED && src_sgn == SIGNED))
-      || (src_precision == dest_precision && src_sgn == dest_sgn))
-    return true;
-
-  /* Now we can only handle ranges with constant bounds.  */
-  if (vr->type != VR_RANGE
-      || TREE_CODE (vr->min) != INTEGER_CST
-      || TREE_CODE (vr->max) != INTEGER_CST)
-    return false;
-
-  /* For sign changes, the MSB of the wide_int has to be clear.
-     An unsigned value with its MSB set cannot be represented by
-     a signed wide_int, while a negative value cannot be represented
-     by an unsigned wide_int.  */
-  if (src_sgn != dest_sgn
-      && (wi::lts_p (wi::to_wide (vr->min), 0)
-	  || wi::lts_p (wi::to_wide (vr->max), 0)))
-    return false;
-
-  /* Then we can perform the conversion on both ends and compare
-     the result for equality.  */
-  tem = wi::ext (wi::to_widest (vr->min), dest_precision, dest_sgn);
-  if (tem != wi::to_widest (vr->min))
-    return false;
-  tem = wi::ext (wi::to_widest (vr->max), dest_precision, dest_sgn);
-  if (tem != wi::to_widest (vr->max))
-    return false;
-
-  return true;
-}
-
-/* Simplify a conditional using a relational operator to an equality
-   test if the range information indicates only one value can satisfy
-   the original conditional.  */
-
-static bool
-simplify_cond_using_ranges_1 (gcond *stmt)
-{
-  tree op0 = gimple_cond_lhs (stmt);
-  tree op1 = gimple_cond_rhs (stmt);
-  enum tree_code cond_code = gimple_cond_code (stmt);
-
-  if (cond_code != NE_EXPR
-      && cond_code != EQ_EXPR
-      && TREE_CODE (op0) == SSA_NAME
-      && INTEGRAL_TYPE_P (TREE_TYPE (op0))
-      && is_gimple_min_invariant (op1))
-    {
-      value_range *vr = get_value_range (op0);
-
-      /* If we have range information for OP0, then we might be
-	 able to simplify this conditional. */
-      if (vr->type == VR_RANGE)
-	{
-	  tree new_tree = test_for_singularity (cond_code, op0, op1, vr);
-	  if (new_tree)
-	    {
-	      if (dump_file)
-		{
-		  fprintf (dump_file, "Simplified relational ");
-		  print_gimple_stmt (dump_file, stmt, 0);
-		  fprintf (dump_file, " into ");
-		}
-
-	      gimple_cond_set_code (stmt, EQ_EXPR);
-	      gimple_cond_set_lhs (stmt, op0);
-	      gimple_cond_set_rhs (stmt, new_tree);
-
-	      update_stmt (stmt);
-
-	      if (dump_file)
-		{
-		  print_gimple_stmt (dump_file, stmt, 0);
-		  fprintf (dump_file, "\n");
-		}
-
-	      return true;
-	    }
-
-	  /* Try again after inverting the condition.  We only deal
-	     with integral types here, so no need to worry about
-	     issues with inverting FP comparisons.  */
-	  new_tree = test_for_singularity
-		       (invert_tree_comparison (cond_code, false),
-			op0, op1, vr);
-	  if (new_tree)
-	    {
-	      if (dump_file)
-		{
-		  fprintf (dump_file, "Simplified relational ");
-		  print_gimple_stmt (dump_file, stmt, 0);
-		  fprintf (dump_file, " into ");
-		}
-
-	      gimple_cond_set_code (stmt, NE_EXPR);
-	      gimple_cond_set_lhs (stmt, op0);
-	      gimple_cond_set_rhs (stmt, new_tree);
-
-	      update_stmt (stmt);
-
-	      if (dump_file)
-		{
-		  print_gimple_stmt (dump_file, stmt, 0);
-		  fprintf (dump_file, "\n");
-		}
-
-	      return true;
-	    }
-	}
-    }
-  return false;
-}
-
-/* STMT is a conditional at the end of a basic block.
-
-   If the conditional is of the form SSA_NAME op constant and the SSA_NAME
-   was set via a type conversion, try to replace the SSA_NAME with the RHS
-   of the type conversion.  Doing so makes the conversion dead which helps
-   subsequent passes.  */
-
-static void
-simplify_cond_using_ranges_2 (gcond *stmt)
+class vrp_folder : public substitute_and_fold_engine
 {
-  tree op0 = gimple_cond_lhs (stmt);
-  tree op1 = gimple_cond_rhs (stmt);
-
-  /* If we have a comparison of an SSA_NAME (OP0) against a constant,
-     see if OP0 was set by a type conversion where the source of
-     the conversion is another SSA_NAME with a range that fits
-     into the range of OP0's type.
-
-     If so, the conversion is redundant as the earlier SSA_NAME can be
-     used for the comparison directly if we just massage the constant in the
-     comparison.  */
-  if (TREE_CODE (op0) == SSA_NAME
-      && TREE_CODE (op1) == INTEGER_CST)
-    {
-      gimple *def_stmt = SSA_NAME_DEF_STMT (op0);
-      tree innerop;
-
-      if (!is_gimple_assign (def_stmt)
-	  || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)))
-	return;
-
-      innerop = gimple_assign_rhs1 (def_stmt);
-
-      if (TREE_CODE (innerop) == SSA_NAME
-	  && !POINTER_TYPE_P (TREE_TYPE (innerop))
-	  && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (innerop)
-	  && desired_pro_or_demotion_p (TREE_TYPE (innerop), TREE_TYPE (op0)))
-	{
-	  value_range *vr = get_value_range (innerop);
-
-	  if (range_int_cst_p (vr)
-	      && range_fits_type_p (vr,
-				    TYPE_PRECISION (TREE_TYPE (op0)),
-				    TYPE_SIGN (TREE_TYPE (op0)))
-	      && int_fits_type_p (op1, TREE_TYPE (innerop)))
-	    {
-	      tree newconst = fold_convert (TREE_TYPE (innerop), op1);
-	      gimple_cond_set_lhs (stmt, innerop);
-	      gimple_cond_set_rhs (stmt, newconst);
-	      update_stmt (stmt);
-	      if (dump_file && (dump_flags & TDF_DETAILS))
-		{
-		  fprintf (dump_file, "Folded into: ");
-		  print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
-		  fprintf (dump_file, "\n");
-		}
-	    }
-	}
-    }
-}
-
-/* Simplify a switch statement using the value range of the switch
-   argument.  */
-
-static bool
-simplify_switch_using_ranges (gswitch *stmt)
-{
-  tree op = gimple_switch_index (stmt);
-  value_range *vr = NULL;
-  bool take_default;
-  edge e;
-  edge_iterator ei;
-  size_t i = 0, j = 0, n, n2;
-  tree vec2;
-  switch_update su;
-  size_t k = 1, l = 0;
-
-  if (TREE_CODE (op) == SSA_NAME)
-    {
-      vr = get_value_range (op);
-
-      /* We can only handle integer ranges.  */
-      if ((vr->type != VR_RANGE
-	   && vr->type != VR_ANTI_RANGE)
-	  || symbolic_range_p (vr))
-	return false;
-
-      /* Find case label for min/max of the value range.  */
-      take_default = !find_case_label_ranges (stmt, vr, &i, &j, &k, &l);
-    }
-  else if (TREE_CODE (op) == INTEGER_CST)
-    {
-      take_default = !find_case_label_index (stmt, 1, op, &i);
-      if (take_default)
-	{
-	  i = 1;
-	  j = 0;
-	}
-      else
-	{
-	  j = i;
-	}
-    }
-  else
-    return false;
-
-  n = gimple_switch_num_labels (stmt);
-
-  /* We can truncate the case label ranges that partially overlap with OP's
-     value range.  */
-  size_t min_idx = 1, max_idx = 0;
-  if (vr != NULL)
-    find_case_label_range (stmt, vr->min, vr->max, &min_idx, &max_idx);
-  if (min_idx <= max_idx)
-    {
-      tree min_label = gimple_switch_label (stmt, min_idx);
-      tree max_label = gimple_switch_label (stmt, max_idx);
-
-      /* Avoid changing the type of the case labels when truncating.  */
-      tree case_label_type = TREE_TYPE (CASE_LOW (min_label));
-      tree vr_min = fold_convert (case_label_type, vr->min);
-      tree vr_max = fold_convert (case_label_type, vr->max);
-
-      if (vr->type == VR_RANGE)
-	{
-	  /* If OP's value range is [2,8] and the low label range is
-	     0 ... 3, truncate the label's range to 2 .. 3.  */
-	  if (tree_int_cst_compare (CASE_LOW (min_label), vr_min) < 0
-	      && CASE_HIGH (min_label) != NULL_TREE
-	      && tree_int_cst_compare (CASE_HIGH (min_label), vr_min) >= 0)
-	    CASE_LOW (min_label) = vr_min;
-
-	  /* If OP's value range is [2,8] and the high label range is
-	     7 ... 10, truncate the label's range to 7 .. 8.  */
-	  if (tree_int_cst_compare (CASE_LOW (max_label), vr_max) <= 0
-	      && CASE_HIGH (max_label) != NULL_TREE
-	      && tree_int_cst_compare (CASE_HIGH (max_label), vr_max) > 0)
-	    CASE_HIGH (max_label) = vr_max;
-	}
-      else if (vr->type == VR_ANTI_RANGE)
-	{
-	  tree one_cst = build_one_cst (case_label_type);
-
-	  if (min_label == max_label)
-	    {
-	      /* If OP's value range is ~[7,8] and the label's range is
-		 7 ... 10, truncate the label's range to 9 ... 10.  */
-	      if (tree_int_cst_compare (CASE_LOW (min_label), vr_min) == 0
-		  && CASE_HIGH (min_label) != NULL_TREE
-		  && tree_int_cst_compare (CASE_HIGH (min_label), vr_max) > 0)
-		CASE_LOW (min_label)
-		  = int_const_binop (PLUS_EXPR, vr_max, one_cst);
-
-	      /* If OP's value range is ~[7,8] and the label's range is
-		 5 ... 8, truncate the label's range to 5 ... 6.  */
-	      if (tree_int_cst_compare (CASE_LOW (min_label), vr_min) < 0
-		  && CASE_HIGH (min_label) != NULL_TREE
-		  && tree_int_cst_compare (CASE_HIGH (min_label), vr_max) == 0)
-		CASE_HIGH (min_label)
-		  = int_const_binop (MINUS_EXPR, vr_min, one_cst);
-	    }
-	  else
-	    {
-	      /* If OP's value range is ~[2,8] and the low label range is
-		 0 ... 3, truncate the label's range to 0 ... 1.  */
-	      if (tree_int_cst_compare (CASE_LOW (min_label), vr_min) < 0
-		  && CASE_HIGH (min_label) != NULL_TREE
-		  && tree_int_cst_compare (CASE_HIGH (min_label), vr_min) >= 0)
-		CASE_HIGH (min_label)
-		  = int_const_binop (MINUS_EXPR, vr_min, one_cst);
-
-	      /* If OP's value range is ~[2,8] and the high label range is
-		 7 ... 10, truncate the label's range to 9 ... 10.  */
-	      if (tree_int_cst_compare (CASE_LOW (max_label), vr_max) <= 0
-		  && CASE_HIGH (max_label) != NULL_TREE
-		  && tree_int_cst_compare (CASE_HIGH (max_label), vr_max) > 0)
-		CASE_LOW (max_label)
-		  = int_const_binop (PLUS_EXPR, vr_max, one_cst);
-	    }
-	}
-
-      /* Canonicalize singleton case ranges.  */
-      if (tree_int_cst_equal (CASE_LOW (min_label), CASE_HIGH (min_label)))
-	CASE_HIGH (min_label) = NULL_TREE;
-      if (tree_int_cst_equal (CASE_LOW (max_label), CASE_HIGH (max_label)))
-	CASE_HIGH (max_label) = NULL_TREE;
-    }
-
-  /* We can also eliminate case labels that lie completely outside OP's value
-     range.  */
-
-  /* Bail out if this is just all edges taken.  */
-  if (i == 1
-      && j == n - 1
-      && take_default)
-    return false;
-
-  /* Build a new vector of taken case labels.  */
-  vec2 = make_tree_vec (j - i + 1 + l - k + 1 + (int)take_default);
-  n2 = 0;
-
-  /* Add the default edge, if necessary.  */
-  if (take_default)
-    TREE_VEC_ELT (vec2, n2++) = gimple_switch_default_label (stmt);
-
-  for (; i <= j; ++i, ++n2)
-    TREE_VEC_ELT (vec2, n2) = gimple_switch_label (stmt, i);
-
-  for (; k <= l; ++k, ++n2)
-    TREE_VEC_ELT (vec2, n2) = gimple_switch_label (stmt, k);
-
-  /* Mark needed edges.  */
-  for (i = 0; i < n2; ++i)
-    {
-      e = find_edge (gimple_bb (stmt),
-		     label_to_block (CASE_LABEL (TREE_VEC_ELT (vec2, i))));
-      e->aux = (void *)-1;
-    }
-
-  /* Queue not needed edges for later removal.  */
-  FOR_EACH_EDGE (e, ei, gimple_bb (stmt)->succs)
-    {
-      if (e->aux == (void *)-1)
-	{
-	  e->aux = NULL;
-	  continue;
-	}
-
-      if (dump_file && (dump_flags & TDF_DETAILS))
-	{
-	  fprintf (dump_file, "removing unreachable case label\n");
-	}
-      to_remove_edges.safe_push (e);
-      e->flags &= ~EDGE_EXECUTABLE;
-    }
-
-  /* And queue an update for the stmt.  */
-  su.stmt = stmt;
-  su.vec = vec2;
-  to_update_switch_stmts.safe_push (su);
-  return false;
-}
-
-/* Simplify an integral conversion from an SSA name in STMT.  */
-
-static bool
-simplify_conversion_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
-{
-  tree innerop, middleop, finaltype;
-  gimple *def_stmt;
-  signop inner_sgn, middle_sgn, final_sgn;
-  unsigned inner_prec, middle_prec, final_prec;
-  widest_int innermin, innermed, innermax, middlemin, middlemed, middlemax;
-
-  finaltype = TREE_TYPE (gimple_assign_lhs (stmt));
-  if (!INTEGRAL_TYPE_P (finaltype))
-    return false;
-  middleop = gimple_assign_rhs1 (stmt);
-  def_stmt = SSA_NAME_DEF_STMT (middleop);
-  if (!is_gimple_assign (def_stmt)
-      || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def_stmt)))
-    return false;
-  innerop = gimple_assign_rhs1 (def_stmt);
-  if (TREE_CODE (innerop) != SSA_NAME
-      || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (innerop))
-    return false;
-
-  /* Get the value-range of the inner operand.  Use get_range_info in
-     case innerop was created during substitute-and-fold.  */
-  wide_int imin, imax;
-  if (!INTEGRAL_TYPE_P (TREE_TYPE (innerop))
-      || get_range_info (innerop, &imin, &imax) != VR_RANGE)
-    return false;
-  innermin = widest_int::from (imin, TYPE_SIGN (TREE_TYPE (innerop)));
-  innermax = widest_int::from (imax, TYPE_SIGN (TREE_TYPE (innerop)));
-
-  /* Simulate the conversion chain to check if the result is equal if
-     the middle conversion is removed.  */
-  inner_prec = TYPE_PRECISION (TREE_TYPE (innerop));
-  middle_prec = TYPE_PRECISION (TREE_TYPE (middleop));
-  final_prec = TYPE_PRECISION (finaltype);
-
-  /* If the first conversion is not injective, the second must not
-     be widening.  */
-  if (wi::gtu_p (innermax - innermin,
-		 wi::mask <widest_int> (middle_prec, false))
-      && middle_prec < final_prec)
-    return false;
-  /* We also want a medium value so that we can track the effect that
-     narrowing conversions with sign change have.  */
-  inner_sgn = TYPE_SIGN (TREE_TYPE (innerop));
-  if (inner_sgn == UNSIGNED)
-    innermed = wi::shifted_mask <widest_int> (1, inner_prec - 1, false);
-  else
-    innermed = 0;
-  if (wi::cmp (innermin, innermed, inner_sgn) >= 0
-      || wi::cmp (innermed, innermax, inner_sgn) >= 0)
-    innermed = innermin;
-
-  middle_sgn = TYPE_SIGN (TREE_TYPE (middleop));
-  middlemin = wi::ext (innermin, middle_prec, middle_sgn);
-  middlemed = wi::ext (innermed, middle_prec, middle_sgn);
-  middlemax = wi::ext (innermax, middle_prec, middle_sgn);
-
-  /* Require that the final conversion applied to both the original
-     and the intermediate range produces the same result.  */
-  final_sgn = TYPE_SIGN (finaltype);
-  if (wi::ext (middlemin, final_prec, final_sgn)
-	 != wi::ext (innermin, final_prec, final_sgn)
-      || wi::ext (middlemed, final_prec, final_sgn)
-	 != wi::ext (innermed, final_prec, final_sgn)
-      || wi::ext (middlemax, final_prec, final_sgn)
-	 != wi::ext (innermax, final_prec, final_sgn))
-    return false;
-
-  gimple_assign_set_rhs1 (stmt, innerop);
-  fold_stmt (gsi, follow_single_use_edges);
-  return true;
-}
-
-/* Simplify a conversion from integral SSA name to float in STMT.  */
-
-static bool
-simplify_float_conversion_using_ranges (gimple_stmt_iterator *gsi,
-					gimple *stmt)
-{
-  tree rhs1 = gimple_assign_rhs1 (stmt);
-  value_range *vr = get_value_range (rhs1);
-  scalar_float_mode fltmode
-    = SCALAR_FLOAT_TYPE_MODE (TREE_TYPE (gimple_assign_lhs (stmt)));
-  scalar_int_mode mode;
-  tree tem;
-  gassign *conv;
-
-  /* We can only handle constant ranges.  */
-  if (vr->type != VR_RANGE
-      || TREE_CODE (vr->min) != INTEGER_CST
-      || TREE_CODE (vr->max) != INTEGER_CST)
-    return false;
-
-  /* First check if we can use a signed type in place of an unsigned.  */
-  scalar_int_mode rhs_mode = SCALAR_INT_TYPE_MODE (TREE_TYPE (rhs1));
-  if (TYPE_UNSIGNED (TREE_TYPE (rhs1))
-      && can_float_p (fltmode, rhs_mode, 0) != CODE_FOR_nothing
-      && range_fits_type_p (vr, TYPE_PRECISION (TREE_TYPE (rhs1)), SIGNED))
-    mode = rhs_mode;
-  /* If we can do the conversion in the current input mode do nothing.  */
-  else if (can_float_p (fltmode, rhs_mode,
-			TYPE_UNSIGNED (TREE_TYPE (rhs1))) != CODE_FOR_nothing)
-    return false;
-  /* Otherwise search for a mode we can use, starting from the narrowest
-     integer mode available.  */
-  else
-    {
-      mode = NARROWEST_INT_MODE;
-      for (;;)
-	{
-	  /* If we cannot do a signed conversion to float from mode
-	     or if the value-range does not fit in the signed type
-	     try with a wider mode.  */
-	  if (can_float_p (fltmode, mode, 0) != CODE_FOR_nothing
-	      && range_fits_type_p (vr, GET_MODE_PRECISION (mode), SIGNED))
-	    break;
-
-	  /* But do not widen the input.  Instead leave that to the
-	     optabs expansion code.  */
-	  if (!GET_MODE_WIDER_MODE (mode).exists (&mode)
-	      || GET_MODE_PRECISION (mode) > TYPE_PRECISION (TREE_TYPE (rhs1)))
-	    return false;
-	}
-    }
-
-  /* It works, insert a truncation or sign-change before the
-     float conversion.  */
-  tem = make_ssa_name (build_nonstandard_integer_type
-			  (GET_MODE_PRECISION (mode), 0));
-  conv = gimple_build_assign (tem, NOP_EXPR, rhs1);
-  gsi_insert_before (gsi, conv, GSI_SAME_STMT);
-  gimple_assign_set_rhs1 (stmt, tem);
-  fold_stmt (gsi, follow_single_use_edges);
-
-  return true;
-}
-
-/* Simplify an internal fn call using ranges if possible.  */
-
-static bool
-simplify_internal_call_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
-{
-  enum tree_code subcode;
-  bool is_ubsan = false;
-  bool ovf = false;
-  switch (gimple_call_internal_fn (stmt))
-    {
-    case IFN_UBSAN_CHECK_ADD:
-      subcode = PLUS_EXPR;
-      is_ubsan = true;
-      break;
-    case IFN_UBSAN_CHECK_SUB:
-      subcode = MINUS_EXPR;
-      is_ubsan = true;
-      break;
-    case IFN_UBSAN_CHECK_MUL:
-      subcode = MULT_EXPR;
-      is_ubsan = true;
-      break;
-    case IFN_ADD_OVERFLOW:
-      subcode = PLUS_EXPR;
-      break;
-    case IFN_SUB_OVERFLOW:
-      subcode = MINUS_EXPR;
-      break;
-    case IFN_MUL_OVERFLOW:
-      subcode = MULT_EXPR;
-      break;
-    default:
-      return false;
-    }
-
-  tree op0 = gimple_call_arg (stmt, 0);
-  tree op1 = gimple_call_arg (stmt, 1);
-  tree type;
-  if (is_ubsan)
-    {
-      type = TREE_TYPE (op0);
-      if (VECTOR_TYPE_P (type))
-	return false;
-    }
-  else if (gimple_call_lhs (stmt) == NULL_TREE)
-    return false;
-  else
-    type = TREE_TYPE (TREE_TYPE (gimple_call_lhs (stmt)));
-  if (!check_for_binary_op_overflow (subcode, type, op0, op1, &ovf)
-      || (is_ubsan && ovf))
-    return false;
-
-  gimple *g;
-  location_t loc = gimple_location (stmt);
-  if (is_ubsan)
-    g = gimple_build_assign (gimple_call_lhs (stmt), subcode, op0, op1);
-  else
-    {
-      int prec = TYPE_PRECISION (type);
-      tree utype = type;
-      if (ovf
-	  || !useless_type_conversion_p (type, TREE_TYPE (op0))
-	  || !useless_type_conversion_p (type, TREE_TYPE (op1)))
-	utype = build_nonstandard_integer_type (prec, 1);
-      if (TREE_CODE (op0) == INTEGER_CST)
-	op0 = fold_convert (utype, op0);
-      else if (!useless_type_conversion_p (utype, TREE_TYPE (op0)))
-	{
-	  g = gimple_build_assign (make_ssa_name (utype), NOP_EXPR, op0);
-	  gimple_set_location (g, loc);
-	  gsi_insert_before (gsi, g, GSI_SAME_STMT);
-	  op0 = gimple_assign_lhs (g);
-	}
-      if (TREE_CODE (op1) == INTEGER_CST)
-	op1 = fold_convert (utype, op1);
-      else if (!useless_type_conversion_p (utype, TREE_TYPE (op1)))
-	{
-	  g = gimple_build_assign (make_ssa_name (utype), NOP_EXPR, op1);
-	  gimple_set_location (g, loc);
-	  gsi_insert_before (gsi, g, GSI_SAME_STMT);
-	  op1 = gimple_assign_lhs (g);
-	}
-      g = gimple_build_assign (make_ssa_name (utype), subcode, op0, op1);
-      gimple_set_location (g, loc);
-      gsi_insert_before (gsi, g, GSI_SAME_STMT);
-      if (utype != type)
-	{
-	  g = gimple_build_assign (make_ssa_name (type), NOP_EXPR,
-				   gimple_assign_lhs (g));
-	  gimple_set_location (g, loc);
-	  gsi_insert_before (gsi, g, GSI_SAME_STMT);
-	}
-      g = gimple_build_assign (gimple_call_lhs (stmt), COMPLEX_EXPR,
-			       gimple_assign_lhs (g),
-			       build_int_cst (type, ovf));
-    }
-  gimple_set_location (g, loc);
-  gsi_replace (gsi, g, false);
-  return true;
-}
-
-/* Return true if VAR is a two-valued variable.  Set a and b with the
-   two-values when it is true.  Return false otherwise.  */
-
-static bool
-two_valued_val_range_p (tree var, tree *a, tree *b)
-{
-  value_range *vr = get_value_range (var);
-  if ((vr->type != VR_RANGE
-       && vr->type != VR_ANTI_RANGE)
-      || TREE_CODE (vr->min) != INTEGER_CST
-      || TREE_CODE (vr->max) != INTEGER_CST)
-    return false;
-
-  if (vr->type == VR_RANGE
-      && wi::to_wide (vr->max) - wi::to_wide (vr->min) == 1)
-    {
-      *a = vr->min;
-      *b = vr->max;
-      return true;
-    }
-
-  /* ~[TYPE_MIN + 1, TYPE_MAX - 1] */
-  if (vr->type == VR_ANTI_RANGE
-      && (wi::to_wide (vr->min)
-	  - wi::to_wide (vrp_val_min (TREE_TYPE (var)))) == 1
-      && (wi::to_wide (vrp_val_max (TREE_TYPE (var)))
-	  - wi::to_wide (vr->max)) == 1)
-    {
-      *a = vrp_val_min (TREE_TYPE (var));
-      *b = vrp_val_max (TREE_TYPE (var));
-      return true;
-    }
-
-  return false;
-}
-
-/* Simplify STMT using ranges if possible.  */
-
-static bool
-simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
-{
-  gimple *stmt = gsi_stmt (*gsi);
-  if (is_gimple_assign (stmt))
-    {
-      enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
-      tree rhs1 = gimple_assign_rhs1 (stmt);
-      tree rhs2 = gimple_assign_rhs2 (stmt);
-      tree lhs = gimple_assign_lhs (stmt);
-      tree val1 = NULL_TREE, val2 = NULL_TREE;
-      use_operand_p use_p;
-      gimple *use_stmt;
-
-      /* Convert:
-	 LHS = CST BINOP VAR
-	 Where VAR is two-valued and LHS is used in GIMPLE_COND only
-	 To:
-	 LHS = VAR == VAL1 ? (CST BINOP VAL1) : (CST BINOP VAL2)
-
-	 Also handles:
-	 LHS = VAR BINOP CST
-	 Where VAR is two-valued and LHS is used in GIMPLE_COND only
-	 To:
-	 LHS = VAR == VAL1 ? (VAL1 BINOP CST) : (VAL2 BINOP CST) */
-
-      if (TREE_CODE_CLASS (rhs_code) == tcc_binary
-	  && INTEGRAL_TYPE_P (TREE_TYPE (lhs))
-	  && ((TREE_CODE (rhs1) == INTEGER_CST
-	       && TREE_CODE (rhs2) == SSA_NAME)
-	      || (TREE_CODE (rhs2) == INTEGER_CST
-		  && TREE_CODE (rhs1) == SSA_NAME))
-	  && single_imm_use (lhs, &use_p, &use_stmt)
-	  && gimple_code (use_stmt) == GIMPLE_COND)
-
-	{
-	  tree new_rhs1 = NULL_TREE;
-	  tree new_rhs2 = NULL_TREE;
-	  tree cmp_var = NULL_TREE;
-
-	  if (TREE_CODE (rhs2) == SSA_NAME
-	      && two_valued_val_range_p (rhs2, &val1, &val2))
-	    {
-	      /* Optimize RHS1 OP [VAL1, VAL2].  */
-	      new_rhs1 = int_const_binop (rhs_code, rhs1, val1);
-	      new_rhs2 = int_const_binop (rhs_code, rhs1, val2);
-	      cmp_var = rhs2;
-	    }
-	  else if (TREE_CODE (rhs1) == SSA_NAME
-		   && two_valued_val_range_p (rhs1, &val1, &val2))
-	    {
-	      /* Optimize [VAL1, VAL2] OP RHS2.  */
-	      new_rhs1 = int_const_binop (rhs_code, val1, rhs2);
-	      new_rhs2 = int_const_binop (rhs_code, val2, rhs2);
-	      cmp_var = rhs1;
-	    }
-
-	  /* If we could not find two-vals or the optimzation is invalid as
-	     in divide by zero, new_rhs1 / new_rhs will be NULL_TREE.  */
-	  if (new_rhs1 && new_rhs2)
-	    {
-	      tree cond = build2 (EQ_EXPR, boolean_type_node, cmp_var, val1);
-	      gimple_assign_set_rhs_with_ops (gsi,
-					      COND_EXPR, cond,
-					      new_rhs1,
-					      new_rhs2);
-	      update_stmt (gsi_stmt (*gsi));
-	      fold_stmt (gsi, follow_single_use_edges);
-	      return true;
-	    }
-	}
-
-      switch (rhs_code)
-	{
-	case EQ_EXPR:
-	case NE_EXPR:
-          /* Transform EQ_EXPR, NE_EXPR into BIT_XOR_EXPR or identity
-	     if the RHS is zero or one, and the LHS are known to be boolean
-	     values.  */
-	  if (INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
-	    return simplify_truth_ops_using_ranges (gsi, stmt);
-	  break;
-
-      /* Transform TRUNC_DIV_EXPR and TRUNC_MOD_EXPR into RSHIFT_EXPR
-	 and BIT_AND_EXPR respectively if the first operand is greater
-	 than zero and the second operand is an exact power of two.
-	 Also optimize TRUNC_MOD_EXPR away if the second operand is
-	 constant and the first operand already has the right value
-	 range.  */
-	case TRUNC_DIV_EXPR:
-	case TRUNC_MOD_EXPR:
-	  if ((TREE_CODE (rhs1) == SSA_NAME
-	       || TREE_CODE (rhs1) == INTEGER_CST)
-	      && INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
-	    return simplify_div_or_mod_using_ranges (gsi, stmt);
-	  break;
-
-      /* Transform ABS (X) into X or -X as appropriate.  */
-	case ABS_EXPR:
-	  if (TREE_CODE (rhs1) == SSA_NAME
-	      && INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
-	    return simplify_abs_using_ranges (gsi, stmt);
-	  break;
-
-	case BIT_AND_EXPR:
-	case BIT_IOR_EXPR:
-	  /* Optimize away BIT_AND_EXPR and BIT_IOR_EXPR
-	     if all the bits being cleared are already cleared or
-	     all the bits being set are already set.  */
-	  if (INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
-	    return simplify_bit_ops_using_ranges (gsi, stmt);
-	  break;
-
-	CASE_CONVERT:
-	  if (TREE_CODE (rhs1) == SSA_NAME
-	      && INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
-	    return simplify_conversion_using_ranges (gsi, stmt);
-	  break;
-
-	case FLOAT_EXPR:
-	  if (TREE_CODE (rhs1) == SSA_NAME
-	      && INTEGRAL_TYPE_P (TREE_TYPE (rhs1)))
-	    return simplify_float_conversion_using_ranges (gsi, stmt);
-	  break;
-
-	case MIN_EXPR:
-	case MAX_EXPR:
-	  return simplify_min_or_max_using_ranges (gsi, stmt);
-
-	default:
-	  break;
-	}
-    }
-  else if (gimple_code (stmt) == GIMPLE_COND)
-    return simplify_cond_using_ranges_1 (as_a <gcond *> (stmt));
-  else if (gimple_code (stmt) == GIMPLE_SWITCH)
-    return simplify_switch_using_ranges (as_a <gswitch *> (stmt));
-  else if (is_gimple_call (stmt)
-	   && gimple_call_internal_p (stmt))
-    return simplify_internal_call_using_ranges (gsi, stmt);
-
-  return false;
-}
+ public:
+  tree get_value (tree) FINAL OVERRIDE;
+  bool fold_stmt (gimple_stmt_iterator *) FINAL OVERRIDE;
+  bool fold_predicate_in (gimple_stmt_iterator *);
+
+  class vr_values *vr_values;
+
+  /* Delegators.  */
+  tree vrp_evaluate_conditional (tree_code code, tree op0,
+				 tree op1, gimple *stmt)
+    { return vr_values->vrp_evaluate_conditional (code, op0, op1, stmt); }
+  bool simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
+    { return vr_values->simplify_stmt_using_ranges (gsi); }
+ tree op_with_constant_singleton_value_range (tree op)
+    { return vr_values->op_with_constant_singleton_value_range (op); }
+};
 
 /* If the statement pointed by SI has a predicate whose value can be
    computed using the value range information computed by VRP, compute
    its value and return true.  Otherwise, return false.  */
 
-static bool
-fold_predicate_in (gimple_stmt_iterator *si)
+bool
+vrp_folder::fold_predicate_in (gimple_stmt_iterator *si)
 {
   bool assignment_p = false;
   tree val;
@@ -10531,8 +6218,8 @@
 
 /* Callback for substitute_and_fold folding the stmt at *SI.  */
 
-static bool
-vrp_fold_stmt (gimple_stmt_iterator *si)
+bool
+vrp_folder::fold_stmt (gimple_stmt_iterator *si)
 {
   if (fold_predicate_in (si))
     return true;
@@ -10540,6 +6227,18 @@
   return simplify_stmt_using_ranges (si);
 }
 
+/* If OP has a value range with a single constant value return that,
+   otherwise return NULL_TREE.  This returns OP itself if OP is a
+   constant.
+
+   Implemented as a pure wrapper right now, but this will change.  */
+
+tree
+vrp_folder::get_value (tree op)
+{
+  return op_with_constant_singleton_value_range (op);
+}
+
 /* Return the LHS of any ASSERT_EXPR where OP appears as the first
    argument to the ASSERT_EXPR and in which the ASSERT_EXPR dominates
    BB.  If no such ASSERT_EXPR is found, return OP.  */
@@ -10567,6 +6266,9 @@
   return op;
 }
 
+/* A hack.  */
+static class vr_values *x_vr_values;
+
 /* A trivial wrapper so that we can present the generic jump threading
    code with a simple API for simplifying statements.  STMT is the
    statement we want to simplify, WITHIN_STMT provides the location
@@ -10582,6 +6284,7 @@
   if (cached_lhs && is_gimple_min_invariant (cached_lhs))
     return cached_lhs;
 
+  vr_values *vr_values = x_vr_values;
   if (gcond *cond_stmt = dyn_cast <gcond *> (stmt))
     {
       tree op0 = gimple_cond_lhs (cond_stmt);
@@ -10590,8 +6293,8 @@
       tree op1 = gimple_cond_rhs (cond_stmt);
       op1 = lhs_of_dominating_assert (op1, bb, stmt);
 
-      return vrp_evaluate_conditional (gimple_cond_code (cond_stmt),
-				       op0, op1, within_stmt);
+      return vr_values->vrp_evaluate_conditional (gimple_cond_code (cond_stmt),
+						  op0, op1, within_stmt);
     }
 
   /* We simplify a switch statement by trying to determine which case label
@@ -10605,17 +6308,18 @@
 
       op = lhs_of_dominating_assert (op, bb, stmt);
 
-      value_range *vr = get_value_range (op);
-      if ((vr->type != VR_RANGE && vr->type != VR_ANTI_RANGE)
-	  || symbolic_range_p (vr))
+      const value_range *vr = vr_values->get_value_range (op);
+      if (vr->undefined_p ()
+	  || vr->varying_p ()
+	  || vr->symbolic_p ())
 	return NULL_TREE;
 
-      if (vr->type == VR_RANGE)
+      if (vr->kind () == 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)
@@ -10625,10 +6329,11 @@
 	      /* 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)))
+		  ? (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;
 	    }
 
@@ -10638,7 +6343,7 @@
 	    return gimple_switch_label (switch_stmt, 0);
 	}
 
-      if (vr->type == VR_ANTI_RANGE)
+      if (vr->kind () == VR_ANTI_RANGE)
 	{
 	  unsigned n = gimple_switch_num_labels (switch_stmt);
 	  tree min_label = gimple_switch_label (switch_stmt, 1);
@@ -10647,10 +6352,12 @@
 	  /* 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
+	  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);
 	}
 
@@ -10659,16 +6366,20 @@
 
   if (gassign *assign_stmt = dyn_cast <gassign *> (stmt))
     {
-      value_range new_vr = VR_INITIALIZER;
       tree lhs = gimple_assign_lhs (assign_stmt);
-
       if (TREE_CODE (lhs) == SSA_NAME
 	  && (INTEGRAL_TYPE_P (TREE_TYPE (lhs))
-	      || POINTER_TYPE_P (TREE_TYPE (lhs))))
+	      || POINTER_TYPE_P (TREE_TYPE (lhs)))
+	  && stmt_interesting_for_vrp (stmt))
 	{
-	  extract_range_from_assignment (&new_vr, assign_stmt);
-	  if (range_int_cst_singleton_p (&new_vr))
-	    return new_vr.min;
+	  edge dummy_e;
+	  tree dummy_tree;
+	  value_range new_vr;
+	  vr_values->extract_range_from_stmt (stmt, &dummy_e,
+					      &dummy_tree, &new_vr);
+	  tree singleton;
+	  if (new_vr.singleton_p (&singleton))
+	    return singleton;
 	}
     }
 
@@ -10681,7 +6392,7 @@
   vrp_dom_walker (cdi_direction direction,
 		  class const_and_copies *const_and_copies,
 		  class avail_exprs_stack *avail_exprs_stack)
-    : dom_walker (direction, true),
+    : dom_walker (direction, REACHABLE_BLOCKS),
       m_const_and_copies (const_and_copies),
       m_avail_exprs_stack (avail_exprs_stack),
       m_dummy_cond (NULL) {}
@@ -10689,11 +6400,14 @@
   virtual edge before_dom_children (basic_block);
   virtual void after_dom_children (basic_block);
 
+  class vr_values *vr_values;
+
 private:
   class const_and_copies *m_const_and_copies;
   class avail_exprs_stack *m_avail_exprs_stack;
 
   gcond *m_dummy_cond;
+
 };
 
 /* Called before processing dominator children of BB.  We want to look
@@ -10746,9 +6460,11 @@
 				      integer_zero_node, integer_zero_node,
 				      NULL, NULL);
 
+  x_vr_values = vr_values;
   thread_outgoing_edges (bb, m_dummy_cond, m_const_and_copies,
-			 m_avail_exprs_stack,
+			 m_avail_exprs_stack, NULL,
 			 simplify_stmt_for_jump_threading);
+  x_vr_values = NULL;
 
   m_avail_exprs_stack->pop_to_marker ();
   m_const_and_copies->pop_to_marker ();
@@ -10775,11 +6491,8 @@
    for later realization.  */
 
 static void
-identify_jump_threads (void)
+identify_jump_threads (class vr_values *vr_values)
 {
-  int i;
-  edge e;
-
   /* Ugh.  When substituting values earlier in this pass we can
      wipe the dominance information.  So rebuild the dominator
      information as we need it within the jump threading code.  */
@@ -10792,11 +6505,6 @@
      recompute it.  */
   mark_dfs_back_edges ();
 
-  /* Do not thread across edges we are about to remove.  Just marking
-     them as EDGE_IGNORE will do.  */
-  FOR_EACH_VEC_ELT (to_remove_edges, i, e)
-    e->flags |= EDGE_IGNORE;
-
   /* Allocate our unwinder stack to unwind any temporary equivalences
      that might be recorded.  */
   const_and_copies *equiv_stack = new const_and_copies ();
@@ -10807,12 +6515,9 @@
     = new class avail_exprs_stack (avail_exprs);
 
   vrp_dom_walker walker (CDI_DOMINATORS, equiv_stack, avail_exprs_stack);
+  walker.vr_values = vr_values;
   walker.walk (cfun->cfg->x_entry_block_ptr);
 
-  /* Clear EDGE_IGNORE.  */
-  FOR_EACH_VEC_ELT (to_remove_edges, i, e)
-    e->flags &= ~EDGE_IGNORE;
-
   /* We do not actually update the CFG or SSA graphs at this point as
      ASSERT_EXPRs are still in the IL and cfg cleanup code does not yet
      handle ASSERT_EXPRs gracefully.  */
@@ -10821,585 +6526,63 @@
   delete avail_exprs_stack;
 }
 
-/* Free VRP lattice.  */
-
-static void
-vrp_free_lattice ()
-{
-  /* Free allocated memory.  */
-  free (vr_value);
-  free (vr_phi_edge_counts);
-  bitmap_obstack_release (&vrp_equiv_obstack);
-  vrp_value_range_pool.release ();
-
-  /* So that we can distinguish between VRP data being available
-     and not available.  */
-  vr_value = NULL;
-  vr_phi_edge_counts = NULL;
-}
-
 /* Traverse all the blocks folding conditionals with known ranges.  */
 
-static void
-vrp_finalize (bool warn_array_bounds_p)
+void
+vrp_prop::vrp_finalize (bool warn_array_bounds_p)
 {
   size_t i;
 
-  values_propagated = true;
+  /* We have completed propagating through the lattice.  */
+  vr_values.set_lattice_propagation_complete ();
 
   if (dump_file)
     {
       fprintf (dump_file, "\nValue ranges after VRP:\n\n");
-      dump_all_value_ranges (dump_file);
+      vr_values.dump_all_value_ranges (dump_file);
       fprintf (dump_file, "\n");
     }
 
   /* Set value range to non pointer SSA_NAMEs.  */
-  for (i  = 0; i < num_vr_values; i++)
-    if (vr_value[i])
-      {
-	tree name = ssa_name (i);
-
-	if (!name
-	    || (vr_value[i]->type == VR_VARYING)
-	    || (vr_value[i]->type == VR_UNDEFINED)
-	    || (TREE_CODE (vr_value[i]->min) != INTEGER_CST)
-	    || (TREE_CODE (vr_value[i]->max) != INTEGER_CST))
-	  continue;
-
-	if (POINTER_TYPE_P (TREE_TYPE (name))
-	    && ((vr_value[i]->type == VR_RANGE
-		 && range_includes_zero_p (vr_value[i]->min,
-					   vr_value[i]->max) == 0)
-		|| (vr_value[i]->type == VR_ANTI_RANGE
-		    && range_includes_zero_p (vr_value[i]->min,
-					      vr_value[i]->max) == 1)))
-	  set_ptr_nonnull (name);
-	else if (!POINTER_TYPE_P (TREE_TYPE (name)))
-	  set_range_info (name, vr_value[i]->type,
-			  wi::to_wide (vr_value[i]->min),
-			  wi::to_wide (vr_value[i]->max));
-      }
-
-  substitute_and_fold (op_with_constant_singleton_value_range, vrp_fold_stmt);
+  for (i = 0; i < num_ssa_names; i++)
+    {
+      tree name = ssa_name (i);
+      if (!name)
+	continue;
+
+      const value_range *vr = get_value_range (name);
+      if (!name || !vr->constant_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->kind (),
+			wi::to_wide (vr->min ()),
+			wi::to_wide (vr->max ()));
+    }
+
+  /* If we're checking array refs, we want to merge information on
+     the executability of each edge between vrp_folder and the
+     check_array_bounds_dom_walker: each can clear the
+     EDGE_EXECUTABLE flag on edges, in different ways.
+
+     Hence, if we're going to call check_all_array_refs, set
+     the flag on every edge now, rather than in
+     check_array_bounds_dom_walker's ctor; vrp_folder may clear
+     it from some edges.  */
+  if (warn_array_bounds && warn_array_bounds_p)
+    set_all_edges_as_executable (cfun);
+
+  class vrp_folder vrp_folder;
+  vrp_folder.vr_values = &vr_values;
+  vrp_folder.substitute_and_fold ();
 
   if (warn_array_bounds && warn_array_bounds_p)
     check_all_array_refs ();
 }
 
-/* evrp_dom_walker visits the basic blocks in the dominance order and set
-   the Value Ranges (VR) for SSA_NAMEs in the scope.  Use this VR to
-   discover more VRs.  */
-
-class evrp_dom_walker : public dom_walker
-{
-public:
-  evrp_dom_walker ()
-    : dom_walker (CDI_DOMINATORS), stack (10)
-    {
-      need_eh_cleanup = BITMAP_ALLOC (NULL);
-    }
-  ~evrp_dom_walker ()
-    {
-      BITMAP_FREE (need_eh_cleanup);
-    }
-  virtual edge before_dom_children (basic_block);
-  virtual void after_dom_children (basic_block);
-  void push_value_range (tree var, value_range *vr);
-  value_range *pop_value_range (tree var);
-  value_range *try_find_new_range (tree, tree op, tree_code code, tree limit);
-
-  /* Cond_stack holds the old VR.  */
-  auto_vec<std::pair <tree, value_range*> > stack;
-  bitmap need_eh_cleanup;
-  auto_vec<gimple *> stmts_to_fixup;
-  auto_vec<gimple *> stmts_to_remove;
-};
-
-/*  Find new range for NAME such that (OP CODE LIMIT) is true.  */
-
-value_range *
-evrp_dom_walker::try_find_new_range (tree name,
-				     tree op, tree_code code, tree limit)
-{
-  value_range vr = VR_INITIALIZER;
-  value_range *old_vr = get_value_range (name);
-
-  /* Discover VR when condition is true.  */
-  extract_range_for_var_from_comparison_expr (name, code, op,
-					      limit, &vr);
-  /* If we found any usable VR, set the VR to ssa_name and create a
-     PUSH old value in the stack with the old VR.  */
-  if (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE)
-    {
-      if (old_vr->type == vr.type
-	  && vrp_operand_equal_p (old_vr->min, vr.min)
-	  && vrp_operand_equal_p (old_vr->max, vr.max))
-	return NULL;
-      value_range *new_vr = vrp_value_range_pool.allocate ();
-      *new_vr = vr;
-      return new_vr;
-    }
-  return NULL;
-}
-
-/* See if there is any new scope is entered with new VR and set that VR to
-   ssa_name before visiting the statements in the scope.  */
-
-edge
-evrp_dom_walker::before_dom_children (basic_block bb)
-{
-  tree op0 = NULL_TREE;
-  edge_iterator ei;
-  edge e;
-
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    fprintf (dump_file, "Visiting BB%d\n", bb->index);
-
-  stack.safe_push (std::make_pair (NULL_TREE, (value_range *)NULL));
-
-  edge pred_e = NULL;
-  FOR_EACH_EDGE (e, ei, bb->preds)
-    {
-      /* Ignore simple backedges from this to allow recording conditions
-	 in loop headers.  */
-      if (dominated_by_p (CDI_DOMINATORS, e->src, e->dest))
-	continue;
-      if (! pred_e)
-	pred_e = e;
-      else
-	{
-	  pred_e = NULL;
-	  break;
-	}
-    }
-  if (pred_e)
-    {
-      gimple *stmt = last_stmt (pred_e->src);
-      if (stmt
-	  && gimple_code (stmt) == GIMPLE_COND
-	  && (op0 = gimple_cond_lhs (stmt))
-	  && TREE_CODE (op0) == SSA_NAME
-	  && (INTEGRAL_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt)))
-	      || POINTER_TYPE_P (TREE_TYPE (gimple_cond_lhs (stmt)))))
-	{
-	  if (dump_file && (dump_flags & TDF_DETAILS))
-	    {
-	      fprintf (dump_file, "Visiting controlling predicate ");
-	      print_gimple_stmt (dump_file, stmt, 0);
-	    }
-	  /* Entering a new scope.  Try to see if we can find a VR
-	     here.  */
-	  tree op1 = gimple_cond_rhs (stmt);
-	  if (TREE_OVERFLOW_P (op1))
-	    op1 = drop_tree_overflow (op1);
-	  tree_code code = gimple_cond_code (stmt);
-
-	  auto_vec<assert_info, 8> asserts;
-	  register_edge_assert_for (op0, pred_e, code, op0, op1, asserts);
-	  if (TREE_CODE (op1) == SSA_NAME)
-	    register_edge_assert_for (op1, pred_e, code, op0, op1, asserts);
-
-	  auto_vec<std::pair<tree, value_range *>, 8> vrs;
-	  for (unsigned i = 0; i < asserts.length (); ++i)
-	    {
-	      value_range *vr = try_find_new_range (asserts[i].name,
-						    asserts[i].expr,
-						    asserts[i].comp_code,
-						    asserts[i].val);
-	      if (vr)
-		vrs.safe_push (std::make_pair (asserts[i].name, vr));
-	    }
-	  /* Push updated ranges only after finding all of them to avoid
-	     ordering issues that can lead to worse ranges.  */
-	  for (unsigned i = 0; i < vrs.length (); ++i)
-	    push_value_range (vrs[i].first, vrs[i].second);
-	}
-    }
-
-  /* Visit PHI stmts and discover any new VRs possible.  */
-  bool has_unvisited_preds = false;
-  FOR_EACH_EDGE (e, ei, bb->preds)
-    if (e->flags & EDGE_EXECUTABLE
-	&& !(e->src->flags & BB_VISITED))
-      {
-	has_unvisited_preds = true;
-	break;
-      }
-
-  for (gphi_iterator gpi = gsi_start_phis (bb);
-       !gsi_end_p (gpi); gsi_next (&gpi))
-    {
-      gphi *phi = gpi.phi ();
-      tree lhs = PHI_RESULT (phi);
-      if (virtual_operand_p (lhs))
-	continue;
-      value_range vr_result = VR_INITIALIZER;
-      bool interesting = stmt_interesting_for_vrp (phi);
-      if (interesting && dump_file && (dump_flags & TDF_DETAILS))
-	{
-	  fprintf (dump_file, "Visiting PHI node ");
-	  print_gimple_stmt (dump_file, phi, 0);
-	}
-      if (!has_unvisited_preds
-	  && interesting)
-	extract_range_from_phi_node (phi, &vr_result);
-      else
-	{
-	  set_value_range_to_varying (&vr_result);
-	  /* When we have an unvisited executable predecessor we can't
-	     use PHI arg ranges which may be still UNDEFINED but have
-	     to use VARYING for them.  But we can still resort to
-	     SCEV for loop header PHIs.  */
-	  struct loop *l;
-	  if (interesting
-	      && (l = loop_containing_stmt (phi))
-	      && l->header == gimple_bb (phi))
-	    adjust_range_with_scev (&vr_result, l, phi, lhs);
-	}
-      update_value_range (lhs, &vr_result);
-
-      /* Mark PHIs whose lhs we fully propagate for removal.  */
-      tree val = op_with_constant_singleton_value_range (lhs);
-      if (val && may_propagate_copy (lhs, val))
-	{
-	  stmts_to_remove.safe_push (phi);
-	  continue;
-	}
-
-      /* Set the SSA with the value range.  */
-      if (INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
-	{
-	  if ((vr_result.type == VR_RANGE
-	       || vr_result.type == VR_ANTI_RANGE)
-	      && (TREE_CODE (vr_result.min) == INTEGER_CST)
-	      && (TREE_CODE (vr_result.max) == INTEGER_CST))
-	    set_range_info (lhs, vr_result.type,
-			    wi::to_wide (vr_result.min),
-			    wi::to_wide (vr_result.max));
-	}
-      else if (POINTER_TYPE_P (TREE_TYPE (lhs))
-	       && ((vr_result.type == VR_RANGE
-		    && range_includes_zero_p (vr_result.min,
-					      vr_result.max) == 0)
-		   || (vr_result.type == VR_ANTI_RANGE
-		       && range_includes_zero_p (vr_result.min,
-						 vr_result.max) == 1)))
-	set_ptr_nonnull (lhs);
-    }
-
-  edge taken_edge = NULL;
-
-  /* Visit all other stmts and discover any new VRs possible.  */
-  for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
-       !gsi_end_p (gsi); gsi_next (&gsi))
-    {
-      gimple *stmt = gsi_stmt (gsi);
-      tree output = NULL_TREE;
-      gimple *old_stmt = stmt;
-      bool was_noreturn = (is_gimple_call (stmt)
-			   && gimple_call_noreturn_p (stmt));
-
-      if (dump_file && (dump_flags & TDF_DETAILS))
-	{
-	  fprintf (dump_file, "Visiting stmt ");
-	  print_gimple_stmt (dump_file, stmt, 0);
-	}
-
-      if (gcond *cond = dyn_cast <gcond *> (stmt))
-	{
-	  vrp_visit_cond_stmt (cond, &taken_edge);
-	  if (taken_edge)
-	    {
-	      if (taken_edge->flags & EDGE_TRUE_VALUE)
-		gimple_cond_make_true (cond);
-	      else if (taken_edge->flags & EDGE_FALSE_VALUE)
-		gimple_cond_make_false (cond);
-	      else
-		gcc_unreachable ();
-	      update_stmt (stmt);
-	    }
-	}
-      else if (stmt_interesting_for_vrp (stmt))
-	{
-	  edge taken_edge;
-	  value_range vr = VR_INITIALIZER;
-	  extract_range_from_stmt (stmt, &taken_edge, &output, &vr);
-	  if (output
-	      && (vr.type == VR_RANGE || vr.type == VR_ANTI_RANGE))
-	    {
-	      update_value_range (output, &vr);
-	      vr = *get_value_range (output);
-
-	      /* Mark stmts whose output we fully propagate for removal.  */
-	      tree val;
-	      if ((val = op_with_constant_singleton_value_range (output))
-		  && may_propagate_copy (output, val)
-		  && !stmt_could_throw_p (stmt)
-		  && !gimple_has_side_effects (stmt))
-		{
-		  stmts_to_remove.safe_push (stmt);
-		  continue;
-		}
-
-	      /* Set the SSA with the value range.  */
-	      if (INTEGRAL_TYPE_P (TREE_TYPE (output)))
-		{
-		  if ((vr.type == VR_RANGE
-		       || vr.type == VR_ANTI_RANGE)
-		      && (TREE_CODE (vr.min) == INTEGER_CST)
-		      && (TREE_CODE (vr.max) == INTEGER_CST))
-		    set_range_info (output, vr.type,
-				    wi::to_wide (vr.min),
-				    wi::to_wide (vr.max));
-		}
-	      else if (POINTER_TYPE_P (TREE_TYPE (output))
-		       && ((vr.type == VR_RANGE
-			    && range_includes_zero_p (vr.min,
-						      vr.max) == 0)
-			   || (vr.type == VR_ANTI_RANGE
-			       && range_includes_zero_p (vr.min,
-							 vr.max) == 1)))
-		set_ptr_nonnull (output);
-	    }
-	  else
-	    set_defs_to_varying (stmt);
-	}
-      else
-	set_defs_to_varying (stmt);
-
-      /* See if we can derive a range for any of STMT's operands.  */
-      tree op;
-      ssa_op_iter i;
-      FOR_EACH_SSA_TREE_OPERAND (op, stmt, i, SSA_OP_USE)
-	{
-	  tree value;
-	  enum tree_code comp_code;
-
-	  /* If OP is used in such a way that we can infer a value
-	     range for it, and we don't find a previous assertion for
-	     it, create a new assertion location node for OP.  */
-	  if (infer_value_range (stmt, op, &comp_code, &value))
-	    {
-	      /* If we are able to infer a nonzero value range for OP,
-		 then walk backwards through the use-def chain to see if OP
-		 was set via a typecast.
-		 If so, then we can also infer a nonzero value range
-		 for the operand of the NOP_EXPR.  */
-	      if (comp_code == NE_EXPR && integer_zerop (value))
-		{
-		  tree t = op;
-		  gimple *def_stmt = SSA_NAME_DEF_STMT (t);
-		  while (is_gimple_assign (def_stmt)
-			 && CONVERT_EXPR_CODE_P
-			      (gimple_assign_rhs_code (def_stmt))
-			 && TREE_CODE
-			      (gimple_assign_rhs1 (def_stmt)) == SSA_NAME
-			 && POINTER_TYPE_P
-			      (TREE_TYPE (gimple_assign_rhs1 (def_stmt))))
-		    {
-		      t = gimple_assign_rhs1 (def_stmt);
-		      def_stmt = SSA_NAME_DEF_STMT (t);
-
-		      /* Add VR when (T COMP_CODE value) condition is
-			 true.  */
-		      value_range *op_range
-			= try_find_new_range (t, t, comp_code, value);
-		      if (op_range)
-			push_value_range (t, op_range);
-		    }
-		}
-	      /* Add VR when (OP COMP_CODE value) condition is true.  */
-	      value_range *op_range = try_find_new_range (op, op,
-							  comp_code, value);
-	      if (op_range)
-		push_value_range (op, op_range);
-	    }
-	}
-
-      /* Try folding stmts with the VR discovered.  */
-      bool did_replace
-	= replace_uses_in (stmt, op_with_constant_singleton_value_range);
-      if (fold_stmt (&gsi, follow_single_use_edges)
-	  || did_replace)
-	{
-	  stmt = gsi_stmt (gsi);
-	  update_stmt (stmt);
-	  did_replace = true;
-	}
-
-      if (did_replace)
-	{
-	  /* If we cleaned up EH information from the statement,
-	     remove EH edges.  */
-	  if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
-	    bitmap_set_bit (need_eh_cleanup, bb->index);
-
-	  /* If we turned a not noreturn call into a noreturn one
-	     schedule it for fixup.  */
-	  if (!was_noreturn
-	      && is_gimple_call (stmt)
-	      && gimple_call_noreturn_p (stmt))
-	    stmts_to_fixup.safe_push (stmt);
-
-	  if (gimple_assign_single_p (stmt))
-	    {
-	      tree rhs = gimple_assign_rhs1 (stmt);
-	      if (TREE_CODE (rhs) == ADDR_EXPR)
-		recompute_tree_invariant_for_addr_expr (rhs);
-	    }
-	}
-    }
-
-  /* Visit BB successor PHI nodes and replace PHI args.  */
-  FOR_EACH_EDGE (e, ei, bb->succs)
-    {
-      for (gphi_iterator gpi = gsi_start_phis (e->dest);
-	   !gsi_end_p (gpi); gsi_next (&gpi))
-	{
-	  gphi *phi = gpi.phi ();
-	  use_operand_p use_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, e);
-	  tree arg = USE_FROM_PTR (use_p);
-	  if (TREE_CODE (arg) != SSA_NAME
-	      || virtual_operand_p (arg))
-	    continue;
-	  tree val = op_with_constant_singleton_value_range (arg);
-	  if (val && may_propagate_copy (arg, val))
-	    propagate_value (use_p, val);
-	}
-    }
- 
-  bb->flags |= BB_VISITED;
-
-  return taken_edge;
-}
-
-/* Restore/pop VRs valid only for BB when we leave BB.  */
-
-void
-evrp_dom_walker::after_dom_children (basic_block bb ATTRIBUTE_UNUSED)
-{
-  gcc_checking_assert (!stack.is_empty ());
-  while (stack.last ().first != NULL_TREE)
-    pop_value_range (stack.last ().first);
-  stack.pop ();
-}
-
-/* Push the Value Range of VAR to the stack and update it with new VR.  */
-
-void
-evrp_dom_walker::push_value_range (tree var, value_range *vr)
-{
-  if (SSA_NAME_VERSION (var) >= num_vr_values)
-    return;
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "pushing new range for ");
-      print_generic_expr (dump_file, var);
-      fprintf (dump_file, ": ");
-      dump_value_range (dump_file, vr);
-      fprintf (dump_file, "\n");
-    }
-  stack.safe_push (std::make_pair (var, get_value_range (var)));
-  vr_value[SSA_NAME_VERSION (var)] = vr;
-}
-
-/* Pop the Value Range from the vrp_stack and update VAR with it.  */
-
-value_range *
-evrp_dom_walker::pop_value_range (tree var)
-{
-  value_range *vr = stack.last ().second;
-  gcc_checking_assert (var == stack.last ().first);
-  if (dump_file && (dump_flags & TDF_DETAILS))
-    {
-      fprintf (dump_file, "popping range for ");
-      print_generic_expr (dump_file, var);
-      fprintf (dump_file, ", restoring ");
-      dump_value_range (dump_file, vr);
-      fprintf (dump_file, "\n");
-    }
-  vr_value[SSA_NAME_VERSION (var)] = vr;
-  stack.pop ();
-  return vr;
-}
-
-
-/* Main entry point for the early vrp pass which is a simplified non-iterative
-   version of vrp where basic blocks are visited in dominance order.  Value
-   ranges discovered in early vrp will also be used by ipa-vrp.  */
-
-static unsigned int
-execute_early_vrp ()
-{
-  edge e;
-  edge_iterator ei;
-  basic_block bb;
-
-  loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS);
-  rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
-  scev_initialize ();
-  calculate_dominance_info (CDI_DOMINATORS);
-  FOR_EACH_BB_FN (bb, cfun)
-    {
-      bb->flags &= ~BB_VISITED;
-      FOR_EACH_EDGE (e, ei, bb->preds)
-	e->flags |= EDGE_EXECUTABLE;
-    }
-  vrp_initialize_lattice ();
-
-  /* Walk stmts in dominance order and propagate VRP.  */
-  evrp_dom_walker walker;
-  walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
-
-  if (dump_file)
-    {
-      fprintf (dump_file, "\nValue ranges after Early VRP:\n\n");
-      dump_all_value_ranges (dump_file);
-      fprintf (dump_file, "\n");
-    }
-
-  /* Remove stmts in reverse order to make debug stmt creation possible.  */
-  while (! walker.stmts_to_remove.is_empty ())
-    {
-      gimple *stmt = walker.stmts_to_remove.pop ();
-      if (dump_file && dump_flags & TDF_DETAILS)
-	{
-	  fprintf (dump_file, "Removing dead stmt ");
-	  print_gimple_stmt (dump_file, stmt, 0);
-	  fprintf (dump_file, "\n");
-	}
-      gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
-      if (gimple_code (stmt) == GIMPLE_PHI)
-	remove_phi_node (&gsi, true);
-      else
-	{
-	  unlink_stmt_vdef (stmt);
-	  gsi_remove (&gsi, true);
-	  release_defs (stmt);
-	}
-    }
-
-  if (!bitmap_empty_p (walker.need_eh_cleanup))
-    gimple_purge_all_dead_eh_edges (walker.need_eh_cleanup);
-
-  /* Fixup stmts that became noreturn calls.  This may require splitting
-     blocks and thus isn't possible during the dominator walk.  Do this
-     in reverse order so we don't inadvertedly remove a stmt we want to
-     fixup by visiting a dominating now noreturn call first.  */
-  while (!walker.stmts_to_fixup.is_empty ())
-    {
-      gimple *stmt = walker.stmts_to_fixup.pop ();
-      fixup_noreturn_call (stmt);
-    }
-
-  vrp_free_lattice ();
-  scev_finalize ();
-  loop_optimizer_finalize ();
-  return 0;
-}
-
-
 /* Main entry point to VRP (Value Range Propagation).  This pass is
    loosely based on J. R. C. Patterson, ``Accurate Static Branch
    Prediction by Value Range Propagation,'' in SIGPLAN Conference on
@@ -11447,9 +6630,6 @@
 static unsigned int
 execute_vrp (bool warn_array_bounds_p)
 {
-  int i;
-  edge e;
-  switch_update *su;
 
   loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS);
   rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
@@ -11460,21 +6640,19 @@
      EDGE_DFS_BACK.  */
   insert_range_assertions ();
 
-  to_remove_edges.create (10);
-  to_update_switch_stmts.create (5);
   threadedge_initialize_values ();
 
   /* For visiting PHI nodes we need EDGE_DFS_BACK computed.  */
   mark_dfs_back_edges ();
 
-  vrp_initialize_lattice ();
-  vrp_initialize ();
-  ssa_propagate (vrp_visit_stmt, vrp_visit_phi_node);
-  vrp_finalize (warn_array_bounds_p);
+  class vrp_prop vrp_prop;
+  vrp_prop.vrp_initialize ();
+  vrp_prop.ssa_propagate ();
+  vrp_prop.vrp_finalize (warn_array_bounds_p);
 
   /* We must identify jump threading opportunities before we release
      the datastructures built by VRP.  */
-  identify_jump_threads ();
+  identify_jump_threads (&vrp_prop.vr_values);
 
   /* A comparison of an SSA_NAME against a constant where the SSA_NAME
      was set by a type conversion can often be rewritten to use the
@@ -11488,10 +6666,8 @@
     {
       gimple *last = last_stmt (bb);
       if (last && gimple_code (last) == GIMPLE_COND)
-	simplify_cond_using_ranges_2 (as_a <gcond *> (last));
-    }
-
-  vrp_free_lattice ();
+	vrp_prop.vr_values.simplify_cond_using_ranges_2 (as_a <gcond *> (last));
+    }
 
   free_numbers_of_iterations_estimates (cfun);
 
@@ -11515,35 +6691,7 @@
      processing by the pass manager.  */
   thread_through_all_blocks (false);
 
-  /* Remove dead edges from SWITCH_EXPR optimization.  This leaves the
-     CFG in a broken state and requires a cfg_cleanup run.  */
-  FOR_EACH_VEC_ELT (to_remove_edges, i, e)
-    remove_edge (e);
-  /* Update SWITCH_EXPR case label vector.  */
-  FOR_EACH_VEC_ELT (to_update_switch_stmts, i, su)
-    {
-      size_t j;
-      size_t n = TREE_VEC_LENGTH (su->vec);
-      tree label;
-      gimple_switch_set_num_labels (su->stmt, n);
-      for (j = 0; j < n; j++)
-	gimple_switch_set_label (su->stmt, j, TREE_VEC_ELT (su->vec, j));
-      /* As we may have replaced the default label with a regular one
-	 make sure to make it a real default label again.  This ensures
-	 optimal expansion.  */
-      label = gimple_switch_label (su->stmt, 0);
-      CASE_LOW (label) = NULL_TREE;
-      CASE_HIGH (label) = NULL_TREE;
-    }
-
-  if (to_remove_edges.length () > 0)
-    {
-      free_dominance_info (CDI_DOMINATORS);
-      loops_state_set (LOOPS_NEED_FIXUP);
-    }
-
-  to_remove_edges.release ();
-  to_update_switch_stmts.release ();
+  vrp_prop.vr_values.cleanup_edges_and_switches ();
   threadedge_finalize_values ();
 
   scev_finalize ();
@@ -11596,43 +6744,59 @@
   return new pass_vrp (ctxt);
 }
 
-namespace {
-
-const pass_data pass_data_early_vrp =
-{
-  GIMPLE_PASS, /* type */
-  "evrp", /* name */
-  OPTGROUP_NONE, /* optinfo_flags */
-  TV_TREE_EARLY_VRP, /* tv_id */
-  PROP_ssa, /* properties_required */
-  0, /* properties_provided */
-  0, /* properties_destroyed */
-  0, /* todo_flags_start */
-  ( TODO_cleanup_cfg | TODO_update_ssa | TODO_verify_all ),
-};
-
-class pass_early_vrp : public gimple_opt_pass
+
+/* Worker for determine_value_range.  */
+
+static void
+determine_value_range_1 (value_range *vr, tree expr)
 {
-public:
-  pass_early_vrp (gcc::context *ctxt)
-    : gimple_opt_pass (pass_data_early_vrp, ctxt)
-    {}
-
-  /* opt_pass methods: */
-  opt_pass * clone () { return new pass_early_vrp (m_ctxt); }
-  virtual bool gate (function *)
-    {
-      return flag_tree_vrp != 0;
-    }
-  virtual unsigned int execute (function *)
-    { return execute_early_vrp (); }
-
-}; // class pass_vrp
-} // anon namespace
-
-gimple_opt_pass *
-make_pass_early_vrp (gcc::context *ctxt)
+  if (BINARY_CLASS_P (expr))
+    {
+      value_range vr0, vr1;
+      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),
+					&vr0, &vr1);
+    }
+  else if (UNARY_CLASS_P (expr))
+    {
+      value_range vr0;
+      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)));
+    }
+  else if (TREE_CODE (expr) == INTEGER_CST)
+    set_value_range_to_value (vr, expr, NULL);
+  else
+    {
+      value_range_kind kind;
+      wide_int min, max;
+      /* For SSA names try to extract range info computed by VRP.  Otherwise
+	 fall back to varying.  */
+      if (TREE_CODE (expr) == SSA_NAME
+	  && INTEGRAL_TYPE_P (TREE_TYPE (expr))
+	  && (kind = get_range_info (expr, &min, &max)) != VR_VARYING)
+	set_value_range (vr, kind, wide_int_to_tree (TREE_TYPE (expr), min),
+			 wide_int_to_tree (TREE_TYPE (expr), max), NULL);
+      else
+	set_value_range_to_varying (vr);
+    }
+}
+
+/* Compute a value-range for EXPR and set it in *MIN and *MAX.  Return
+   the determined range type.  */
+
+value_range_kind
+determine_value_range (tree expr, wide_int *min, wide_int *max)
 {
-  return new pass_early_vrp (ctxt);
+  value_range vr;
+  determine_value_range_1 (&vr, expr);
+  if (vr.constant_p ())
+    {
+      *min = wi::to_wide (vr.min ());
+      *max = wi::to_wide (vr.max ());
+      return vr.kind ();
+    }
+
+  return VR_VARYING;
 }
-