diff --git a/gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C b/gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C
index c80977d3043..eb4801918fc 100644
--- a/gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C
+++ b/gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C
@@ -161,6 +161,40 @@ void test_strcpy_new_int16_t (size_t n, const size_t vals[])
 
   ptrdiff_t r_dmin_dmax = SR (DIFF_MIN, DIFF_MAX);
   T (S (1), new int16_t[r_dmin_dmax]);
+  /* ?? The above SR(DIFF_MIN, DIFF_MAX) implies r_dmin_dmax can be
+     the entire domain, including negative numbers because ptrdiff_t
+     is a signed entity.
+
+     This causes a warning in the following line after the
+     DOM/threader changes for C++98.
+
+      <bb 2> [local count: 1073741824]:
+      _26 ={v} signed_value_source;                      ;; could be -1
+      r_dmin_dmax.1_8 = (sizetype) _26;
+      if (r_dmin_dmax.1_8 <= 4611686018427387900)        ;; placement new rounding
+        goto <bb 3>; [50.00%]
+      else
+        goto <bb 9>; [50.00%]
+
+      ...
+      ...
+
+      <bb 9> [local count: 536870912]:
+      # iftmp.0_39 = PHI <18446744073709551615(2)>
+      _41 = operator new [] (iftmp.0_39);
+      __builtin_memcpy (_41, "z", 2);
+      sink (_41);
+      _44 = _26 + 1;					;; _44 = 0
+      _45 = (sizetype) _44;				;; _45 = 0
+      if (_45 <= 4611686018427387900)
+        goto <bb 8>; [0.00%]
+      else
+        goto <bb 7>; [100.00%]
+
+      <bb 8> [local count: 0]:
+      iftmp.2_33 = _45 * 2;				;; iftmp.2_33 = 0
+      _34 = operator new [] (iftmp.2_33);		;; new [] (0)
+  */
   T (S (2), new int16_t[r_dmin_dmax + 1]);
   T (S (9), new int16_t[r_dmin_dmax * 2 + 1]);
 }
diff --git a/gcc/testsuite/gcc.dg/sancov/cmp0.c b/gcc/testsuite/gcc.dg/sancov/cmp0.c
index 8bbf06e9466..9fd7f5cccc8 100644
--- a/gcc/testsuite/gcc.dg/sancov/cmp0.c
+++ b/gcc/testsuite/gcc.dg/sancov/cmp0.c
@@ -1,6 +1,6 @@
 /* Basic test on number of inserted callbacks.  */
 /* { dg-do compile } */
-/* { dg-options "-fsanitize-coverage=trace-cmp -fdump-tree-optimized" } */
+/* { dg-options "-fsanitize-coverage=trace-cmp -fdump-tree-optimized -fno-thread-jumps" } */
 /* { dg-skip-if "different type layout" { avr-*-* } } */
 
 #if __SIZEOF_INT__ < 4
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-branch-1.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-branch-1.c
index fae5bdef818..ede3274f59d 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-branch-1.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-branch-1.c
@@ -19,10 +19,9 @@ try_combine (rtx i1, rtx newpat)
   else if (i1 && foo ());
 }
 
-/* There should be four tests against i1.  One from the hash table
-   dumps, one from the EVRP analyzer one from EVRP evaluation and one
+/* There should be 3 tests against i1.  Two from DOM machinery and one
    in the code itself.  */
-/* { dg-final { scan-tree-dump-times "if .i1_" 4 "dom2"} } */
+/* { dg-final { scan-tree-dump-times "if .i1_" 3 "dom2"} } */
 
 /* There should be no actual jump threads realized by DOM.  The
    legitimize jump threads are handled in VRP and those discovered
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c
index b64e71dae22..aa06db5e223 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-thread-7.c
@@ -11,7 +11,7 @@
    to change decisions in switch expansion which in turn can expose new
    jump threading opportunities.  Skip the later tests on aarch64.  */
 /* { dg-final { scan-tree-dump-not "Jumps threaded"  "dom3" { target { ! aarch64*-*-* } } } } */
