[03/17] Create gimple_range_op_handler in a new source file.

Message ID 6d24be24-0924-f56b-7dfe-18b251b42ed5@redhat.com
State New
Headers
Series Move builtin functions to range-ops. |

Commit Message

Andrew MacLeod Sept. 22, 2022, 6:56 p.m. UTC
  Range-ops is meant to be IL independent.  Some gimple processing has 
be placed in range-ops, and some is located in gori.  Split it all into 
a file and isolate it in a new class gimple_range_op_handler.

Bootstrapped on x86_64-pc-linux-gnu with no regressions.  Pushed.

Andrew
  

Patch

From 51ce06385bf259a092f830f1a6dcc4b98757919e Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Thu, 1 Sep 2022 10:34:55 -0400
Subject: [PATCH 03/17] Create gimple_range_op_handler in a new source file.

Range-ops is meant to be IL independent.  Some gimple processing has
be placed in range-ops, and some is located in gori.  Split it all into
a file and isolate it in a new class gimple_range_op_handler.

	* Makefile.in (OBJS): Add gimple-range-op.o.
	* gimple-range-edge.cc (gimple_outgoing_range_stmt_p): Use
	gimple_range_op_handler.
	* gimple-range-fold.cc (gimple_range_base_of_assignment): Move
	to a method in gimple_range_op_handler.
	(gimple_range_operand1): Ditto.
	(gimple_range_operand2): Ditto.
	(fold_using_range::fold_stmt): Use gimple_range_op_handler.
	(fold_using_range::range_of_range_op): Ditto.
	(fold_using_range::relation_fold_and_or): Ditto.
	(fur_source::register_outgoing_edges): Ditto.
	(gimple_range_ssa_names): Relocate to gimple-range-op.cc.
	* gimple-range-fold.h: Adjust prototypes.
	* gimple-range-gori.cc (gimple_range_calc_op1): Move
	to a method in gimple_range_op_handler.
	(gimple_range_calc_op2): Ditto.
	(gori_compute::compute_operand_range): Use
	gimple_range_op_handler.
	(gori_compute::compute_logical_operands): Ditto.
	(compute_operand1_range): Ditto.
	(gori_compute::compute_operand2_range): Ditto.
	(gori_compute::compute_operand1_and_operand2_range): Ditto.
	* gimple-range-gori.h: Adjust protoypes.
	* gimple-range-op.cc: New.  Supply gimple_range_op_handler methods.
	* gimple-range-op.h: New.  Supply gimple_range_op_handler class.
	* gimple-range.cc (gimple_ranger::prefill_name): Use
	gimple_range_op_handler.
	(gimple_ranger::prefill_stmt_dependencies): Ditto.
	* gimple-range.h: Include gimple-range-op.h.
	* range-op.cc (range_op_handler::range_op_handler): Adjust and
	remove gimple * parameter option.
	* range-op.h: Adjust prototypes.
---
 gcc/Makefile.in          |   1 +
 gcc/gimple-range-edge.cc |   2 +-
 gcc/gimple-range-fold.cc | 153 +++++-------------------
 gcc/gimple-range-fold.h  |  12 +-
 gcc/gimple-range-gori.cc | 134 ++++++---------------
 gcc/gimple-range-gori.h  |  27 ++---
 gcc/gimple-range-op.cc   | 245 +++++++++++++++++++++++++++++++++++++++
 gcc/gimple-range-op.h    |  51 ++++++++
 gcc/gimple-range.cc      |  11 +-
 gcc/gimple-range.h       |   2 +-
 gcc/range-op.cc          |  37 ++----
 gcc/range-op.h           |   4 +-
 12 files changed, 386 insertions(+), 293 deletions(-)
 create mode 100644 gcc/gimple-range-op.cc
 create mode 100644 gcc/gimple-range-op.h

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index a4689d52e36..59b67d99441 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1416,6 +1416,7 @@  OBJS = \
 	gimple-range-fold.o \
 	gimple-range-gori.o \
 	gimple-range-infer.o \
+	gimple-range-op.o \
 	gimple-range-trace.o \
 	gimple-ssa-backprop.o \
 	gimple-ssa-isolate-paths.o \
diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc
index 194e8f87a4b..95deadffc55 100644
--- a/gcc/gimple-range-edge.cc
+++ b/gcc/gimple-range-edge.cc
@@ -43,7 +43,7 @@  gimple_outgoing_range_stmt_p (basic_block bb)
   if (!gsi_end_p (gsi))
     {
       gimple *s = gsi_stmt (gsi);
-      if (is_a<gcond *> (s) && range_op_handler (s))
+      if (is_a<gcond *> (s) && gimple_range_op_handler::supported_p (s))
 	return gsi_stmt (gsi);
       if (is_a <gswitch *> (s))
 	return gsi_stmt (gsi);
diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index a45fc7ad4c6..addf3e7f254 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -42,7 +42,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "vr-values.h"
 #include "range.h"
 #include "value-query.h"
-#include "range-op.h"
+#include "gimple-range-op.h"
 #include "gimple-range.h"
 // Construct a fur_source, and set the m_query field.
 
@@ -463,73 +463,6 @@  gimple_range_adjustment (vrange &res, const gimple *stmt)
     }
 }
 
