commit 87f9ac937d6cfd81cbbe0a43518ba10781888d7c
Author: Andrew MacLeod <amacleod@redhat.com>
Date:   Tue Jun 8 15:43:03 2021 -0400

    Virtualize fur_source and turn it into a proper API.
    
    No more accessing the local info.  Also add fur_source/fold_stmt where ranges
    are provided via being specified, or a vector to replace gimple_fold_range.
    
            * gimple-range-gori.cc (gori_compute::outgoing_edge_range_p): Use a
            fur_stmt source record.
            * gimple-range.cc (fur_source::get_operand): Generic range query.
            (fur_source::get_phi_operand): New.
            (fur_source::register_dependency): New.
            (fur_source::query): New.
            (class fur_edge): New.  Edge source for operands.
            (fur_edge::fur_edge): New.
            (fur_edge::get_operand): New.
            (fur_edge::get_phi_operand): New.
            (fur_edge::query): New.
            (fur_stmt::fur_stmt): New.
            (fur_stmt::get_operand): New.
            (fur_stmt::get_phi_operand): New.
            (fur_stmt::query): New.
            (class fur_depend): New.  Statement source and process dependencies.
            (fur_depend::fur_depend): New.
            (fur_depend::register_dependency): New.
            (class fur_list): New.  List source for operands.
            (fur_list::fur_list): New.
            (fur_list::get_operand): New.
            (fur_list::get_phi_operand): New.
            (fold_range): New.  Instantiate appropriate fur_source class and fold.
            (fold_using_range::range_of_range_op): Use new API.
            (fold_using_range::range_of_address): Ditto.
            (fold_using_range::range_of_phi): Ditto.
            (imple_ranger::fold_range_internal): Use fur_depend class.
            (fold_using_range::range_of_ssa_name_with_loop_info): Use new API.
            * gimple-range.h (class fur_source): Now a base class.
            (class fur_stmt): New.
            (fold_range): New prototypes.
            (fur_source::fur_source): Delete.

diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index 2c5360690db..09dcd694319 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -1008,7 +1008,7 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name,
   if (!stmt)
     return false;
 
-  fur_source src (&q, NULL, e, stmt);
+  fur_stmt src (stmt, &q);
 
   // If NAME can be calculated on the edge, use that.
   if (is_export_p (name, e->src))
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index db8419bc4c6..b534b8e0a2c 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -49,19 +49,284 @@ along with GCC; see the file COPYING3.  If not see
 
 // 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.
+// cannot be calculated, return FALSE.
 
 bool
 fur_source::get_operand (irange &r, tree expr)
 {
-  // First look for a stmt.
-  if (m_stmt)
-    return m_query->range_of_expr (r, expr, m_stmt);
+  return get_range_query (cfun)->range_of_expr (r, expr);
+}
+
+// Evaluate EXPR for this stmt as a PHI argument on edge E.  Use the current
+// range_query to get the range on the edge.
+
+bool
+fur_source::get_phi_operand (irange &r, tree expr, edge e)
+{
+  return get_range_query (cfun)->range_on_edge (r, e, expr);
+}
+
+// Default is to not register any dependencies from fold_using_range.
+
+void
+fur_source::register_dependency (tree lhs ATTRIBUTE_UNUSED,
+				 tree rhs ATTRIBUTE_UNUSED)
+{
+}
+
+// Default object is the current range query.
+
+range_query *
+fur_source::query ()
+{
+  return get_range_query (cfun);
+}
+
+// This version of fur_source will pick a range up off an edge.
 
-  // Finally must be on an edge.
+class fur_edge : public fur_source
+{
+public:
+  fur_edge (edge e, range_query *q = NULL);
+  virtual bool get_operand (irange &r, tree expr) OVERRIDE;
+  virtual bool get_phi_operand (irange &r, tree expr, edge e) OVERRIDE;
+  virtual range_query *query () OVERRIDE;
+private:
+  range_query *m_query;
+  edge m_edge;
+};
+
+// Instantiate an edge based fur_source.
+
+inline
+fur_edge::fur_edge (edge e, range_query *q)
+{
+  m_edge = e;
+  if (q)
+    m_query = q;
+  else
+    m_query = get_range_query (cfun);
+}
+
+// Get the value of EXPR on edge m_edge.
+
+bool
+fur_edge::get_operand (irange &r, tree expr)
+{
   return m_query->range_on_edge (r, m_edge, expr);
 }
 