-/* { dg-final { scan-tree-dump "Jumps threaded: 7"  "thread2" { target { ! aarch64*-*-* } } } } */
+/* { dg-final { scan-tree-dump "Jumps threaded: 8"  "thread2" { target { ! aarch64*-*-* } } } } */
 /* { dg-final { scan-tree-dump "Jumps threaded: 18"  "thread2" { target { aarch64*-*-* } } } } */
 
 enum STATE {
diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-2.c b/gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-2.c
index 6b213d4da28..56c4bbf86d8 100644
--- a/gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-2.c
+++ b/gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-2.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-additional-options "-fno-tree-loop-vectorize" } */
+/* { dg-additional-options "-fno-tree-loop-vectorize -fno-tree-dominator-opts" } */
 /* { dg-require-effective-target lp64 } */
 
 double p[1000];
diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-4.c b/gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-4.c
index 599f718ecdc..67ee809826c 100644
--- a/gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-4.c
+++ b/gcc/testsuite/gcc.dg/vect/bb-slp-pr81635-4.c
@@ -1,7 +1,11 @@
 /* { dg-do compile } */
-/* { dg-additional-options "-fno-tree-loop-vectorize" } */
+/* { dg-additional-options "-fno-tree-loop-vectorize -fno-tree-dominator-opts" } */
 /* { dg-require-effective-target lp64 } */
 
+/* A ranger based DOM causes many more SSA names to be exported, which
+   causes slp1 to vectorize more things.  Disabling DOM to avoid
+   disturbing this test.  */
+
 void
 f1 (double *p, double *q, unsigned int n)
 {
diff --git a/gcc/tree-ssa-dom.cc b/gcc/tree-ssa-dom.cc
index 21745bf31d3..74f4eec91be 100644
--- a/gcc/tree-ssa-dom.cc
+++ b/gcc/tree-ssa-dom.cc
@@ -48,7 +48,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "alloc-pool.h"
 #include "tree-vrp.h"
 #include "vr-values.h"
-#include "gimple-ssa-evrp-analyze.h"
+#include "gimple-range.h"
+#include "gimple-range-path.h"
 #include "alias.h"
 
 /* This file implements optimizations on the dominator tree.  */
@@ -589,132 +590,64 @@ class dom_jt_state : public jt_state
 {
 public:
   dom_jt_state (const_and_copies *copies, avail_exprs_stack *avails,
-		evrp_range_analyzer *evrp)
-    : m_copies (copies), m_avails (avails), m_evrp (evrp)
+		gimple_ranger *ranger)
+    : m_copies (copies), m_avails (avails), m_ranger (ranger)
   {
   }
   void push (edge e) override
   {
     m_copies->push_marker ();
     m_avails->push_marker ();
-    m_evrp->push_marker ();
     jt_state::push (e);
   }
   void pop () override
   {
     m_copies->pop_to_marker ();
     m_avails->pop_to_marker ();
-    m_evrp->pop_to_marker ();
     jt_state::pop ();
   }
   void register_equivs_edge (edge e) override
   {
     record_temporary_equivalences (e, m_copies, m_avails);
   }
-  void record_ranges_from_stmt (gimple *stmt, bool temporary) override
-  {
-    m_evrp->record_ranges_from_stmt (stmt, temporary);
-  }
   void register_equiv (tree dest, tree src, bool update) override;
 private:
   const_and_copies *m_copies;
   avail_exprs_stack *m_avails;
-  evrp_range_analyzer *m_evrp;
+  gimple_ranger *m_ranger;
 };
 
 void
