commit dc6758f03effbf7d6946d8c314576c7a6c0003af
Author: Andrew MacLeod <amacleod@redhat.com>
Date:   Tue May 18 20:33:09 2021 -0400

    Split gimple range folding with ranges into a stand alone class.
    
    Introduces fold_using_range which folds any kind of gimple statement by
    querying argument ranges thru a generic range_query.
    This pulls all the statement processing into a client neutral location.
    
            * gimple-range.cc (fur_source::get_operand): New.
            (gimple_range_fold): Delete.
            (fold_using_range::fold_stmt): Move from gimple_ranger::calc_stmt.
            (fold_using_range::range_of_range_op): Move from gimple_ranger.
            (fold_using_range::range_of_address): Ditto.
            (fold_using_range::range_of_phi): Ditto.
            (fold_using_range::range_of_call): Ditto.
            (fold_using_range::range_of_builtin_ubsan_call): Move from
            range_of_builtin_ubsan_call.
            (fold_using_range::range_of_builtin_call): Move from
            range_of_builtin_call.
            (gimple_ranger::range_of_builtin_call): Delete.
            (fold_using_range::range_of_cond_expr): Move from gimple_ranger.
            (gimple_ranger::fold_range_internal): New.
            (gimple_ranger::range_of_stmt): Use new fold_using_range API.
            (fold_using_range::range_of_ssa_name_with_loop_info): Move from
            gimple_ranger.  Improve ranges of SSA_NAMES when possible.
            * gimple-range.h (gimple_ranger): Remove various range_of routines.
            (class fur_source): New.
            (class fold_using_range): New.
            (fur_source::fur_source): New.
            (fold_range): New.
            * vr-values.c (vr_values::extract_range_basic): Use fold_using_range
            instead of range_of_builtin_call.

diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 710bc7f9632..06e9804494b 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -47,6 +47,31 @@ along with GCC; see the file COPYING3.  If not see
 #include "vr-values.h"
 #include "gimple-range.h"
 
+// Evaluate expression EXPR using the source information the class was
+// instantiated with.  Place the result in R, and return TRUE.  If a range
+// cannot be calcluated, return FALSE.
+
+bool
+fur_source::get_operand (irange &r, tree expr)
+{
+  if (!gimple_range_ssa_p (expr))
+    return get_tree_range (r, expr);
+
+  // If no query engine is present, simply get the global value.
+  if (!m_query)
+    {
+       r = gimple_range_global (expr);
+       return true;
+    }
+
+  // First look for a stmt.
+  if (m_stmt)
+    return m_query->range_of_expr (r, expr, m_stmt);
+
+  // Finally must be on an edge.
+  return m_query->range_on_edge (r, m_edge, expr);
+}
+
 
 // Adjust the range for a pointer difference where the operands came
 // from a memchr.
@@ -193,41 +218,9 @@ get_tree_range (irange &r, tree expr)
   return true;
 }
 
-// Fold this unary statement using R1 as operand1's range, returning
-// the result in RES.  Return false if the operation fails.
-
-bool
-gimple_range_fold (irange &res, const gimple *stmt, const irange &r1)
-{
-  gcc_checking_assert (gimple_range_handler (stmt));
-
-  tree type = gimple_expr_type (stmt);
-  // Unary SSA operations require the LHS type as the second range.
-  int_range<2> r2 (type);
-
-  return gimple_range_fold (res, stmt, r1, r2);
-}
-
-// Fold this binary statement using R1 and R2 as the operands ranges,
-// returning the result in RES.  Return false if the operation fails.
-
-bool
-gimple_range_fold (irange &res, const gimple *stmt,
-		   const irange &r1, const irange &r2)
-{
-  gcc_checking_assert (gimple_range_handler (stmt));
-
-  gimple_range_handler (stmt)->fold_range (res, gimple_expr_type (stmt),
-					   r1, r2);
-
-  // If there are any gimple lookups, do those now.
-  gimple_range_adjustment (res, stmt);
-  return true;
-}
-
 // Return the base of the RHS of an assignment.
 