+// Evaluate EXPR for this stmt as a PHI argument on edge E.  Use the current
+// range_query to get the range on the edge.
+
+bool
+fur_edge::get_phi_operand (irange &r, tree expr, edge e)
+{
+  // edge to edge recalculations not supoprted yet, until we sort it out.
+  gcc_checking_assert (e == m_edge);
+  return m_query->range_on_edge (r, e, expr);
+}
+
+// Return the current range_query object.
+
+range_query *
+fur_edge::query ()
+{
+  return m_query;
+}
+
+
+// Instantiate a stmt based fur_source.
+
+
+fur_stmt::fur_stmt (gimple *s, range_query *q)
+{
+  m_stmt= s;
+  if (q)
+    m_query = q;
+  else
+    m_query = get_global_range_query ();
+}
+
+// Retirenve range of EXPR as it occurs as a use on stmt M_STMT.
+
+bool
+fur_stmt::get_operand (irange &r, tree expr)
+{
+  return m_query->range_of_expr (r, expr, m_stmt);
+}
+
+// Evaluate EXPR for this stmt as a PHI argument on edge E.  Use the current
+// range_query to get the range on the edge.
+
+bool
+fur_stmt::get_phi_operand (irange &r, tree expr, edge e)
+{
+  // Pick up the range of expr from edge E.
+  fur_edge e_src (e, m_query);
+  return e_src.get_operand (r, expr);
+}
+
+// Return the current range_query object.
+
+range_query *
+fur_stmt::query ()
+{
+  return m_query;
+}
+
+// This version of fur_source will pick a range from a stmt, and register
+// also dependencies via a gori_compute object.  This is mostly an internal API.
+
+class fur_depend : public fur_stmt
+{
+public:
+  fur_depend (gimple *s, gori_compute *gori, range_query *q = NULL);
+  virtual void register_dependency (tree lhs, tree rhs) OVERRIDE;
+private:
+  gori_compute *m_gori;
+};
+
+// Instantiate a stmt based fur_source witrh a GORI object
+inline
+fur_depend::fur_depend (gimple *s, gori_compute *gori, range_query *q)
+							      : fur_stmt (s, q)
+{
+  gcc_checking_assert (gori);
+  m_gori = gori;
+}
+
+
+// find and add any dependnecy between LHS and RHS
+
+void
+fur_depend::register_dependency (tree lhs, tree rhs)
+{
+  m_gori->register_dependency (lhs, rhs);
+}
+
+
+// This version of fur_source will pick a range up from a list of ranges
+// supplied by the caller.
+
+class fur_list : public fur_source
+{
+public:
+  fur_list (irange &r1);
+  fur_list (irange &r1, irange &r2);
+  fur_list (unsigned num, irange *list);
+  virtual bool get_operand (irange &r, tree expr) OVERRIDE;
+  virtual bool get_phi_operand (irange &r, tree expr, edge e) OVERRIDE;
+private:
+  int_range_max m_local[2];
+  irange *m_list;
+  unsigned m_index;
+  unsigned m_limit;
+};
+
+// One range supplied for unary operations.
+
+fur_list::fur_list (irange &r1)
+{
+  m_list = m_local;
+  m_index = 0;
+  m_limit = 1;
+  m_local[0] = r1;
+}
+
+// Two ranges supplied for binary operations.
+
+fur_list::fur_list (irange &r1, irange &r2)
+{
+  m_list = m_local;
+  m_index = 0;
+  m_limit = 2;
+  m_local[0] = r1;
+  m_local[0] = r2;
+}
+
+// Arbitrary number of ranges in a vector.
+
+fur_list::fur_list (unsigned num, irange *list)
+{
+  m_list = list;
+  m_index = 0;
+  m_limit = num;
+}
+
+// Get the next operand from the vector, ensure types are compatible,
+
+bool
+fur_list::get_operand (irange &r, tree expr)
+{
+  if (m_index >= m_limit)
+    return get_range_query (cfun)->range_of_expr (r, expr);
+  r = m_list[m_index++];
+  gcc_checking_assert (range_compatible_p (TREE_TYPE (expr), r.type ()));
+  return true;
+}
+
+// This will simply pick the next operand from the vector.
+bool
+fur_list::get_phi_operand (irange &r, tree expr, edge e ATTRIBUTE_UNUSED)
+{
+  return get_operand (r, expr);
+}
+
+// Fold stmt S into range R using R1 as the first operand.
+
+bool
+fold_range (irange &r, gimple *s, irange &r1)
+{
+  fold_using_range f;
+  fur_list src (r1);
+  return f.fold_stmt (r, s, src);
+}
+
+// Fold stmt S into range R using R1  and R2 as the first two operands.
+
+bool
+fold_range (irange &r, gimple *s, irange &r1, irange &r2)
+{
+  fold_using_range f;
+  fur_list src (r1, r2);
+  return f.fold_stmt (r, s, src);
+}
+
+
+// Fold stmt S into range R using NUM_ELEMENTS from VECTOR as the initial
+// operands encountered.
+
+bool
+fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector)
+{
+  fold_using_range f;
+  fur_list src (num_elements, vector);
+  return f.fold_stmt (r, s, src);
+}
+
+
+// Fold stmt S into range R using range query Q.
+
+bool
+fold_range (irange &r, gimple *s, range_query *q)
+{
+  fold_using_range f;
+  fur_stmt src (s, q);
+  return f.fold_stmt (r, s, src);
+}
+
+// Recalculate stmt S into R using range query Q as if it were on edge ON_EDGE.
+
+bool
+fold_range (irange &r, gimple *s, edge on_edge, range_query *q)
+{
+  fold_using_range f;
+  fur_edge src (on_edge, q);
+  return f.fold_stmt (r, s, src);
+}
+
+// -------------------------------------------------------------------------
 
 // Adjust the range for a pointer difference where the operands came
 // from a memchr.