-dom_jt_state::register_equiv (tree dest, tree src, bool update)
+dom_jt_state::register_equiv (tree dest, tree src, bool)
 {
   m_copies->record_const_or_copy (dest, src);
-
-  /* If requested, update the value range associated with DST, using
-     the range from SRC.  */
-  if (update)
-    {
-      /* Get new VR we can pass to push_value_range.  */
-      value_range_equiv *new_vr = m_evrp->allocate_value_range_equiv ();
-      new (new_vr) value_range_equiv ();
-
-      /* There are three cases to consider:
-
-	 First if SRC is an SSA_NAME, then we can copy the value range
-	 from SRC into NEW_VR.
-
-	 Second if SRC is an INTEGER_CST, then we can just set NEW_VR
-	 to a singleton range.  Note that even if SRC is a constant we
-	 need to set a suitable output range so that VR_UNDEFINED
-	 ranges do not leak through.
-
-	 Otherwise set NEW_VR to varying.  This may be overly
-	 conservative.  */
-      if (TREE_CODE (src) == SSA_NAME)
-	new_vr->deep_copy (m_evrp->get_value_range (src));
-      else if (TREE_CODE (src) == INTEGER_CST)
-	new_vr->set (src);
-      else
-	new_vr->set_varying (TREE_TYPE (src));
-
-      /* This is a temporary range for DST, so push it.  */
-      m_evrp->push_value_range (dest, new_vr);
-    }
 }
 
-class dom_jt_simplifier : public jt_simplifier
+class dom_jt_simplifier : public hybrid_jt_simplifier
 {
 public:
-  dom_jt_simplifier (vr_values *v, avail_exprs_stack *avails)
-    : m_vr_values (v), m_avails (avails) { }
+  dom_jt_simplifier (avail_exprs_stack *avails, gimple_ranger *ranger,
+		     path_range_query *query)
+    : hybrid_jt_simplifier (ranger, query), m_avails (avails) { }
 
 private:
   tree simplify (gimple *, gimple *, basic_block, jt_state *) override;
-  vr_values *m_vr_values;
   avail_exprs_stack *m_avails;
 };
 
 tree
 dom_jt_simplifier::simplify (gimple *stmt, gimple *within_stmt,
-			     basic_block, jt_state *)
+			     basic_block bb, jt_state *state)
 {
   /* First see if the conditional is in the hash table.  */
   tree cached_lhs =  m_avails->lookup_avail_expr (stmt, false, true);
   if (cached_lhs)
     return cached_lhs;
 
-  if (gcond *cond_stmt = dyn_cast <gcond *> (stmt))
-    {
-      simplify_using_ranges simplifier (m_vr_values);
-      return simplifier.vrp_evaluate_conditional (gimple_cond_code (cond_stmt),
-						  gimple_cond_lhs (cond_stmt),
-						  gimple_cond_rhs (cond_stmt),
-						  within_stmt);
-    }
-  if (gswitch *switch_stmt = dyn_cast <gswitch *> (stmt))
-    {
-      tree op = gimple_switch_index (switch_stmt);
-      if (TREE_CODE (op) != SSA_NAME)
-	return NULL_TREE;
+  /* Otherwise call the ranger if possible.  */
+  if (state)
+    return hybrid_jt_simplifier::simplify (stmt, within_stmt, bb, state);
 
-      const value_range_equiv *vr = m_vr_values->get_value_range (op);
-      return find_case_label_range (switch_stmt, vr);
-    }
-  if (gassign *assign_stmt = dyn_cast <gassign *> (stmt))
-    {
-      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)))
-	  && stmt_interesting_for_vrp (stmt))
-	{
-	  edge dummy_e;
-	  tree dummy_tree;
-	  value_range_equiv new_vr;
-	  m_vr_values->extract_range_from_stmt (stmt, &dummy_e, &dummy_tree,
-						&new_vr);
-	  tree singleton;
-	  if (new_vr.singleton_p (&singleton))
-	    return singleton;
-	}
-    }
   return NULL;
 }
 