-tree
+static tree
 gimple_range_base_of_assignment (const gimple *stmt)
 {
   gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN);
@@ -364,20 +357,29 @@ gimple_range_calc_op2 (irange &r, const gimple *stmt,
 // be calculated, return false.
 
 bool
-gimple_ranger::calc_stmt (irange &r, gimple *s, tree name)
+fold_using_range::fold_stmt (irange &r, gimple *s, fur_source &src, tree name)
 {
   bool res = false;
-  // If name is specified, make sure it is an LHS of S.
-  gcc_checking_assert (name ? SSA_NAME_DEF_STMT (name) == s : true);
+  // If name and S are specified, make sure it is an LHS of S.
+  gcc_checking_assert (!name || !gimple_get_lhs (s) ||
+		       name == gimple_get_lhs (s));
+
+  if (!name)
+    name = gimple_get_lhs (s);
+
+  // Process addresses.
+  if (gimple_code (s) == GIMPLE_ASSIGN
+      && gimple_assign_rhs_code (s) == ADDR_EXPR)
+    return range_of_address (r, s, src);
 
   if (gimple_range_handler (s))
-    res = range_of_range_op (r, s);
+    res = range_of_range_op (r, s, src);
   else if (is_a<gphi *>(s))
-    res = range_of_phi (r, as_a<gphi *> (s));
+    res = range_of_phi (r, as_a<gphi *> (s), src);
   else if (is_a<gcall *>(s))
-    res = range_of_call (r, as_a<gcall *> (s));
+    res = range_of_call (r, as_a<gcall *> (s), src);
   else if (is_a<gassign *> (s) && gimple_assign_rhs_code (s) == COND_EXPR)
-    res = range_of_cond_expr (r, as_a<gassign *> (s));
+    res = range_of_cond_expr (r, as_a<gassign *> (s), src);
 
   if (!res)
     {
@@ -414,36 +416,45 @@ gimple_ranger::calc_stmt (irange &r, gimple *s, tree name)
 // If a range cannot be calculated, return false.
 
 bool
-gimple_ranger::range_of_range_op (irange &r, gimple *s)
+fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
 {
   int_range_max range1, range2;
-  tree lhs = gimple_get_lhs (s);
   tree type = gimple_expr_type (s);
+  range_operator *handler = gimple_range_handler (s);
+  gcc_checking_assert (handler);
   gcc_checking_assert (irange::supports_type_p (type));
 
+  tree lhs = gimple_get_lhs (s);
   tree op1 = gimple_range_operand1 (s);
   tree op2 = gimple_range_operand2 (s);
 
-  if (lhs)
-    {
-      // Register potential dependencies for stale value tracking.
-      m_cache.register_dependency (lhs, op1);
-      m_cache.register_dependency (lhs, op2);
-    }
-
-  if (gimple_code (s) == GIMPLE_ASSIGN
-      && gimple_assign_rhs_code (s) == ADDR_EXPR)
-    return range_of_address (r, s);
-
-  if (range_of_expr (range1, op1, s))
+  if (src.get_operand (range1, op1))
     {
       if (!op2)
-	return gimple_range_fold (r, s, range1);
-
-      if (range_of_expr (range2, op2, s))
-	return gimple_range_fold (r, s, range1, range2);
+	{
+	  // Fold range, and register any dependency if available.
+	  int_range<2> r2 (type);
+	  handler->fold_range (r, type, range1, r2);
+	  if (lhs && src.m_cache)
+	    src.m_cache->register_dependency (lhs, op1);
+	}
+      else if (src.get_operand (range2, op2))
+	{
+	  // Fold range, and register any dependency if available.
+	  handler->fold_range (r, type, range1, range2);
+	  if (lhs && src.m_cache)
+	    {
+	      src.m_cache->register_dependency (lhs, op1);
+	      src.m_cache->register_dependency (lhs, op2);
+	    }
+	}
+      else
+	r.set_varying (type);
     }
-  r.set_varying (type);
+  else
+    r.set_varying (type);
+  // Make certain range-op adjustments that aren't handled any other way.
+  gimple_range_adjustment (r, s);
   return true;
 }
 
@@ -452,7 +463,7 @@ gimple_ranger::range_of_range_op (irange &r, gimple *s)
 // If a range cannot be calculated, set it to VARYING and return true.
 
 bool
-gimple_ranger::range_of_address (irange &r, gimple *stmt)
+fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src)
 {
   gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN);
   gcc_checking_assert (gimple_assign_rhs_code (stmt) == ADDR_EXPR);
@@ -473,8 +484,11 @@ gimple_ranger::range_of_address (irange &r, gimple *stmt)
       && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
     {
       tree ssa = TREE_OPERAND (base, 0);
+      tree lhs = gimple_get_lhs (stmt);
+      if (src.m_cache && lhs && gimple_range_ssa_p (ssa))
+	src.m_cache->register_dependency (lhs, ssa);
       gcc_checking_assert (irange::supports_type_p (TREE_TYPE (ssa)));
-      range_of_expr (r, ssa, stmt);
+      src.get_operand (r, ssa);
       range_cast (r, TREE_TYPE (gimple_assign_rhs1 (stmt)));
 
       poly_offset_int off = 0;
@@ -531,7 +545,7 @@ gimple_ranger::range_of_address (irange &r, gimple *stmt)
 // If a range cannot be calculated, return false.
 
 bool
-gimple_ranger::range_of_phi (irange &r, gphi *phi)
+fold_using_range::range_of_phi (irange &r, gphi *phi, fur_source &src)
 {
   tree phi_def = gimple_phi_result (phi);
   tree type = TREE_TYPE (phi_def);
@@ -549,9 +563,19 @@ gimple_ranger::range_of_phi (irange &r, gphi *phi)
       edge e = gimple_phi_arg_edge (phi, x);
 
       // Register potential dependencies for stale value tracking.
-      m_cache.register_dependency (phi_def, arg);
-
-      range_on_edge (arg_range, e, arg);
+      if (src.m_cache && gimple_range_ssa_p (arg))
+	src.m_cache->register_dependency (phi_def, arg);
+
+      // Get the range of the argument on its edge.
+      fur_source e_src (src.m_query, e);
+      e_src.get_operand (arg_range, arg);
+      // If we're recomputing the argument elsewhere, try to refine it.
+      if (src.m_stmt != phi)
+	{
+	  int_range_max tmp;
+	  e_src.get_operand (tmp, arg);
+	  arg_range.intersect (tmp);
+	}
       r.union_ (arg_range);
       // Once the value reaches varying, stop looking.
       if (r.varying_p ())
@@ -565,7 +589,7 @@ gimple_ranger::range_of_phi (irange &r, gphi *phi)
       class loop *l = loop_containing_stmt (phi);
       if (l && loop_outer (l))
         {
-	  range_of_ssa_name_with_loop_info (loop_range, phi_def, l, phi);
+	  range_of_ssa_name_with_loop_info (loop_range, phi_def, l, phi, src);
 	  if (!loop_range.varying_p ())
 	    {
 	      if (dump_file && (dump_flags & TDF_DETAILS))
@@ -590,7 +614,7 @@ gimple_ranger::range_of_phi (irange &r, gphi *phi)
 // If a range cannot be calculated, return false.
 
 bool
-gimple_ranger::range_of_call (irange &r, gcall *call)
+fold_using_range::range_of_call (irange &r, gcall *call, fur_source &src)
 {
   tree type = gimple_call_return_type (call);
   tree lhs = gimple_call_lhs (call);
@@ -599,7 +623,7 @@ gimple_ranger::range_of_call (irange &r, gcall *call)
   if (!irange::supports_type_p (type))
     return false;
 
-  if (range_of_builtin_call (r, call))
+  if (range_of_builtin_call (r, call, src))
     ;
   else if (gimple_stmt_nonnegative_warnv_p (call, &strict_overflow_p))
     r.set (build_int_cst (type, 0), TYPE_MAX_VALUE (type));
@@ -623,9 +647,9 @@ gimple_ranger::range_of_call (irange &r, gcall *call)
 // CODE is the type of ubsan call (PLUS_EXPR, MINUS_EXPR or
 // MULT_EXPR).
 
-static void
-range_of_builtin_ubsan_call (range_query &query, irange &r, gcall *call,
-			     tree_code code)
+void
+fold_using_range::range_of_builtin_ubsan_call (irange &r, gcall *call,
+					       tree_code code, fur_source &src)
 {
   gcc_checking_assert (code == PLUS_EXPR || code == MINUS_EXPR
 		       || code == MULT_EXPR);
@@ -635,8 +659,8 @@ range_of_builtin_ubsan_call (range_query &query, irange &r, gcall *call,
   int_range_max ir0, ir1;
   tree arg0 = gimple_call_arg (call, 0);
   tree arg1 = gimple_call_arg (call, 1);
-  query.range_of_expr (ir0, arg0, call);
-  query.range_of_expr (ir1, arg1, call);
+  src.get_operand (ir0, arg0);
+  src.get_operand (ir1, arg1);
 
   bool saved_flag_wrapv = flag_wrapv;
   // Pretend the arithmetic is wrapping.  If there is any overflow,
@@ -656,7 +680,8 @@ range_of_builtin_ubsan_call (range_query &query, irange &r, gcall *call,
 // TRUE.  Otherwise return FALSE.
 
 bool
-range_of_builtin_call (range_query &query, irange &r, gcall *call)
+fold_using_range::range_of_builtin_call (irange &r, gcall *call,
+					 fur_source &src)
 {
   combined_fn func = gimple_call_combined_fn (call);
   if (func == CFN_LAST)
@@ -677,7 +702,7 @@ range_of_builtin_call (range_query &query, irange &r, gcall *call)
 	  return true;
 	}
       arg = gimple_call_arg (call, 0);
-      if (query.range_of_expr (r, arg, call) && r.singleton_p ())
+      if (src.get_operand (r, arg) && r.singleton_p ())
 	{
 	  r.set (build_one_cst (type), build_one_cst (type));
 	  return true;
@@ -691,7 +716,7 @@ range_of_builtin_call (range_query &query, irange &r, gcall *call)
       prec = TYPE_PRECISION (TREE_TYPE (arg));
       mini = 0;
       maxi = prec;
-      query.range_of_expr (r, arg, call);
+      src.get_operand (r, arg);
       // If arg is non-zero, then ffs or popcount are non-zero.
       if (!range_includes_zero_p (&r))
 	mini = 1;
@@ -735,7 +760,7 @@ range_of_builtin_call (range_query &query, irange &r, gcall *call)
 	    }
 	}
 
-      query.range_of_expr (r, arg, call);
+      src.get_operand (r, arg);
       // From clz of minimum we can compute result maximum.
       if (r.constant_p () && !r.varying_p ())
 	{
@@ -800,7 +825,7 @@ range_of_builtin_call (range_query &query, irange &r, gcall *call)
 		mini = -2;
 	    }
 	}
-      query.range_of_expr (r, arg, call);
+      src.get_operand (r, arg);
       if (!r.undefined_p ())
 	{
 	  if (r.lower_bound () != 0)
@@ -838,13 +863,13 @@ range_of_builtin_call (range_query &query, irange &r, gcall *call)
       r.set (build_int_cst (type, 0), build_int_cst (type, prec - 1));
       return true;
     case CFN_UBSAN_CHECK_ADD:
-      range_of_builtin_ubsan_call (query, r, call, PLUS_EXPR);
+      range_of_builtin_ubsan_call (r, call, PLUS_EXPR, src);
       return true;
     case CFN_UBSAN_CHECK_SUB:
-      range_of_builtin_ubsan_call (query, r, call, MINUS_EXPR);
+      range_of_builtin_ubsan_call (r, call, MINUS_EXPR, src);
       return true;
     case CFN_UBSAN_CHECK_MUL:
-      range_of_builtin_ubsan_call (query, r, call, MULT_EXPR);
+      range_of_builtin_ubsan_call (r, call, MULT_EXPR, src);
       return true;
 
     case CFN_GOACC_DIM_SIZE:
@@ -894,17 +919,11 @@ range_of_builtin_call (range_query &query, irange &r, gcall *call)
 }
 
 
-bool
-gimple_ranger::range_of_builtin_call (irange &r, gcall *call)
-{
-  return ::range_of_builtin_call (*this, r, call);
-}
-
 // Calculate a range for COND_EXPR statement S and return it in R.
 // If a range cannot be calculated, return false.
 
 bool
-gimple_ranger::range_of_cond_expr  (irange &r, gassign *s)
+fold_using_range::range_of_cond_expr  (irange &r, gassign *s, fur_source &src)
 {
   int_range_max cond_range, range1, range2;
   tree cond = gimple_assign_rhs1 (s);
@@ -917,9 +936,9 @@ gimple_ranger::range_of_cond_expr  (irange &r, gassign *s)
   if (!irange::supports_type_p (TREE_TYPE (op1)))
     return false;
 
-  range_of_expr (cond_range, cond, s);
-  range_of_expr (range1, op1, s);
-  range_of_expr (range2, op2, s);
+  src.get_operand (cond_range, cond);
+  src.get_operand (range1, op1);
+  src.get_operand (range2, op2);
 
   // If the condition is known, choose the appropriate expression.
   if (cond_range.singleton_p ())
@@ -1047,6 +1066,16 @@ gimple_ranger::range_on_edge (irange &r, edge e, tree name)
   return true;
 }
 
+// fold_range wrapper for range_of_stmt to use as an internal client.
+
+bool
+gimple_ranger::fold_range_internal (irange &r, gimple *s, tree name)
+{
+  fold_using_range f;
+  fur_source src (this, &m_cache, NULL, s);
+  return f.fold_stmt (r, s, src, name);
+}
+
 // Calculate a range for statement S and return it in R.  If NAME is
 // provided it represents the SSA_NAME on the LHS of the statement.
 // It is only required if there is more than one lhs/output.  Check
@@ -1063,7 +1092,7 @@ gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name)
 
   // If no name, simply call the base routine.
   if (!name)
-    return calc_stmt (r, s, NULL_TREE);
+    return fold_range_internal (r, s, NULL_TREE);
 
   if (!gimple_range_ssa_p (name))
     return false;
@@ -1074,7 +1103,7 @@ gimple_ranger::range_of_stmt (irange &r, gimple *s, tree name)
 
   // Otherwise calculate a new value.
   int_range_max tmp;
-  calc_stmt (tmp, s, name);
+  fold_range_internal (tmp, s, name);
 
   // Combine the new value with the old value.  This is required because
   // the way value propagation works, when the IL changes on the fly we
@@ -1216,20 +1245,32 @@ gimple_ranger::dump (FILE *f)
 // If SCEV has any information about phi node NAME, return it as a range in R.
 
 void
-gimple_ranger::range_of_ssa_name_with_loop_info (irange &r, tree name,
-						 class loop *l, gphi *phi)
+fold_using_range::range_of_ssa_name_with_loop_info (irange &r, tree name,
+						    class loop *l, gphi *phi,
+						    fur_source &src)
 {
   gcc_checking_assert (TREE_CODE (name) == SSA_NAME);
   tree min, max, type = TREE_TYPE (name);
-  if (bounds_of_var_in_loop (&min, &max, this, l, phi, name))
+  if (bounds_of_var_in_loop (&min, &max, src.m_query, l, phi, name))
     {
-      // ?? We could do better here.  Since MIN/MAX can only be an
-      // SSA, SSA +- INTEGER_CST, or INTEGER_CST, we could easily call
-      // the ranger and solve anything not an integer.
       if (TREE_CODE (min) != INTEGER_CST)
-	min = vrp_val_min (type);
+	{
+	  if (src.m_query
+	      && src.m_query->range_of_expr (r, min, phi)
+	      && !r.undefined_p ())
+	    min = wide_int_to_tree (type, r.lower_bound ());
+	  else
+	    min = vrp_val_min (type);
+	}
       if (TREE_CODE (max) != INTEGER_CST)
-	max = vrp_val_max (type);
+	{
+	  if (src.m_query
+	      && src.m_query->range_of_expr (r, max, phi)
+	      && !r.undefined_p ())
+	    max = wide_int_to_tree (type, r.upper_bound ());
+	  else
+	    max = vrp_val_max (type);
+	}
       r.set (min, max);
     }
   else
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index f33156181bf..53205066ab4 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -30,6 +30,18 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-range-cache.h"
 #include "value-query.h"
 
+// This file is the main include point for gimple ranges.
+// There are two fold_range routines of interest:
+//   bool fold_range (irange &r, gimple *s, range_query *q)
+//   bool fold_range (irange &r, gimple *s, edge on_edge, range_query *q)
+// These routines will fold stmt S into the result irange R.
+// Any ssa_names on the stmt will be calculated using the range_query
+// parameter via a call to range_of_expr.
+// If no range_query is provided, current global range info will be used.
+// The second variation specifies an edge, and stmt S is recalculated as if
+// it appeared on that edge.
+
+
 // This is the basic range generator interface.
 //
 // This base class provides all the API entry points, but only provides
@@ -55,32 +67,116 @@ public:
   void export_global_ranges ();
   void dump (FILE *f);
 protected:
-  bool calc_stmt (irange &r, gimple *s, tree name = NULL_TREE);
-  bool range_of_range_op (irange &r, gimple *s);
-  bool range_of_call (irange &r, gcall *call);
-  bool range_of_cond_expr (irange &r, gassign* cond);
+  bool fold_range_internal (irange &r, gimple *s, tree name);
   ranger_cache m_cache;
-private:
-  bool range_of_phi (irange &r, gphi *phi);
-  bool range_of_address (irange &r, gimple *s);
-  bool range_of_builtin_call (irange &r, gcall *call);
-  bool range_with_loop_info (irange &r, tree name);
-  void range_of_ssa_name_with_loop_info (irange &, tree, class loop *,
-					 gphi *);
 };
 
-// Calculate a basic range for a tree expression.
+// Source of an operand for fold_using_range.
+// It can specify a stmt or and edge, or thru an internal API which uses
+// the ranger cache.
+// Its primary function is to retreive an operand from the source via a
+// call thru the range_query object.
+
+class fur_source
+{
+  friend class fold_using_range;
+public:
+  inline fur_source (range_query *q, edge e);
+  inline fur_source (range_query *q, gimple *s);
+  inline fur_source (range_query *q, class ranger_cache *g, edge e, gimple *s);
+  bool get_operand (irange &r, tree expr);
+protected:
+  ranger_cache *m_cache;
+  range_query *m_query;
+  edge m_edge;
+  gimple *m_stmt;
+};
+
+
+// This class uses ranges to fold a gimple statement producinf a range for
+// the LHS.  The source of all operands is supplied via the fur_source class
+// which provides a range_query as well as a source location and any other
+// required information.
+
+class fold_using_range
+{
+public:
+  bool fold_stmt (irange &r, gimple *s, class fur_source &src,
+		  tree name = NULL_TREE);
+protected:
+  bool range_of_range_op (irange &r, gimple *s, fur_source &src);
+  bool range_of_call (irange &r, gcall *call, fur_source &src);
+  bool range_of_cond_expr (irange &r, gassign* cond, fur_source &src);
+  bool range_of_address (irange &r, gimple *s, fur_source &src);
+  bool range_of_builtin_call (irange &r, gcall *call, fur_source &src);
+  void range_of_builtin_ubsan_call (irange &r, gcall *call, tree_code code,
+				    fur_source &src);
+  bool range_of_phi (irange &r, gphi *phi, fur_source &src);
+  void range_of_ssa_name_with_loop_info (irange &, tree, class loop *, gphi *,
+					 fur_source &src);
+};
+
+
+// Create a source for a query on an edge.
+
+inline
+fur_source::fur_source (range_query *q, edge e)
+{
+  m_query = q;
+  m_cache = NULL;
+  m_edge = e;
+  m_stmt = NULL;
+}
+
+// Create a source for a query at a statement.
+
+inline
+fur_source::fur_source (range_query *q, gimple *s)
+{
+  m_query = q;
+  m_cache = NULL;
+  m_edge = NULL;
+  m_stmt = s;
+}
+
+// Create a source for Ranger.  THis can recalculate from a different location
+// and can also set the dependency information as appropriate when invoked.
+
+inline
+fur_source::fur_source (range_query *q, ranger_cache *g, edge e, gimple *s)
+{
+  m_query = q;
+  m_cache = g;
+  m_edge = e;
+  m_stmt = s;
+}
+
+// Fold stmt S into range R using range query Q.
+
+inline bool
+fold_range (irange &r, gimple *s, range_query *q = NULL)
+{
+  fold_using_range f;
+  fur_source src (q, s);
+  return f.fold_stmt (r, s, src);
+}
+
+// Recalculate stmt S into R using range query Q as if it were on edge ON_EDGE.
+
+inline bool
+fold_range (irange &r, gimple *s, edge on_edge, range_query *q = NULL)
+{
+  fold_using_range f;
+  fur_source src (q, on_edge);
+  return f.fold_stmt (r, s, src);
+}
+
+// Calculate a basic range for a tree node expression.
 extern bool get_tree_range (irange &r, tree expr);
 
 // These routines provide a GIMPLE interface to the range-ops code.
 extern tree gimple_range_operand1 (const gimple *s);
 extern tree gimple_range_operand2 (const gimple *s);
-extern tree gimple_range_base_of_assignment (const gimple *s);
-extern bool gimple_range_fold (irange &res, const gimple *s,
-			       const irange &r1);
-extern bool gimple_range_fold (irange &res, const gimple *s,
-			       const irange &r1,
-			       const irange &r2);
 extern bool gimple_range_calc_op1 (irange &r, const gimple *s,
 				   const irange &lhs_range);
 extern bool gimple_range_calc_op1 (irange &r, const gimple *s,
@@ -199,7 +295,4 @@ private:
 // Flag to enable debugging the various internal Caches.
 #define DEBUG_RANGE_CACHE (dump_file && (param_evrp_mode & EVRP_MODE_DEBUG))
 
-// Temporary external interface to share with vr_values.
-bool range_of_builtin_call (range_query &query, irange &r, gcall *call);
-
 #endif // GCC_GIMPLE_RANGE_STMT_H
diff --git a/gcc/vr-values.c b/gcc/vr-values.c
index b1bf53af9e0..02bc0db9088 100644
--- a/gcc/vr-values.c
+++ b/gcc/vr-values.c
@@ -1229,7 +1229,7 @@ vr_values::extract_range_basic (value_range_equiv *vr, gimple *stmt)
 	    return;
 	  break;
 	default:
-	  if (range_of_builtin_call (*this, *vr, as_a<gcall *> (stmt)))
+	  if (fold_range (*vr, stmt, this))
 	    {
 	      /* The original code nuked equivalences every time a
 		 range was found, so do the same here.  */