@@ -375,17 +640,17 @@ fold_using_range::range_of_range_op (irange &r, gimple *s, fur_source &src)
 	  // Fold range, and register any dependency if available.
 	  int_range<2> r2 (type);
 	  handler->fold_range (r, type, range1, r2);
-	  if (lhs && src.m_gori)
-	    src.m_gori->register_dependency (lhs, op1);
+	  if (lhs)
+	    src.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_gori)
+	  if (lhs)
 	    {
-	      src.m_gori->register_dependency (lhs, op1);
-	      src.m_gori->register_dependency (lhs, op2);
+	      src.register_dependency (lhs, op1);
+	      src.register_dependency (lhs, op2);
 	    }
 	}
       else
@@ -425,8 +690,8 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src)
     {
       tree ssa = TREE_OPERAND (base, 0);
       tree lhs = gimple_get_lhs (stmt);
-      if (src.m_gori && lhs && gimple_range_ssa_p (ssa))
-	src.m_gori->register_dependency (lhs, ssa);
+      if (lhs && gimple_range_ssa_p (ssa))
+	src.register_dependency (lhs, ssa);
       gcc_checking_assert (irange::supports_type_p (TREE_TYPE (ssa)));
       src.get_operand (r, ssa);
       range_cast (r, TREE_TYPE (gimple_assign_rhs1 (stmt)));
@@ -503,19 +768,12 @@ fold_using_range::range_of_phi (irange &r, gphi *phi, fur_source &src)
       edge e = gimple_phi_arg_edge (phi, x);
 
       // Register potential dependencies for stale value tracking.
-      if (src.m_gori && gimple_range_ssa_p (arg))
-	src.m_gori->register_dependency (phi_def, arg);
+      if (gimple_range_ssa_p (arg))
+	src.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);
+      src.get_phi_operand (arg_range, arg, e);
       // 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 ())