@@ -724,12 +657,12 @@ public:
   dom_opt_dom_walker (cdi_direction direction,
 		      jump_threader *threader,
 		      jt_state *state,
-		      evrp_range_analyzer *analyzer,
+		      gimple_ranger *ranger,
 		      const_and_copies *const_and_copies,
 		      avail_exprs_stack *avail_exprs_stack)
     : dom_walker (direction, REACHABLE_BLOCKS)
     {
-      m_evrp_range_analyzer = analyzer;
+      m_ranger = ranger;
       m_state = state;
       m_dummy_cond = gimple_build_cond (NE_EXPR, integer_zero_node,
 					integer_zero_node, NULL, NULL);
@@ -756,11 +689,13 @@ private:
      value.  */
   edge optimize_stmt (basic_block, gimple_stmt_iterator *, bool *);
 
+  void set_global_ranges_from_unreachable_edges (basic_block);
 
   void test_for_singularity (gimple *, avail_exprs_stack *);
+  edge fold_cond (gcond *cond);
 
   jump_threader *m_threader;
-  evrp_range_analyzer *m_evrp_range_analyzer;
+  gimple_ranger *m_ranger;
   jt_state *m_state;
 };
 
@@ -857,18 +792,22 @@ pass_dominator::execute (function *fun)
     record_edge_info (bb);
 
   /* Recursively walk the dominator tree optimizing statements.  */
-  evrp_range_analyzer analyzer (true);
-  dom_jt_simplifier simplifier (&analyzer, avail_exprs_stack);
-  dom_jt_state state (const_and_copies, avail_exprs_stack, &analyzer);
+  gimple_ranger *ranger = enable_ranger (fun);
+  path_range_query path_query (/*resolve=*/true, ranger);
+  dom_jt_simplifier simplifier (avail_exprs_stack, ranger, &path_query);
+  dom_jt_state state (const_and_copies, avail_exprs_stack, ranger);
   jump_threader threader (&simplifier, &state);
   dom_opt_dom_walker walker (CDI_DOMINATORS,
 			     &threader,
 			     &state,
-			     &analyzer,
+			     ranger,
 			     const_and_copies,
 			     avail_exprs_stack);
   walker.walk (fun->cfg->x_entry_block_ptr);
 
+  ranger->export_global_ranges ();
+  disable_ranger (fun);
+
   /* Look for blocks where we cleared EDGE_EXECUTABLE on an outgoing
      edge.  When found, remove jump threads which contain any outgoing
      edge from the affected block.  */
@@ -1253,6 +1192,77 @@ record_equivalences_from_phis (basic_block bb)
     }
 }
 
+/* Return true if all uses of NAME are dominated by STMT or feed STMT
+   via a chain of single immediate uses.  */
+
+static bool
+all_uses_feed_or_dominated_by_stmt (tree name, gimple *stmt)
+{
+  use_operand_p use_p, use2_p;
+  imm_use_iterator iter;
+  basic_block stmt_bb = gimple_bb (stmt);
+
+  FOR_EACH_IMM_USE_FAST (use_p, iter, name)
+    {
+      gimple *use_stmt = USE_STMT (use_p), *use_stmt2;
+      if (use_stmt == stmt
+	  || is_gimple_debug (use_stmt)
+	  || (gimple_bb (use_stmt) != stmt_bb
+	      && dominated_by_p (CDI_DOMINATORS,
+				 gimple_bb (use_stmt), stmt_bb)))
+	continue;
+      while (use_stmt != stmt
+	     && is_gimple_assign (use_stmt)
+	     && TREE_CODE (gimple_assign_lhs (use_stmt)) == SSA_NAME
+	     && single_imm_use (gimple_assign_lhs (use_stmt),
+				&use2_p, &use_stmt2))
+	use_stmt = use_stmt2;
+      if (use_stmt != stmt)
+	return false;
+    }
+  return true;
+}
+
+/* Set global ranges that can be determined from the C->M edge:
+
+   <bb C>:
+   ...
+   if (something)
+     goto <bb N>;
+   else
+     goto <bb M>;
+   <bb N>:
+   __builtin_unreachable ();
+   <bb M>:
+*/
+
+void
+dom_opt_dom_walker::set_global_ranges_from_unreachable_edges (basic_block bb)
+{
+  edge pred_e = single_pred_edge_ignoring_loop_edges (bb, false);
+
+  if (!pred_e)
+    return;
+
+  gimple *stmt = last_stmt (pred_e->src);
+  tree name;
+  int_range_max r;
+  if (stmt
+      && gimple_code (stmt) == GIMPLE_COND
+      && (name = gimple_cond_lhs (stmt))
+      && TREE_CODE (name) == SSA_NAME
+      && irange::supports_type_p (TREE_TYPE (name))
+      && assert_unreachable_fallthru_edge_p (pred_e)
+      && all_uses_feed_or_dominated_by_stmt (name, stmt)
+      && m_ranger->range_on_edge (r, pred_e, name)
+      && !r.varying_p ()
+      && !r.undefined_p ())
+    {
+      update_global_range (r, name);
+      maybe_set_nonzero_bits (pred_e, name);
+    }
+}
+
 /* Record any equivalences created by the incoming edge to BB into
    CONST_AND_COPIES and AVAIL_EXPRS_STACK.  If BB has more than one
    incoming edge, then no equivalence is created.  */