-// Return the base of the RHS of an assignment.
-
-static tree
-gimple_range_base_of_assignment (const gimple *stmt)
-{
-  gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN);
-  tree op1 = gimple_assign_rhs1 (stmt);
-  if (gimple_assign_rhs_code (stmt) == ADDR_EXPR)
-    return get_base_address (TREE_OPERAND (op1, 0));
-  return op1;
-}
-
-// Return the first operand of this statement if it is a valid operand
-// supported by ranges, otherwise return NULL_TREE.  Special case is
-// &(SSA_NAME expr), return the SSA_NAME instead of the ADDR expr.
-
-tree
-gimple_range_operand1 (const gimple *stmt)
-{
-  gcc_checking_assert (range_op_handler (stmt));
-
-  switch (gimple_code (stmt))
-    {
-      case GIMPLE_COND:
-	return gimple_cond_lhs (stmt);
-      case GIMPLE_ASSIGN:
-	{
-	  tree base = gimple_range_base_of_assignment (stmt);
-	  if (base && TREE_CODE (base) == MEM_REF)
-	    {
-	      // If the base address is an SSA_NAME, we return it
-	      // here.  This allows processing of the range of that
-	      // name, while the rest of the expression is simply
-	      // ignored.  The code in range_ops will see the
-	      // ADDR_EXPR and do the right thing.
-	      tree ssa = TREE_OPERAND (base, 0);
-	      if (TREE_CODE (ssa) == SSA_NAME)
-		return ssa;
-	    }
-	  return base;
-	}
-      default:
-	break;
-    }
-  return NULL;
-}
-
-// Return the second operand of statement STMT, otherwise return NULL_TREE.
-
-tree
-gimple_range_operand2 (const gimple *stmt)
-{
-  gcc_checking_assert (range_op_handler (stmt));
-
-  switch (gimple_code (stmt))
-    {
-    case GIMPLE_COND:
-      return gimple_cond_rhs (stmt);
-    case GIMPLE_ASSIGN:
-      if (gimple_num_ops (stmt) >= 3)
-	return gimple_assign_rhs2 (stmt);
-    default:
-      break;
-    }
-  return NULL_TREE;
-}
-
 // 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.  If a range cannot
@@ -551,8 +484,9 @@  fold_using_range::fold_stmt (vrange &r, gimple *s, fur_source &src, tree name)
       && gimple_assign_rhs_code (s) == ADDR_EXPR)
     return range_of_address (as_a <irange> (r), s, src);
 
-  if (range_op_handler (s))
-    res = range_of_range_op (r, s, src);
+  gimple_range_op_handler handler (s);
+  if (handler)
+    res = range_of_range_op (r, handler, src);
   else if (is_a<gphi *>(s))
     res = range_of_phi (r, as_a<gphi *> (s), src);
   else if (is_a<gcall *>(s))
@@ -587,17 +521,19 @@  fold_using_range::fold_stmt (vrange &r, gimple *s, fur_source &src, tree name)
 // If a range cannot be calculated, return false.
 
 bool
-fold_using_range::range_of_range_op (vrange &r, gimple *s, fur_source &src)
+fold_using_range::range_of_range_op (vrange &r,
+				     gimple_range_op_handler &handler,
+				     fur_source &src)
 {
+  gcc_checking_assert (handler);
+  gimple *s = handler.stmt ();
   tree type = gimple_range_type (s);
   if (!type)
     return false;
-  range_op_handler handler (s);
-  gcc_checking_assert (handler);
 
-  tree lhs = gimple_get_lhs (s);
-  tree op1 = gimple_range_operand1 (s);
-  tree op2 = gimple_range_operand2 (s);
+  tree lhs = handler.lhs ();
+  tree op1 = handler.operand1 ();
+  tree op2 = handler.operand2 ();
   Value_Range range1 (TREE_TYPE (op1));
   Value_Range range2 (op2 ? TREE_TYPE (op2) : TREE_TYPE (op1));
 
@@ -1430,9 +1366,10 @@  fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
   else if (code != BIT_IOR_EXPR && code != TRUTH_OR_EXPR)
     return;
 
-  tree lhs = gimple_get_lhs (s);
-  tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (s));
-  tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (s));
+  gimple_range_op_handler handler (s);
+  tree lhs = handler.lhs ();
+  tree ssa1 = gimple_range_ssa_p (handler.operand1 ());
+  tree ssa2 = gimple_range_ssa_p (handler.operand2 ());
 
   // Deal with || and && only when there is a full set of symbolics.
   if (!lhs || !ssa1 || !ssa2
@@ -1448,18 +1385,18 @@  fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
   gimple *ssa1_stmt = SSA_NAME_DEF_STMT (ssa1);
   gimple *ssa2_stmt = SSA_NAME_DEF_STMT (ssa2);
 
-  range_op_handler handler1 (SSA_NAME_DEF_STMT (ssa1));
-  range_op_handler handler2 (SSA_NAME_DEF_STMT (ssa2));
+  gimple_range_op_handler handler1 (ssa1_stmt);
+  gimple_range_op_handler handler2 (ssa2_stmt);
 
   // If either handler is not present, no relation can be found.
   if (!handler1 || !handler2)
     return;
 
   // Both stmts will need to have 2 ssa names in the stmt.
-  tree ssa1_dep1 = gimple_range_ssa_p (gimple_range_operand1 (ssa1_stmt));
-  tree ssa1_dep2 = gimple_range_ssa_p (gimple_range_operand2 (ssa1_stmt));
-  tree ssa2_dep1 = gimple_range_ssa_p (gimple_range_operand1 (ssa2_stmt));
-  tree ssa2_dep2 = gimple_range_ssa_p (gimple_range_operand2 (ssa2_stmt));
+  tree ssa1_dep1 = gimple_range_ssa_p (handler1.operand1 ());
+  tree ssa1_dep2 = gimple_range_ssa_p (handler1.operand2 ());
+  tree ssa2_dep1 = gimple_range_ssa_p (handler2.operand1 ());
+  tree ssa2_dep2 = gimple_range_ssa_p (handler2.operand2 ());
 
   if (!ssa1_dep1 || !ssa1_dep2 || !ssa2_dep1 || !ssa2_dep2)
     return;
@@ -1516,7 +1453,7 @@  fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
   tree name;
   basic_block bb = gimple_bb (s);
 
-  range_op_handler handler (s);
+  gimple_range_op_handler handler (s);
   if (!handler)
     return;
 
@@ -1529,7 +1466,6 @@  fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
 	e0 = NULL;
     }
 