@@ -1012,7 +1270,7 @@ bool
 gimple_ranger::fold_range_internal (irange &r, gimple *s, tree name)
 {
   fold_using_range f;
-  fur_source src (this, &(gori ()), NULL, s);
+  fur_depend src (s, &(gori ()), this);
   return f.fold_stmt (r, s, src, name);
 }
 
@@ -1191,22 +1449,18 @@ fold_using_range::range_of_ssa_name_with_loop_info (irange &r, tree name,
 {
   gcc_checking_assert (TREE_CODE (name) == SSA_NAME);
   tree min, max, type = TREE_TYPE (name);
-  if (bounds_of_var_in_loop (&min, &max, src.m_query, l, phi, name))
+  if (bounds_of_var_in_loop (&min, &max, src.query (), l, phi, name))
     {
       if (TREE_CODE (min) != INTEGER_CST)
 	{
-	  if (src.m_query
-	      && src.m_query->range_of_expr (r, min, phi)
-	      && !r.undefined_p ())
+	  if (src.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)
 	{
-	  if (src.m_query
-	      && src.m_query->range_of_expr (r, max, phi)
-	      && !r.undefined_p ())
+	  if (src.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);
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index 02b891fad69..9ac779a720c 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -73,28 +73,45 @@ protected:
   ranger_cache m_cache;
 };
 
-// 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.
+// Source of all operands for fold_using_range and gori_compute.
+// It abstracts out the source of an operand so it can come from a stmt or
+// and edge or anywhere a derived classof fur_source wants.
 
 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, gori_compute *g, edge e, gimple *s);
-  bool get_operand (irange &r, tree expr);
-protected:
-  gori_compute *m_gori;
+  virtual bool get_operand (irange &r, tree expr);
+  virtual bool get_phi_operand (irange &r, tree expr, edge e);
+  virtual void register_dependency (tree lhs, tree rhs);
+  virtual range_query *query ();
+};
+
+// fur_stmt is the specification for drawing an operand from range_query Q
+// via a range_of_Expr call on stmt S.
+
+class fur_stmt : public fur_source
+{
+public:
+  fur_stmt (gimple *s, range_query *q = NULL);
+  virtual bool get_operand (irange &r, tree expr) OVERRIDE;
+  virtual bool get_phi_operand (irange &r, tree expr, edge e) OVERRIDE;
+  virtual range_query *query () OVERRIDE;
+private:
   range_query *m_query;
-  edge m_edge;
   gimple *m_stmt;
 };
 
 
+// Fold stmt S into range R using range query Q.
+bool fold_range (irange &r, gimple *s, range_query *q = NULL);
+// Recalculate stmt S into R using range query Q as if it were on edge ON_EDGE.
+bool fold_range (irange &r, gimple *s, edge on_edge, range_query *q = NULL);
+// These routines allow you to specify the operands to use when folding.
+// Any excess queries will be drawn from the current range_query.
+bool fold_range (irange &r, gimple *s, irange &r1);
+bool fold_range (irange &r, gimple *s, irange &r1, irange &r2);
+bool fold_range (irange &r, gimple *s, unsigned num_elements, irange *vector);
+
 // 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
@@ -119,64 +136,6 @@ protected:
 };
 
 
-// Create a source for a query on an edge.
-
-inline
-fur_source::fur_source (range_query *q, edge e)
-{
-  m_query = q;
-  m_gori = 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_gori = 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, gori_compute *g, edge e, gimple *s)
-{
-  m_query = q;
-  m_gori = 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;
-  if (q == NULL)
-    q = get_global_range_query ();
-  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;
-  if (q == NULL)
-    q = get_global_range_query ();
-  fur_source src (q, on_edge);
-  return f.fold_stmt (r, s, src);
-}
-
 // 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);