@@ -1506,8 +1516,6 @@ dom_opt_dom_walker::before_dom_children (basic_block bb)
   if (dump_file && (dump_flags & TDF_DETAILS))
     fprintf (dump_file, "\n\nOptimizing block #%d\n\n", bb->index);
 
-  m_evrp_range_analyzer->enter (bb);
-
   /* Push a marker on the stacks of local information so that we know how
      far to unwind when we finalize this block.  */
   m_avail_exprs_stack->push_marker ();
@@ -1515,6 +1523,7 @@ dom_opt_dom_walker::before_dom_children (basic_block bb)
 
   record_equivalences_from_incoming_edge (bb, m_const_and_copies,
 					  m_avail_exprs_stack);
+  set_global_ranges_from_unreachable_edges (bb);
 
   /* PHI nodes can create equivalences too.  */
   record_equivalences_from_phis (bb);
@@ -1543,7 +1552,6 @@ dom_opt_dom_walker::before_dom_children (basic_block bb)
 	  continue;
 	}
 
-      m_state->record_ranges_from_stmt (gsi_stmt (gsi), false);
       bool removed_p = false;
       taken_edge = this->optimize_stmt (bb, &gsi, &removed_p);
       if (!removed_p)
@@ -1591,7 +1599,6 @@ dom_opt_dom_walker::after_dom_children (basic_block bb)
   m_threader->thread_outgoing_edges (bb);
   m_avail_exprs_stack->pop_to_marker ();
   m_const_and_copies->pop_to_marker ();
-  m_evrp_range_analyzer->leave (bb);
 }
 
 /* Search for redundant computations in STMT.  If any are found, then
@@ -1833,7 +1840,7 @@ cprop_operand (gimple *stmt, use_operand_p op_p, range_query *query)
   val = SSA_NAME_VALUE (op);
   if (!val)
     {
-      value_range r;
+      int_range<2> r;
       tree single;
       if (query->range_of_expr (r, op, stmt) && r.singleton_p (&single))
 	val = single;
@@ -2074,6 +2081,24 @@ reduce_vector_comparison_to_scalar_comparison (gimple *stmt)
     }
 }
 
+/* If possible, rewrite the conditional as TRUE or FALSE, and return
+   the taken edge.  Otherwise, return NULL.  */
+
+edge
+dom_opt_dom_walker::fold_cond (gcond *cond)
+{
+  simplify_using_ranges simplify (m_ranger);
+  if (simplify.fold_cond (cond))
+    {
+      basic_block bb = gimple_bb (cond);
+      if (gimple_cond_true_p (cond))
+	return find_taken_edge (bb, boolean_true_node);
+      if (gimple_cond_false_p (cond))
+	return find_taken_edge (bb, boolean_false_node);
+    }
+  return NULL;
+}
+
 /* Optimize the statement in block BB pointed to by iterator SI.
 
    We try to perform some simplistic global redundancy elimination and
@@ -2122,7 +2147,7 @@ dom_opt_dom_walker::optimize_stmt (basic_block bb, gimple_stmt_iterator *si,
   opt_stats.num_stmts++;
 
   /* Const/copy propagate into USES, VUSES and the RHS of VDEFs.  */