-
   if (e1)
     {
       // If this edge is never taken, ignore it.
@@ -1544,8 +1480,8 @@  fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
 
   // First, register the gcond itself.  This will catch statements like
   // if (a_2 < b_5)
-  tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (s));
-  tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (s));
+  tree ssa1 = gimple_range_ssa_p (handler.operand1 ());
+  tree ssa2 = gimple_range_ssa_p (handler.operand2 ());
   if (ssa1 && ssa2)
     {
       if (e0)
@@ -1575,11 +1511,11 @@  fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
       if (TREE_CODE (TREE_TYPE (name)) != BOOLEAN_TYPE)
 	continue;
       gimple *stmt = SSA_NAME_DEF_STMT (name);
-      range_op_handler handler (stmt);
+      gimple_range_op_handler handler (stmt);
       if (!handler)
 	continue;
-      tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
-      tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (stmt));
+      tree ssa1 = gimple_range_ssa_p (handler.operand1 ());
+      tree ssa2 = gimple_range_ssa_p (handler.operand2 ());
       Value_Range r (TREE_TYPE (name));
       if (ssa1 && ssa2)
 	{
@@ -1600,36 +1536,3 @@  fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
 	}
     }
 }
-
-// Given stmt S, fill VEC, up to VEC_SIZE elements, with relevant ssa-names
-// on the statement.  For efficiency, it is an error to not pass in enough
-// elements for the vector.  Return the number of ssa-names.
-
-unsigned
-gimple_range_ssa_names (tree *vec, unsigned vec_size, gimple *stmt)
-{
-  tree ssa;
-  int count = 0;
-
-  if (range_op_handler (stmt))
-    {
-      gcc_checking_assert (vec_size >= 2);
-      if ((ssa = gimple_range_ssa_p (gimple_range_operand1 (stmt))))
-	vec[count++] = ssa;
-      if ((ssa = gimple_range_ssa_p (gimple_range_operand2 (stmt))))
-	vec[count++] = ssa;
-    }
-  else if (is_a<gassign *> (stmt)
-	   && gimple_assign_rhs_code (stmt) == COND_EXPR)
-    {
-      gcc_checking_assert (vec_size >= 3);
-      gassign *st = as_a<gassign *> (stmt);
-      if ((ssa = gimple_range_ssa_p (gimple_assign_rhs1 (st))))
-	vec[count++] = ssa;
-      if ((ssa = gimple_range_ssa_p (gimple_assign_rhs2 (st))))
-	vec[count++] = ssa;
-      if ((ssa = gimple_range_ssa_p (gimple_assign_rhs3 (st))))
-	vec[count++] = ssa;
-    }
-  return count;
-}
diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h
index f2eab720213..ce18c66b8e7 100644
--- a/gcc/gimple-range-fold.h
+++ b/gcc/gimple-range-fold.h
@@ -96,15 +96,6 @@  range_compatible_p (tree type1, tree type2)
 	  && TYPE_SIGN (type1) == TYPE_SIGN (type2));
 }
 
-extern tree gimple_range_operand1 (const gimple *s);
-extern tree gimple_range_operand2 (const gimple *s);
-
-// Given stmt S, fill VEC, up to VEC_SIZE elements, with relevant ssa-names
-// on the statement.  For efficiency, it is an error to not pass in enough
-// elements for the vector.  Return the number of ssa-names.
-
-unsigned gimple_range_ssa_names (tree *vec, unsigned vec_size, gimple *stmt);
-
 // 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 class of fur_source wants.
@@ -169,7 +160,8 @@  public:
   bool fold_stmt (vrange &r, gimple *s, class fur_source &src,
 		  tree name = NULL_TREE);
 protected:
-  bool range_of_range_op (vrange &r, gimple *s, fur_source &src);
+  bool range_of_range_op (vrange &r, gimple_range_op_handler &handler,
+			  fur_source &src);
   bool range_of_call (vrange &r, gcall *call, fur_source &src);
   bool range_of_cond_expr (vrange &r, gassign* cond, fur_source &src);
   bool range_of_address (irange &r, gimple *s, fur_source &src);
diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc
index 957b8d543fa..40b2f2f6ae9 100644
--- a/gcc/gimple-range-gori.cc
+++ b/gcc/gimple-range-gori.cc
@@ -29,83 +29,6 @@  along with GCC; see the file COPYING3.  If not see
 #include "gimple-pretty-print.h"
 #include "gimple-range.h"
 