-  cprop_into_stmt (stmt, m_evrp_range_analyzer);
+  cprop_into_stmt (stmt, m_ranger);
 
   /* If the statement has been modified with constant replacements,
      fold its RHS before checking for redundant computations.  */
@@ -2219,17 +2244,9 @@ dom_opt_dom_walker::optimize_stmt (basic_block bb, gimple_stmt_iterator *si,
 		 IL because we've attached range information to new
 		 SSA_NAMES.  */
 	      update_stmt_if_modified (stmt);
-	      edge taken_edge = NULL;
-	      simplify_using_ranges simpl (m_evrp_range_analyzer);
-	      simpl.vrp_visit_cond_stmt (as_a <gcond *> (stmt), &taken_edge);
+	      edge taken_edge = fold_cond (as_a <gcond *> (stmt));
 	      if (taken_edge)
 		{
-		  if (taken_edge->flags & EDGE_TRUE_VALUE)
-		    gimple_cond_make_true (as_a <gcond *> (stmt));
-		  else if (taken_edge->flags & EDGE_FALSE_VALUE)
-		    gimple_cond_make_false (as_a <gcond *> (stmt));
-		  else
-		    gcc_unreachable ();
 		  gimple_set_modified (stmt, true);
 		  update_stmt (stmt);
 		  cfg_altered = true;
diff --git a/gcc/tree-ssa-threadedge.cc b/gcc/tree-ssa-threadedge.cc
index 4eb65ca7cac..50251af8fc0 100644
--- a/gcc/tree-ssa-threadedge.cc
+++ b/gcc/tree-ssa-threadedge.cc
@@ -1377,7 +1377,9 @@ jt_state::register_equivs_stmt (gimple *stmt, basic_block bb,
 		SET_USE (use_p, tmp);
 	    }
 
-	  cached_lhs = simplifier->simplify (stmt, stmt, bb, this);
+	  /* Do not pass state to avoid calling the ranger with the
+	     temporarily altered IL.  */
+	  cached_lhs = simplifier->simplify (stmt, stmt, bb, /*state=*/NULL);
 
 	  /* Restore the statement's original uses/defs.  */
 	  i = 0;
diff --git a/gcc/vr-values.h b/gcc/vr-values.h
index f29441747e2..db0aa838bfe 100644
--- a/gcc/vr-values.h
+++ b/gcc/vr-values.h
@@ -41,6 +41,7 @@ public:
   // ?? These should be cleaned, merged, and made private.
   tree vrp_evaluate_conditional (tree_code, tree, tree, gimple *);
   void vrp_visit_cond_stmt (gcond *, edge *);
+  bool fold_cond (gcond *);
   tree vrp_evaluate_conditional_warnv_with_ops (gimple *stmt, enum tree_code,
 						tree, tree, bool,
 						bool *, bool *);
@@ -53,7 +54,6 @@ private:
   bool simplify_bit_ops_using_ranges (gimple_stmt_iterator *, gimple *);
   bool simplify_min_or_max_using_ranges (gimple_stmt_iterator *, gimple *);
   bool simplify_cond_using_ranges_1 (gcond *);
-  bool fold_cond (gcond *);
   bool simplify_switch_using_ranges (gswitch *);
   bool simplify_float_conversion_using_ranges (gimple_stmt_iterator *,
 					       gimple *);