-// Calculate what we can determine of the range of this unary
-// statement's operand if the lhs of the expression has the range
-// LHS_RANGE.  Return false if nothing can be determined.
-
-bool
-gimple_range_calc_op1 (vrange &r, const gimple *stmt, const vrange &lhs_range)
-{
-  gcc_checking_assert (gimple_num_ops (stmt) < 3);
-  // Give up on empty ranges.
-  if (lhs_range.undefined_p ())
-    return false;
-
-  // Unary operations require the type of the first operand in the
-  // second range position.
-  tree type = TREE_TYPE (gimple_range_operand1 (stmt));
-  Value_Range type_range (type);
-  type_range.set_varying (type);
-  return range_op_handler (stmt).op1_range (r, type, lhs_range, type_range);
-}
-
-// Calculate what we can determine of the range of this statement's
-// first operand if the lhs of the expression has the range LHS_RANGE
-// and the second operand has the range OP2_RANGE.  Return false if
-// nothing can be determined.
-
-bool
-gimple_range_calc_op1 (vrange &r, const gimple *stmt,
-		       const vrange &lhs_range, const vrange &op2_range)
-{
-  // Give up on empty ranges.
-  if (lhs_range.undefined_p ())
-    return false;
-
-  // Unary operation are allowed to pass a range in for second operand
-  // as there are often additional restrictions beyond the type which
-  // can be imposed.  See operator_cast::op1_range().
-  tree type = TREE_TYPE (gimple_range_operand1 (stmt));
-  // If op2 is undefined, solve as if it is varying.
-  if (op2_range.undefined_p ())
-    {
-      // This is sometimes invoked on single operand stmts.
-      if (gimple_num_ops (stmt) < 3)
-	return false;
-      tree op2_type = TREE_TYPE (gimple_range_operand2 (stmt));
-      Value_Range trange (op2_type);
-      trange.set_varying (op2_type);
-      return range_op_handler (stmt).op1_range (r, type, lhs_range, trange);
-    }
-  return range_op_handler (stmt).op1_range (r, type, lhs_range, op2_range);
-}
-
-// Calculate what we can determine of the range of this statement's
-// second operand if the lhs of the expression has the range LHS_RANGE
-// and the first operand has the range OP1_RANGE.  Return false if
-// nothing can be determined.
-
-bool
-gimple_range_calc_op2 (vrange &r, const gimple *stmt,
-		       const vrange &lhs_range, const vrange &op1_range)
-{
-  // Give up on empty ranges.
-  if (lhs_range.undefined_p ())
-    return false;
-
-  tree type = TREE_TYPE (gimple_range_operand2 (stmt));
-  // If op1 is undefined, solve as if it is varying.
-  if (op1_range.undefined_p ())
-    {
-      tree op1_type = TREE_TYPE (gimple_range_operand1 (stmt));
-      Value_Range trange (op1_type);
-      trange.set_varying (op1_type);
-      return range_op_handler (stmt).op2_range (r, type, lhs_range, trange);
-    }
-  return range_op_handler (stmt).op2_range (r, type, lhs_range,
-					    op1_range);
-}
-
 // Return TRUE if GS is a logical && or || expression.
 
 static inline bool
@@ -695,17 +618,18 @@  gori_compute::compute_operand_range (vrange &r, gimple *stmt,
   if (is_a<gswitch *> (stmt))
     return compute_operand_range_switch (r, as_a<gswitch *> (stmt), lhs, name,
 					 src);
-  if (!range_op_handler (stmt))
+  gimple_range_op_handler handler (stmt);
+  if (!handler)
     return false;
 
-  tree op1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
-  tree op2 = gimple_range_ssa_p (gimple_range_operand2 (stmt));
+  tree op1 = gimple_range_ssa_p (handler.operand1 ());
+  tree op2 = gimple_range_ssa_p (handler.operand2 ());
 
   // Handle end of lookup first.
   if (op1 == name)
-    return compute_operand1_range (r, stmt, lhs, name, src);
+    return compute_operand1_range (r, handler, lhs, name, src);
   if (op2 == name)
-    return compute_operand2_range (r, stmt, lhs, name, src);
+    return compute_operand2_range (r, handler, lhs, name, src);
 
   // NAME is not in this stmt, but one of the names in it ought to be
   // derived from it.
@@ -733,10 +657,10 @@  gori_compute::compute_operand_range (vrange &r, gimple *stmt,
       tree type = TREE_TYPE (name);
       Value_Range op1_trange (type), op1_frange (type);
       Value_Range op2_trange (type), op2_frange (type);
-      compute_logical_operands (op1_trange, op1_frange, stmt,
+      compute_logical_operands (op1_trange, op1_frange, handler,
 				as_a <irange> (lhs),
 				name, src, op1, op1_in_chain);
-      compute_logical_operands (op2_trange, op2_frange, stmt,
+      compute_logical_operands (op2_trange, op2_frange, handler,
 				as_a <irange> (lhs),
 				name, src, op2, op2_in_chain);
       res = logical_combine (r,
@@ -748,11 +672,11 @@  gori_compute::compute_operand_range (vrange &r, gimple *stmt,
     }
   // Follow the appropriate operands now.
   else if (op1_in_chain && op2_in_chain)
-    res = compute_operand1_and_operand2_range (r, stmt, lhs, name, src);
+    res = compute_operand1_and_operand2_range (r, handler, lhs, name, src);
   else if (op1_in_chain)
-    res = compute_operand1_range (r, stmt, lhs, name, src);
+    res = compute_operand1_range (r, handler, lhs, name, src);
   else if (op2_in_chain)
-    res = compute_operand2_range (r, stmt, lhs, name, src);
+    res = compute_operand2_range (r, handler, lhs, name, src);
   else
     gcc_unreachable ();
 
@@ -944,13 +868,14 @@  gori_compute::logical_combine (vrange &r, enum tree_code code,
 
 void
 gori_compute::compute_logical_operands (vrange &true_range, vrange &false_range,
-					gimple *stmt,
+					gimple_range_op_handler &handler,
 					const irange &lhs,
 					tree name, fur_source &src,
 					tree op, bool op_in_chain)
 {
+  gimple *stmt = handler.stmt ();
   gimple *src_stmt = gimple_range_ssa_p (op) ? SSA_NAME_DEF_STMT (op) : NULL;
-  if (!op_in_chain || !src_stmt || chain_import_p (gimple_get_lhs (stmt), op))
+  if (!op_in_chain || !src_stmt || chain_import_p (handler.lhs (), op))
     {
       // If op is not in the def chain, or defined in this block,
       // use its known value on entry to the block.
@@ -999,12 +924,15 @@  gori_compute::compute_logical_operands (vrange &true_range, vrange &false_range,
 // R, or false if no range could be calculated.
 
 bool
-gori_compute::compute_operand1_range (vrange &r, gimple *stmt,
+gori_compute::compute_operand1_range (vrange &r,
+				      gimple_range_op_handler &handler,
 				      const vrange &lhs, tree name,
 				      fur_source &src)
 {
-  tree op1 = gimple_range_operand1 (stmt);
-  tree op2 = gimple_range_operand2 (stmt);
+  gimple *stmt = handler.stmt ();
+  tree op1 = handler.operand1 ();
+  tree op2 = handler.operand2 ();
+
   Value_Range op1_range (TREE_TYPE (op1));
   Value_Range tmp (TREE_TYPE (op1));
   Value_Range op2_range (op2 ? TREE_TYPE (op2) : TREE_TYPE (op1));
@@ -1016,7 +944,7 @@  gori_compute::compute_operand1_range (vrange &r, gimple *stmt,
   if (op2)
     {
       src.get_operand (op2_range, op2);
-      if (!gimple_range_calc_op1 (tmp, stmt, lhs, op2_range))
+      if (!handler.calc_op1 (tmp, lhs, op2_range))
 	return false;
     }
   else
@@ -1024,7 +952,7 @@  gori_compute::compute_operand1_range (vrange &r, gimple *stmt,
       // We pass op1_range to the unary operation.  Nomally it's a
       // hidden range_for_type parameter, but sometimes having the
       // actual range can result in better information.
-      if (!gimple_range_calc_op1 (tmp, stmt, lhs, op1_range))
+      if (!handler.calc_op1 (tmp, lhs, op1_range))
 	return false;
     }
 
@@ -1079,12 +1007,15 @@  gori_compute::compute_operand1_range (vrange &r, gimple *stmt,
 // R, or false if no range could be calculated.
 
 bool
-gori_compute::compute_operand2_range (vrange &r, gimple *stmt,
+gori_compute::compute_operand2_range (vrange &r,
+				      gimple_range_op_handler &handler,
 				      const vrange &lhs, tree name,
 				      fur_source &src)
 {
-  tree op1 = gimple_range_operand1 (stmt);
-  tree op2 = gimple_range_operand2 (stmt);
+  gimple *stmt = handler.stmt ();
+  tree op1 = handler.operand1 ();
+  tree op2 = handler.operand2 ();
+
   Value_Range op1_range (TREE_TYPE (op1));
   Value_Range op2_range (TREE_TYPE (op2));
   Value_Range tmp (TREE_TYPE (op2));
@@ -1093,7 +1024,7 @@  gori_compute::compute_operand2_range (vrange &r, gimple *stmt,
   src.get_operand (op2_range, op2);
 
   // Intersect with range for op2 based on lhs and op1.
-  if (!gimple_range_calc_op2 (tmp, stmt, lhs, op1_range))
+  if (!handler.calc_op2 (tmp, lhs, op1_range))
     return false;
 
   unsigned idx;
@@ -1148,7 +1079,8 @@  gori_compute::compute_operand2_range (vrange &r, gimple *stmt,
 
 bool
 gori_compute::compute_operand1_and_operand2_range (vrange &r,
-						   gimple *stmt,
+						   gimple_range_op_handler
+								     &handler,
 						   const vrange &lhs,
 						   tree name,
 						   fur_source &src)
@@ -1157,11 +1089,11 @@  gori_compute::compute_operand1_and_operand2_range (vrange &r,
 
   // Calculate a good a range for op2.  Since op1 == op2, this will
   // have already included whatever the actual range of name is.
-  if (!compute_operand2_range (op_range, stmt, lhs, name, src))
+  if (!compute_operand2_range (op_range, handler, lhs, name, src))
     return false;
 
   // Now get the range thru op1.
-  if (!compute_operand1_range (r, stmt, lhs, name, src))
+  if (!compute_operand1_range (r, handler, lhs, name, src))
     return false;
 
   // Both operands have to be simultaneously true, so perform an intersection.
diff --git a/gcc/gimple-range-gori.h b/gcc/gimple-range-gori.h
index 3d57ab94624..0c776ef853f 100644
--- a/gcc/gimple-range-gori.h
+++ b/gcc/gimple-range-gori.h
@@ -170,17 +170,18 @@  private:
 			      tree name, class fur_source &src);
   bool compute_operand_range_switch (vrange &r, gswitch *s, const vrange &lhs,
 				     tree name, fur_source &src);
-  bool compute_operand1_range (vrange &r, gimple *stmt, const vrange &lhs,
-			       tree name, fur_source &src);
-  bool compute_operand2_range (vrange &r, gimple *stmt, const vrange &lhs,
-			       tree name, fur_source &src);
-  bool compute_operand1_and_operand2_range (vrange &r, gimple *stmt,
+  bool compute_operand1_range (vrange &r, gimple_range_op_handler &handler,
+			       const vrange &lhs, tree name, fur_source &src);
+  bool compute_operand2_range (vrange &r, gimple_range_op_handler &handler,
+			       const vrange &lhs, tree name, fur_source &src);
+  bool compute_operand1_and_operand2_range (vrange &r,
+					    gimple_range_op_handler &handler,
 					    const vrange &lhs, tree name,
 					    fur_source &src);
   void compute_logical_operands (vrange &true_range, vrange &false_range,
-				 gimple *stmt, const irange &lhs,
-				 tree name, fur_source &src, tree op,
-				 bool op_in_chain);
+				 gimple_range_op_handler &handler,
+				 const irange &lhs, tree name, fur_source &src,
+				 tree op, bool op_in_chain);
   bool logical_combine (vrange &r, enum tree_code code, const irange &lhs,
 			const vrange &op1_true, const vrange &op1_false,
 			const vrange &op2_true, const vrange &op2_false);
@@ -192,16 +193,6 @@  private:
   int m_not_executable_flag;
 };
 
-// These routines provide a GIMPLE interface to the range-ops code.
-extern bool gimple_range_calc_op1 (vrange &r, const gimple *s,
-				   const vrange &lhs_range);
-extern bool gimple_range_calc_op1 (vrange &r, const gimple *s,
-				   const vrange &lhs_range,
-				   const vrange &op2_range);
-extern bool gimple_range_calc_op2 (vrange &r, const gimple *s,
-				   const vrange &lhs_range,
-				   const vrange &op1_range);
-
 // For each name that is an import into BB's exports..
 #define FOR_EACH_GORI_IMPORT_NAME(gori, bb, name)			\
   for (gori_export_iterator iter ((gori).imports ((bb)));	\
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
new file mode 100644
index 00000000000..f03125a0fc5
--- /dev/null
+++ b/gcc/gimple-range-op.cc
@@ -0,0 +1,245 @@ 
+/* Code for GIMPLE range op related routines.
+   Copyright (C) 2019-2022 Free Software Foundation, Inc.
+   Contributed by Andrew MacLeod <amacleod@redhat.com>
+   and Aldy Hernandez <aldyh@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "insn-codes.h"
+#include "tree.h"
+#include "gimple.h"
+#include "ssa.h"
+#include "gimple-pretty-print.h"
+#include "optabs-tree.h"
+#include "gimple-iterator.h"
+#include "gimple-fold.h"
+#include "wide-int.h"
+#include "fold-const.h"
+#include "case-cfn-macros.h"
+#include "omp-general.h"
+#include "cfgloop.h"
+#include "tree-ssa-loop.h"
+#include "tree-scalar-evolution.h"
+#include "langhooks.h"
+#include "vr-values.h"
+#include "range.h"
+#include "value-query.h"
+#include "gimple-range.h"
+
+// Given stmt S, fill VEC, up to VEC_SIZE elements, with relevant ssa-names
+// on the statement.  For efficiency, it is an error to not pass in enough
+// elements for the vector.  Return the number of ssa-names.
+
+unsigned
+gimple_range_ssa_names (tree *vec, unsigned vec_size, gimple *stmt)
+{
+  tree ssa;
+  int count = 0;
+
+  gimple_range_op_handler handler (stmt);
+  if (handler)
+    {
+      gcc_checking_assert (vec_size >= 2);
+      if ((ssa = gimple_range_ssa_p (handler.operand1 ())))
+	vec[count++] = ssa;
+      if ((ssa = gimple_range_ssa_p (handler.operand2 ())))
+	vec[count++] = ssa;
+    }
+  else if (is_a<gassign *> (stmt)
+	   && gimple_assign_rhs_code (stmt) == COND_EXPR)
+    {
+      gcc_checking_assert (vec_size >= 3);
+      gassign *st = as_a<gassign *> (stmt);
+      if ((ssa = gimple_range_ssa_p (gimple_assign_rhs1 (st))))
+	vec[count++] = ssa;
+      if ((ssa = gimple_range_ssa_p (gimple_assign_rhs2 (st))))
+	vec[count++] = ssa;
+      if ((ssa = gimple_range_ssa_p (gimple_assign_rhs3 (st))))
+	vec[count++] = ssa;
+    }
+  return count;
+}
+
+// Return the base of the RHS of an assignment.
+
+static tree
+gimple_range_base_of_assignment (const gimple *stmt)
+{
+  gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN);
+  tree op1 = gimple_assign_rhs1 (stmt);
+  if (gimple_assign_rhs_code (stmt) == ADDR_EXPR)
+    return get_base_address (TREE_OPERAND (op1, 0));
+  return op1;
+}
+
+// If statement is supported by range-ops, set the CODE and return the TYPE.
+
+static tree
+get_code_and_type (gimple *s, enum tree_code &code)
+{
+  tree type = NULL_TREE;
+  code = NOP_EXPR;
+
+  if (const gassign *ass = dyn_cast<const gassign *> (s))
+    {
+      code = gimple_assign_rhs_code (ass);
+      // The LHS of a comparison is always an int, so we must look at
+      // the operands.
+      if (TREE_CODE_CLASS (code) == tcc_comparison)
+	type = TREE_TYPE (gimple_assign_rhs1 (ass));
+      else
+	type = TREE_TYPE (gimple_assign_lhs (ass));
+    }
+  else if (const gcond *cond = dyn_cast<const gcond *> (s))
+    {
+      code = gimple_cond_code (cond);
+      type = TREE_TYPE (gimple_cond_lhs (cond));
+    }
+  return type;
+}
+
+// If statement S has a supported range_op handler return TRUE.
+
+bool
+gimple_range_op_handler::supported_p (gimple *s)
+{
+  enum tree_code code;
+  tree type = get_code_and_type (s, code);
+  return (type && range_op_handler (code, type));
+}
+
+// Construct a handler object for statement S.
+
+gimple_range_op_handler::gimple_range_op_handler (gimple *s)
+{
+  enum tree_code code;
+  tree type = get_code_and_type (s, code);
+  m_stmt = s;
+  if (type)
+    set_op_handler (code, type);
+
+  if (m_valid)
+    switch (gimple_code (m_stmt))
+      {
+	case GIMPLE_COND:
+	  m_op1 = gimple_cond_lhs (m_stmt);
+	  m_op2 = gimple_cond_rhs (m_stmt);
+	  break;
+	case GIMPLE_ASSIGN:
+	  m_op1 = gimple_range_base_of_assignment (m_stmt);
+	  if (m_op1 && TREE_CODE (m_op1) == MEM_REF)
+	    {
+	      // If the base address is an SSA_NAME, we return it
+	      // here.  This allows processing of the range of that
+	      // name, while the rest of the expression is simply
+	      // ignored.  The code in range_ops will see the
+	      // ADDR_EXPR and do the right thing.
+	      tree ssa = TREE_OPERAND (m_op1, 0);
+	      if (TREE_CODE (ssa) == SSA_NAME)
+		m_op1 = ssa;
+	    }
+	  if (gimple_num_ops (m_stmt) >= 3)
+	    m_op2 = gimple_assign_rhs2 (m_stmt);
+	  else
+	    m_op2 = NULL_TREE;
+	  break;
+	default:
+	  m_op1 = NULL_TREE;
+	  m_op2 = NULL_TREE;
+	  break;
+      }
+}
+
+// Calculate what we can determine of the range of this unary
+// statement's operand if the lhs of the expression has the range
+// LHS_RANGE.  Return false if nothing can be determined.
+
+bool
+gimple_range_op_handler::calc_op1 (vrange &r, const vrange &lhs_range)
+{
+  gcc_checking_assert (gimple_num_ops (m_stmt) < 3);
+  // Give up on empty ranges.
+  if (lhs_range.undefined_p ())
+    return false;
+
+  // Unary operations require the type of the first operand in the
+  // second range position.
+  tree type = TREE_TYPE (operand1 ());
+  Value_Range type_range (type);
+  type_range.set_varying (type);
+  return op1_range (r, type, lhs_range, type_range);
+}
+
+// Calculate what we can determine of the range of this statement's
+// first operand if the lhs of the expression has the range LHS_RANGE
+// and the second operand has the range OP2_RANGE.  Return false if
+// nothing can be determined.
+
+bool
+gimple_range_op_handler::calc_op1 (vrange &r, const vrange &lhs_range,
+				   const vrange &op2_range)
+{
+  // Give up on empty ranges.
+  if (lhs_range.undefined_p ())
+    return false;
+
+  // Unary operation are allowed to pass a range in for second operand
+  // as there are often additional restrictions beyond the type which
+  // can be imposed.  See operator_cast::op1_range().
+  tree type = TREE_TYPE (operand1 ());
+  // If op2 is undefined, solve as if it is varying.
+  if (op2_range.undefined_p ())
+    {
+      // This is sometimes invoked on single operand stmts.
+      if (gimple_num_ops (m_stmt) < 3)
+	return false;
+      tree op2_type = TREE_TYPE (operand2 ());
+      Value_Range trange (op2_type);
+      trange.set_varying (op2_type);
+      return op1_range (r, type, lhs_range, trange);
+    }
+  return op1_range (r, type, lhs_range, op2_range);
+}
+
+// Calculate what we can determine of the range of this statement's
+// second operand if the lhs of the expression has the range LHS_RANGE
+// and the first operand has the range OP1_RANGE.  Return false if
+// nothing can be determined.
+
+bool
+gimple_range_op_handler::calc_op2 (vrange &r, const vrange &lhs_range,
+				   const vrange &op1_range)
+{
+  // Give up on empty ranges.
+  if (lhs_range.undefined_p ())
+    return false;
+
+  tree type = TREE_TYPE (operand2 ());
+  // If op1 is undefined, solve as if it is varying.
+  if (op1_range.undefined_p ())
+    {
+      tree op1_type = TREE_TYPE (operand1 ());
+      Value_Range trange (op1_type);
+      trange.set_varying (op1_type);
+      return op2_range (r, type, lhs_range, trange);
+    }
+  return op2_range (r, type, lhs_range, op1_range);
+}
diff --git a/gcc/gimple-range-op.h b/gcc/gimple-range-op.h
new file mode 100644
index 00000000000..8bc0a8fbe11
--- /dev/null
+++ b/gcc/gimple-range-op.h
@@ -0,0 +1,51 @@ 
+/* Header file for the GIMPLE range-op interface.
+   Copyright (C) 2022 Free Software Foundation, Inc.
+   Contributed by Andrew MacLeod <amacleod@redhat.com>
+   and Aldy Hernandez <aldyh@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_GIMPLE_RANGE_OP_H
+#define GCC_GIMPLE_RANGE_OP_H
+
+#include "range-op.h"
+
+
+class gimple_range_op_handler : public range_op_handler
+{
+public:
+  static bool supported_p (gimple *s);
+  gimple_range_op_handler (gimple *s);
+  inline gimple *stmt () const { return m_stmt; }
+  inline tree lhs () const { return gimple_get_lhs (m_stmt); }
+  tree operand1 () const { gcc_checking_assert (m_valid); return m_op1; }
+  tree operand2 () const { gcc_checking_assert (m_valid); return m_op2; }
+  bool calc_op1 (vrange &r, const vrange &lhs_range);
+  bool calc_op1 (vrange &r, const vrange &lhs_range, const vrange &op2_range);
+  bool calc_op2 (vrange &r, const vrange &lhs_range, const vrange &op1_range);
+private:
+  gimple *m_stmt;
+  tree m_op1, m_op2;
+};
+
+// Given stmt S, fill VEC, up to VEC_SIZE elements, with relevant ssa-names
+// on the statement.  For efficiency, it is an error to not pass in enough
+// elements for the vector.  Return the number of ssa-names.
+
+unsigned gimple_range_ssa_names (tree *vec, unsigned vec_size, gimple *stmt);
+
+#endif // GCC_GIMPLE_RANGE_OP_H
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index eb347eee45b..d67d6499c78 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -341,7 +341,7 @@  gimple_ranger::prefill_name (vrange &r, tree name)
   if (!gimple_range_ssa_p (name))
     return;
   gimple *stmt = SSA_NAME_DEF_STMT (name);
-  if (!range_op_handler (stmt) && !is_a<gphi *> (stmt))
+  if (!gimple_range_op_handler::supported_p (stmt) && !is_a<gphi *> (stmt))
     return;
 
   bool current;
@@ -364,7 +364,7 @@  gimple_ranger::prefill_stmt_dependencies (tree ssa)
   gcc_checking_assert (stmt && gimple_bb (stmt));
 
   // Only pre-process range-ops and phis.
-  if (!range_op_handler (stmt) && !is_a<gphi *> (stmt))
+  if (!gimple_range_op_handler::supported_p (stmt) && !is_a<gphi *> (stmt))
     return;
 
   // Mark where on the stack we are starting.
@@ -422,14 +422,15 @@  gimple_ranger::prefill_stmt_dependencies (tree ssa)
 	}
       else
 	{
-	  gcc_checking_assert (range_op_handler (stmt));
-	  tree op = gimple_range_operand2 (stmt);
+	  gimple_range_op_handler handler (stmt);
+	  gcc_checking_assert (handler);
+	  tree op = handler.operand2 ();
 	  if (op)
 	    {
 	      Value_Range r (TREE_TYPE (op));
 	      prefill_name (r, op);
 	    }
-	  op = gimple_range_operand1 (stmt);
+	  op = handler.operand1 ();
 	  if (op)
 	    {
 	      Value_Range r (TREE_TYPE (op));
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index 34f61025ac3..8b2ff5685e5 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -24,7 +24,7 @@  along with GCC; see the file COPYING3.  If not see
 
 #include "range.h"
 #include "value-query.h"
-#include "range-op.h"
+#include "gimple-range-op.h"
 #include "gimple-range-trace.h"
 #include "gimple-range-edge.h"
 #include "gimple-range-fold.h"
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index f642b3f26de..9ae42b8331f 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -4182,42 +4182,19 @@  range_op_handler::set_op_handler (tree_code code, tree type)
     }
 }
 
-range_op_handler::range_op_handler (tree_code code, tree type)
+range_op_handler::range_op_handler ()
 {
-  set_op_handler (code, type);
+  m_int = NULL;
+  m_float = NULL;
+  m_valid = false;
 }
 
-range_op_handler::range_op_handler (const gimple *s)
+range_op_handler::range_op_handler (tree_code code, tree type)
 {
-  tree_code code = NOP_EXPR;
-  tree type = NULL_TREE;
-
-  if (const gassign *ass = dyn_cast<const gassign *> (s))
-    {
-      code = gimple_assign_rhs_code (ass);
-      // The LHS of a comparison is always an int, so we must look at
-      // the operands.
-      if (TREE_CODE_CLASS (code) == tcc_comparison)
-	type = TREE_TYPE (gimple_assign_rhs1 (ass));
-      else
-	type = TREE_TYPE (gimple_assign_lhs (ass));
-    }
-  else if (const gcond *cond = dyn_cast<const gcond *> (s))
-    {
-      code = gimple_cond_code (cond);
-      type = TREE_TYPE (gimple_cond_lhs (cond));
-    }
-
-  if (!type)
-    {
-      m_int = NULL;
-      m_float = NULL;
-      m_valid = false;
-    }
-  else
-    set_op_handler (code, type);
+  set_op_handler (code, type);
 }
 
+
 bool
 range_op_handler::fold_range (vrange &r, tree type,
 			      const vrange &lh,
diff --git a/gcc/range-op.h b/gcc/range-op.h
index 56c57c46a8e..b4b5101a9e0 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -160,8 +160,8 @@  public:
 class range_op_handler
 {
 public:
+  range_op_handler ();
   range_op_handler (enum tree_code code, tree type);
-  range_op_handler (const gimple *s);
   inline operator bool () const { return m_valid; }
 
   bool fold_range (vrange &r, tree type,
@@ -185,7 +185,7 @@  public:
 				  const vrange &op2,
 				  relation_kind = VREL_VARYING) const;
   relation_kind op1_op2_relation (const vrange &lhs) const;
-private:
+protected:
   void set_op_handler (enum tree_code code, tree type);
   bool m_valid;
   range_operator *m_int;
-- 
2.37.3