With the addition of floating point ranges, we did a lot of additional class abstraction, then added a bunch more routines for floating point. We didn't know how it would look in the end, so we just marched forward and got it working.

Now that has settled down a bit, and before we go and add more kinds of ranges, I want to visit restructuring the files and provide a better dispatch to the range operators from a vrange.

We currently dispatch based on the type of the statement.. int or float.  the line is blurred heavily when we have statements that have more than one kid of range.. ie

int_value = (int) float_value
  vs
float_value = (float) int_value

Under the current regime, both kinds of casts have to go into the float table.. and this is going to get more complicated if we add more distinct kinds of ranges. With the current implementation, the floating point range operators don't even inherit from range_operator, they are their own kind of operator.   The ideal situation is to have a single unified range-operator class which has all the combinations, and they rest in a single table.  This simplifies numerous things, and avoid us having to classify anything in some arbitrary way. It also moves us back in the direction of the original vision I had for range-ops.

Ive done an initial rough conversion so you can see what it looks like. I've attached a new range-op.h which shows class range-operator will all the virtual function combinations. The new dispatch mechniasm buys us about 1% speedup in both VRP and in jump_threading.  The new mechanism also handles unsupported combinations of operands smoothly, simply returning false if its an unsupported combination of aprameters that is invoked, which is what a default routine would do.

  As for conversion, lets take operator_not_equal as an example.    The end result in range-operator.h is:

class operator_not_equal : public range_operator
{
public:
  bool fold_range (irange &r, tree type, const irange &op1, const irange &op2, relation_trio = TRIO_VARYING) const final override;   bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, relation_trio = TRIO_VARYING) const final override;

  bool op1_range (irange &r, tree type, const irange &lhs, const irange &op2, relation_trio = TRIO_VARYING) const final override;   bool op1_range (frange &r, tree type, const irange &lhs, const frange &op2, relation_trio = TRIO_VARYING) const final override;

  bool op2_range (frange &r, tree type, const irange &lhs, const frange &op1, relation_trio rel = TRIO_VARYING) const final override;   bool op2_range (irange &r, tree type, const irange &lhs, const irange &op1, relation_trio = TRIO_VARYING) const final override;

  relation_kind op1_op2_relation (const irange &lhs) const;
  void update_bitmask (irange &r, const irange &lh, const irange &rh) const;
};
extern operator_not_equal rop_NE_EXPR;

When we add a new range type, such as pointers, you simply add the required prototypes, add new dispatch codes, and implement them.

This is going  to cause some churn but I am trying to keep it to a minimum.  I've been mucking about with it for a couple of weeks, and I was thinking to structure it something like this:

range-op.h and range-op.cc  will have the base range_operator class, along with the range_op_handler class  we move all the class headers, like the above operator_not_equal class into "range-operator.h"

Where the code goes is the biggest struggle. Initially I was going to put it all in one file. This would be best as it allows us to co-locate all the code for various classes of routines. But that would already be about 8000 lines for int and float combined, and will only get larger with new range types. I also considered just including all the range-op-int.cc and range-op-float.cc files into range-op.cc when it compiles, but you still end up with  a big compilation unit.  So this is what I'm think now:

We leave all the existing floating point code in range-op-float.cc, and then move all the existing integer code into a range-op-int.cc file (or I suppose we could even leave it in range-op.cc to avoid extra churn).  The classes must move to  a header to be accessible from the various files which implement them.  This provides for minimal churn. a few deletes and renames, and thats it.  I've attached the diff which moves operator_not_equal to this form (once some other structuring is in place).

The plus is you can see in the header file range-operator.h exactly what is available for any opcode.  Whats less than ideal is that some of the routines are in range-op.cc and some are in range-op-float.cc,   Ultimately, I dont think thats such a big deal as those floating point routines often require common infrastructure, such as nan querying that integer things dont need.   When we add say a pointer range class,  we would create range-op-pointer.cc and all the new stuff required for prange would go in that file.

That is the direction I am headed to clean this up, are there any objections or other suggestions?

I hope to start with some of the early infrastructure next wee., then move on to each individual opcode.

Andrew

PS For the curious, I also decided to preview the first 3 patches which move to a unified range_operator class and implements the new dispatch system (which is in patch 0003*).   Whats missing is the follow on transition to a single unified table which I would do a single opcode at a time to ensure that if a problem comes up, we can easily isolate it to a specific change.  Once all the opcodes have been converted, and everything is in the new unified tree table, then we can simply switch to using just that.  Much of the speedup comes from lack of conditions when loading an operator.... it is a much more streamlined mechanism.
/* Header file for range operator class.
   Copyright (C) 2017-2023 Free Software Foundation, Inc.
   Contributed by Andrew MacLeod <amacl...@redhat.com>
   and Aldy Hernandez <al...@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_RANGE_OP_H
#define GCC_RANGE_OP_H

// This class is implemented for each kind of operator supported by
// the range generator.  It serves various purposes.
//
// 1 - Generates range information for the specific operation between
//     two ranges.  This provides the ability to fold ranges for an
//     expression.
//
// 2 - Performs range algebra on the expression such that a range can be
//     adjusted in terms of one of the operands:
//
//       def = op1 + op2
//
//     Given a range for def, we can adjust the range so that it is in
//     terms of either operand.
//
//     op1_range (def_range, op2) will adjust the range in place so it
//     is in terms of op1.  Since op1 = def - op2, it will subtract
//     op2 from each element of the range.
//
// 3 - Creates a range for an operand based on whether the result is 0 or
//     non-zero.  This is mostly for logical true false, but can serve other
//     purposes.
//       ie   0 = op1 - op2 implies op2 has the same range as op1.
//
// 4 - All supported range combinations are explicitly specified.
//     Any desired combinations should be implemented for each operator.
//     When new range classes are added, new matching prototypes should be
//     added.

class range_operator
{
  friend class range_op_table;
public:
  // Perform an operation between 2 ranges and return it.
  virtual bool fold_range (irange &r, tree type,
			   const irange &lh,
			   const irange &rh,
			   relation_trio = TRIO_VARYING) const;
  virtual bool fold_range (frange &r, tree type,
			   const frange &lh,
			   const frange &rh,
			   relation_trio = TRIO_VARYING) const;
  virtual bool fold_range (irange &r, tree type,
			   const frange &lh,
			   const irange &rh,
			   relation_trio = TRIO_VARYING) const;
  virtual bool fold_range (irange &r, tree type,
			   const frange &lh,
			   const frange &rh,
			   relation_trio = TRIO_VARYING) const;

  // Return the range for op[12] in the general case.  LHS is the range for
  // the LHS of the expression, OP[12]is the range for the other
  //
  // The operand and the result is returned in R.
  //
  // TYPE is the expected type of the range.
  //
  // Return TRUE if the operation is performed and a valid range is available.
  //
  // i.e.  [LHS] = ??? + OP2
  // is re-formed as R = [LHS] - OP2.
  virtual bool op1_range (irange &r, tree type,
			  const irange &lhs,
			  const irange &op2,
			  relation_trio = TRIO_VARYING) const;
  virtual bool op1_range (frange &r, tree type,
			  const frange &lhs,
			  const frange &op2,
			  relation_trio = TRIO_VARYING) const;
  virtual bool op1_range (frange &r, tree type,
			  const irange &lhs,
			  const frange &op2,
			  relation_trio = TRIO_VARYING) const;


  virtual bool op2_range (irange &r, tree type,
			  const irange &lhs,
			  const irange &op1,
			  relation_trio = TRIO_VARYING) const;
  virtual bool op2_range (frange &r, tree type,
			  const frange &lhs,
			  const frange &op1,
			  relation_trio = TRIO_VARYING) const;
  virtual bool op2_range (frange &r, tree type,
			  const irange &lhs,
			  const frange &op1,
			  relation_trio = TRIO_VARYING) const;

  // The following routines are used to represent relations between the
  // various operations.  If the caller knows where the symbolics are,
  // it can query for relationships between them given known ranges.
  // the optional relation passed in is the relation between op1 and op2.
  virtual relation_kind lhs_op1_relation (const irange &lhs,
					  const irange &op1,
					  const irange &op2,
					  relation_kind = VREL_VARYING) const;
  virtual relation_kind lhs_op1_relation (const frange &lhs,
					  const frange &op1,
					  const frange &op2,
					  relation_kind = VREL_VARYING) const;
  virtual relation_kind lhs_op1_relation (const irange &lhs,
					  const frange &op1,
					  const frange &op2,
					  relation_kind = VREL_VARYING) const;

  virtual relation_kind lhs_op2_relation (const irange &lhs,
					  const irange &op1,
					  const irange &op2,
					  relation_kind = VREL_VARYING) const;
  virtual relation_kind lhs_op2_relation (const frange &lhs,
					  const frange &op1,
					  const frange &op2,
					  relation_kind = VREL_VARYING) const;
  virtual relation_kind lhs_op2_relation (const irange &lhs,
					  const frange &op1,
					  const frange &op2,
					  relation_kind = VREL_VARYING) const;

  virtual relation_kind op1_op2_relation (const irange &lhs) const;
  virtual relation_kind op1_op2_relation (const frange &lhs) const;
protected:
  // Perform an integral operation between 2 sub-ranges and return it.
  virtual void wi_fold (irange &r, tree type,
		        const wide_int &lh_lb,
		        const wide_int &lh_ub,
		        const wide_int &rh_lb,
		        const wide_int &rh_ub) const;
  // Effect of relation for generic fold_range clients.
  virtual bool op1_op2_relation_effect (irange &lhs_range, tree type,
					const irange &op1_range,
					const irange &op2_range,
					relation_kind rel) const;
  // Called by fold range to split small subranges into parts.
  void wi_fold_in_parts (irange &r, tree type,
			 const wide_int &lh_lb,
			 const wide_int &lh_ub,
			 const wide_int &rh_lb,
			 const wide_int &rh_ub) const;

  // Called by fold range to split small subranges into parts when op1 == op2
  void wi_fold_in_parts_equiv (irange &r, tree type,
			       const wide_int &lb,
			       const wide_int &ub,
			       unsigned limit) const;
  // Apply any bitmasks implied by these ranges.
  virtual void update_bitmask (irange &, const irange &, const irange &) const;

  // Perform an float operation between 2 ranges and return it.
  virtual void rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub,
			bool &maybe_nan,
			tree type,
			const REAL_VALUE_TYPE &lh_lb,
			const REAL_VALUE_TYPE &lh_ub,
			const REAL_VALUE_TYPE &rh_lb,
			const REAL_VALUE_TYPE &rh_ub,
			relation_kind) const;
};

class range_op_handler
{
public:
  range_op_handler ();
  range_op_handler (enum tree_code code, tree type);
  inline operator bool () const { return m_operator != NULL; }

  bool fold_range (vrange &r, tree type,
		   const vrange &lh,
		   const vrange &rh,
		   relation_trio = TRIO_VARYING) const;
  bool op1_range (vrange &r, tree type,
		  const vrange &lhs,
		  const vrange &op2,
		  relation_trio = TRIO_VARYING) const;
  bool op2_range (vrange &r, tree type,
		  const vrange &lhs,
		  const vrange &op1,
		  relation_trio = TRIO_VARYING) const;
  relation_kind lhs_op1_relation (const vrange &lhs,
				  const vrange &op1,
				  const vrange &op2,
				  relation_kind = VREL_VARYING) const;
  relation_kind lhs_op2_relation (const vrange &lhs,
				  const vrange &op1,
				  const vrange &op2,
				  relation_kind = VREL_VARYING) const;
  relation_kind op1_op2_relation (const vrange &lhs) const;
protected:
  unsigned dispatch_kind (const vrange &lhs, const vrange &op1,
			  const vrange& op2) const;
  void set_op_handler (enum tree_code code, tree type);
  range_operator *m_operator;
};

extern bool range_cast (vrange &, tree type);
extern void wi_set_zero_nonzero_bits (tree type,
				      const wide_int &, const wide_int &,
				      wide_int &maybe_nonzero,
				      wide_int &mustbe_nonzero);

// This implements the range operator tables as local objects.

class range_op_table
{
public:
  range_operator *operator[] (enum tree_code code);
protected:
  void set (enum tree_code code, range_operator &op);
private:
  range_operator *m_range_tree[MAX_TREE_CODES];
};


// Return a pointer to the range_operator instance, if there is one
// associated with tree_code CODE.

inline range_operator *
range_op_table::operator[] (enum tree_code code)
{
  gcc_checking_assert (code > 0 && code < MAX_TREE_CODES);
  return m_range_tree[code];
}

// Add OP to the handler table for CODE.

inline void
range_op_table::set (enum tree_code code, range_operator &op)
{
  gcc_checking_assert (m_range_tree[code] == NULL);
  m_range_tree[code] = &op;
}
#endif // GCC_RANGE_OP_H
From fa7fbe47912e035d82bcc8de0d76ea882de96102 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacl...@redhat.com>
Date: Thu, 1 Jun 2023 13:53:32 -0400
Subject: [PATCH 07/11] Unify NE_EXPR

---
 gcc/range-op-float.cc | 36 +++++++++---------------------------
 gcc/range-op.cc       | 39 +++++++++------------------------------
 gcc/range-operator.h  | 31 +++++++++++++++++++++++++++++++
 3 files changed, 49 insertions(+), 57 deletions(-)

diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index 823b7f5685c..84ecddbb340 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -676,28 +676,10 @@ operator_equal::op1_range (frange &r, tree type,
   return true;
 }
 
-class foperator_not_equal : public range_operator
-{
-  using range_operator::fold_range;
-  using range_operator::op1_range;
-  using range_operator::op1_op2_relation;
-public:
-  bool fold_range (irange &r, tree type,
-		   const frange &op1, const frange &op2,
-		   relation_trio rel = TRIO_VARYING) const final override;
-  relation_kind op1_op2_relation (const irange &lhs) const final override
-  {
-    return not_equal_op1_op2_relation (lhs);
-  }
-  bool op1_range (frange &r, tree type,
-		  const irange &lhs, const frange &op2,
-		  relation_trio = TRIO_VARYING) const final override;
-} fop_not_equal;
-
 bool
-foperator_not_equal::fold_range (irange &r, tree type,
-				 const frange &op1, const frange &op2,
-				 relation_trio rel) const
+operator_not_equal::fold_range (irange &r, tree type,
+				const frange &op1, const frange &op2,
+				relation_trio rel) const
 {
   if (frelop_early_resolve (r, type, op1, op2, rel, VREL_NE))
     return true;
@@ -751,10 +733,10 @@ foperator_not_equal::fold_range (irange &r, tree type,
 }
 
 bool
-foperator_not_equal::op1_range (frange &r, tree type,
-				const irange &lhs,
-				const frange &op2,
-				relation_trio trio) const
+operator_not_equal::op1_range (frange &r, tree type,
+			       const irange &lhs,
+			       const frange &op2,
+			       relation_trio trio) const
 {
   relation_kind rel = trio.op1_op2 ();
   switch (get_bool_state (r, lhs, type))
@@ -2086,7 +2068,7 @@ public:
       op1_no_nan.clear_nan ();
     if (op2.maybe_isnan ())
       op2_no_nan.clear_nan ();
-    if (!fop_not_equal.fold_range (r, type, op1_no_nan, op2_no_nan, rel))
+    if (!rop_NE_EXPR.fold_range (r, type, op1_no_nan, op2_no_nan, rel))
       return false;
     // The result is the same as the ordered version when the
     // comparison is true or when the operands cannot be NANs.
@@ -2803,7 +2785,6 @@ float_table::float_table ()
   // All the relational operators are expected to work, because the
   // calculation of ranges on outgoing edges expect the handlers to be
   // present.
-  set (NE_EXPR, fop_not_equal);
   set (LT_EXPR, fop_lt);
   set (LE_EXPR, fop_le);
   set (GT_EXPR, fop_gt);
@@ -2828,6 +2809,7 @@ float_table::float_table ()
 unified_table::unified_table ()
 {
   set (EQ_EXPR, rop_EQ_EXPR);
+  set (NE_EXPR, rop_NE_EXPR);
 }
 
 #if CHECKING_P
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 954289d6711..47b5c697c8e 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -55,6 +55,7 @@ float_table float_tree_table;
 unified_table unified_tree_table;
 
 operator_equal rop_EQ_EXPR;
+operator_not_equal rop_NE_EXPR;
 
 // Cast the range in R to TYPE.
 
@@ -923,34 +924,19 @@ operator_equal::op2_range (irange &r, tree type,
   return operator_equal::op1_range (r, type, lhs, op1, rel.swap_op1_op2 ());
 }
 
-class operator_not_equal : public range_operator
+// --------------------------------------------------------------------------
+
+void
+operator_not_equal::update_bitmask (irange &r, const irange &lh,
+				    const irange &rh) const
 {
-  using range_operator::fold_range;
-  using range_operator::op1_range;
-  using range_operator::op2_range;
-  using range_operator::op1_op2_relation;
-public:
-  virtual bool fold_range (irange &r, tree type,
-			   const irange &op1,
-			   const irange &op2,
-			   relation_trio = TRIO_VARYING) const;
-  virtual bool op1_range (irange &r, tree type,
-			  const irange &lhs,
-			  const irange &op2,
-			  relation_trio = TRIO_VARYING) const;
-  virtual bool op2_range (irange &r, tree type,
-			  const irange &lhs,
-			  const irange &op1,
-			  relation_trio = TRIO_VARYING) const;
-  virtual relation_kind op1_op2_relation (const irange &lhs) const;
-  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
-    { update_known_bitmask (r, NE_EXPR, lh, rh); }
-} op_not_equal;
+  update_known_bitmask (r, NE_EXPR, lh, rh);
+}
 
 // Check if the LHS range indicates a relation between OP1 and OP2.
 
 relation_kind
-not_equal_op1_op2_relation (const irange &lhs)
+operator_not_equal::op1_op2_relation (const irange &lhs) const
 {
   if (lhs.undefined_p ())
     return VREL_UNDEFINED;
@@ -965,11 +951,6 @@ not_equal_op1_op2_relation (const irange &lhs)
   return VREL_VARYING;
 }
 
-relation_kind
-operator_not_equal::op1_op2_relation (const irange &lhs) const
-{
-  return not_equal_op1_op2_relation (lhs);
-}
 
 bool
 operator_not_equal::fold_range (irange &r, tree type,
@@ -4863,7 +4844,6 @@ pointer_or_operator::wi_fold (irange &r, tree type,
 
 integral_table::integral_table ()
 {
-  set (NE_EXPR, op_not_equal);
   set (LT_EXPR, op_lt);
   set (LE_EXPR, op_le);
   set (GT_EXPR, op_gt);
@@ -4911,7 +4891,6 @@ pointer_table::pointer_table ()
   set (MAX_EXPR, op_ptr_min_max);
   set (POINTER_PLUS_EXPR, op_pointer_plus);
 
-  set (NE_EXPR, op_not_equal);
   set (LT_EXPR, op_lt);
   set (LE_EXPR, op_le);
   set (GT_EXPR, op_gt);
diff --git a/gcc/range-operator.h b/gcc/range-operator.h
index 0f953650139..1ce9ac648dc 100644
--- a/gcc/range-operator.h
+++ b/gcc/range-operator.h
@@ -57,4 +57,35 @@ public:
 };
 extern operator_equal rop_EQ_EXPR;
 
+class operator_not_equal : public range_operator
+{
+public:
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
+  using range_operator::op1_op2_relation;
+  bool fold_range (irange &r, tree type,
+		   const irange &op1, const irange &op2,
+		   relation_trio = TRIO_VARYING) const final override;
+  bool fold_range (irange &r, tree type,
+		   const frange &op1, const frange &op2,
+		   relation_trio rel = TRIO_VARYING) const final override;
+
+  bool op1_range (irange &r, tree type,
+		  const irange &lhs, const irange &op2,
+		  relation_trio = TRIO_VARYING) const final override;
+  bool op1_range (frange &r, tree type,
+		  const irange &lhs, const frange &op2,
+		  relation_trio = TRIO_VARYING) const final override;
+
+  bool op2_range (irange &r, tree type,
+		  const irange &lhs, const irange &op1,
+		  relation_trio = TRIO_VARYING) const final override;
+
+  relation_kind op1_op2_relation (const irange &lhs) const final override;
+  void update_bitmask (irange &r, const irange &lh,
+		       const irange &rh) const final override;
+};
+extern operator_not_equal rop_NE_EXPR;
+
 #endif // GCC_RANGE_OPERATOR_H
-- 
2.40.1

From d1fa32e07e175384ce099ed7f15735397af6cbc6 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacl...@redhat.com>
Date: Wed, 31 May 2023 10:55:28 -0400
Subject: [PATCH 01/11] Remove tree_code from range-operator.

range_operator had a tree code added last last release to facilitate
bitmask operations.  Remove the tree_code and repalce it with a virtual
routine to peform the masking.  Then remove any duplicate instances
which are no longer needed.

	* range-op.cc (range_operator::fold_range): Call virtual routine.
	(range_operator::update_bitmask): New.
	(operator_equal::update_bitmask): New.
	(operator_not_equal::update_bitmask): New.
	(operator_lt::update_bitmask): New.
	(operator_le::update_bitmask): New.
	(operator_gt::update_bitmask): New.
	(operator_ge::update_bitmask): New.
	(operator_ge::update_bitmask): New.
	(operator_plus::update_bitmask): New.
	(operator_minus::update_bitmask): New.
	(operator_pointer_diff::update_bitmask): New.
	(operator_min::update_bitmask): New.
	(operator_max::update_bitmask): New.
	(operator_mult::update_bitmask): New.
	(operator_div:operator_div):New.
	(operator_div::update_bitmask): New.
	(operator_div::m_code): New member.
	(operator_exact_divide::operator_exact_divide): New constructor.
	(operator_lshift::update_bitmask): New.
	(operator_rshift::update_bitmask): New.
	(operator_bitwise_and::update_bitmask): New.
	(operator_bitwise_or::update_bitmask): New.
	(operator_bitwise_xor::update_bitmask): New.
	(operator_trunc_mod::update_bitmask): New.
	(op_ident, op_unknown, op_ptr_min_max): New.
	(op_nop, op_convert): Delete.
	(op_ssa, op_paren, op_obj_type): Delete.
	(op_realpart, op_imagpart): Delete.
	(op_ptr_min, op_ptr_max): Delete.
	(pointer_plus_operator:update_bitmask): New.
	(range_op_table::set): Do not use m_code.
	(integral_table::integral_table): Adjust to single instances.
	* range-op.h (range_operator::range_operator): Delete.
	(range_operator::m_code): Delete.
	(range_operator::update_bitmask): New.
---
 gcc/range-op.cc | 110 +++++++++++++++++++++++++++++++++---------------
 gcc/range-op.h  |   6 +--
 2 files changed, 79 insertions(+), 37 deletions(-)

diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 3ab2c665901..2deca3bac93 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -286,7 +286,7 @@ range_operator::fold_range (irange &r, tree type,
 	    break;
 	}
       op1_op2_relation_effect (r, type, lh, rh, rel);
-      update_known_bitmask (r, m_code, lh, rh);
+      update_bitmask (r, lh, rh);
       return true;
     }
 
@@ -298,7 +298,7 @@ range_operator::fold_range (irange &r, tree type,
       wi_fold_in_parts (r, type, lh.lower_bound (), lh.upper_bound (),
 			rh.lower_bound (), rh.upper_bound ());
       op1_op2_relation_effect (r, type, lh, rh, rel);
-      update_known_bitmask (r, m_code, lh, rh);
+      update_bitmask (r, lh, rh);
       return true;
     }
 
@@ -316,12 +316,12 @@ range_operator::fold_range (irange &r, tree type,
 	if (r.varying_p ())
 	  {
 	    op1_op2_relation_effect (r, type, lh, rh, rel);
-	    update_known_bitmask (r, m_code, lh, rh);
+	    update_bitmask (r, lh, rh);
 	    return true;
 	  }
       }
   op1_op2_relation_effect (r, type, lh, rh, rel);
-  update_known_bitmask (r, m_code, lh, rh);
+  update_bitmask (r, lh, rh);
   return true;
 }
 
@@ -387,6 +387,14 @@ range_operator::op1_op2_relation_effect (irange &lhs_range ATTRIBUTE_UNUSED,
   return false;
 }
 
+// Apply any known bitmask updates based on this operator.
+
+void
+range_operator::update_bitmask (irange &, const irange &,
+				       const irange &) const
+{
+}
+
 // Create and return a range from a pair of wide-ints that are known
 // to have overflowed (or underflowed).
 
@@ -562,6 +570,8 @@ public:
 			  const irange &val,
 			  relation_trio = TRIO_VARYING) const;
   virtual relation_kind op1_op2_relation (const irange &lhs) const;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, EQ_EXPR, lh, rh); }
 } op_equal;
 
 // Check if the LHS range indicates a relation between OP1 and OP2.
@@ -682,6 +692,8 @@ public:
 			  const irange &op1,
 			  relation_trio = TRIO_VARYING) const;
   virtual relation_kind op1_op2_relation (const irange &lhs) const;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, NE_EXPR, lh, rh); }
 } op_not_equal;
 
 // Check if the LHS range indicates a relation between OP1 and OP2.
@@ -862,6 +874,8 @@ public:
 			  const irange &op1,
 			  relation_trio = TRIO_VARYING) const;
   virtual relation_kind op1_op2_relation (const irange &lhs) const;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, LT_EXPR, lh, rh); }
 } op_lt;
 
 // Check if the LHS range indicates a relation between OP1 and OP2.
@@ -982,6 +996,8 @@ public:
 			  const irange &op1,
 			  relation_trio = TRIO_VARYING) const;
   virtual relation_kind op1_op2_relation (const irange &lhs) const;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, LE_EXPR, lh, rh); }
 } op_le;
 
 // Check if the LHS range indicates a relation between OP1 and OP2.
@@ -1099,6 +1115,8 @@ public:
 			  const irange &op1,
 			  relation_trio = TRIO_VARYING) const;
   virtual relation_kind op1_op2_relation (const irange &lhs) const;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, GT_EXPR, lh, rh); }
 } op_gt;
 
 // Check if the LHS range indicates a relation between OP1 and OP2.
@@ -1215,6 +1233,8 @@ public:
 			  const irange &op1,
 			  relation_trio = TRIO_VARYING) const;
   virtual relation_kind op1_op2_relation (const irange &lhs) const;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, GE_EXPR, lh, rh); }
 } op_ge;
 
 // Check if the LHS range indicates a relation between OP1 and OP2.
@@ -1339,6 +1359,8 @@ public:
   virtual relation_kind lhs_op2_relation (const irange &lhs, const irange &op1,
 					  const irange &op2,
 					  relation_kind rel) const;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, PLUS_EXPR, lh, rh); }
 } op_plus;
 
 // Check to see if the range of OP2 indicates anything about the relation
@@ -1648,6 +1670,8 @@ public:
 					const irange &op1_range,
 					const irange &op2_range,
 					relation_kind rel) const;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, MINUS_EXPR, lh, rh); }
 } op_minus;
 
 void 
@@ -1801,6 +1825,8 @@ class operator_pointer_diff : public range_operator
 					const irange &op1_range,
 					const irange &op2_range,
 					relation_kind rel) const;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, POINTER_DIFF_EXPR, lh, rh); }
 } op_pointer_diff;
 
 bool
@@ -1822,6 +1848,8 @@ public:
 		        const wide_int &lh_ub,
 		        const wide_int &rh_lb,
 		        const wide_int &rh_ub) const;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, MIN_EXPR, lh, rh); }
 } op_min;
 
 void
@@ -1844,6 +1872,8 @@ public:
 		        const wide_int &lh_ub,
 		        const wide_int &rh_lb,
 		        const wide_int &rh_ub) const;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, MAX_EXPR, lh, rh); }
 } op_max;
 
 void
@@ -1952,6 +1982,8 @@ public:
 			  const irange &lhs,
 			  const irange &op1,
 			  relation_trio) const final override;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, MULT_EXPR, lh, rh); }
 } op_mult;
 
 bool
@@ -2162,6 +2194,7 @@ operator_widen_mult_unsigned::wi_fold (irange &r, tree type,
 class operator_div : public cross_product_operator
 {
 public:
+  operator_div (tree_code div_kind) { m_code = div_kind; }
   virtual void wi_fold (irange &r, tree type,
 		        const wide_int &lh_lb,
 		        const wide_int &lh_ub,
@@ -2170,8 +2203,17 @@ public:
   virtual bool wi_op_overflows (wide_int &res, tree type,
 				const wide_int &, const wide_int &)
     const final override;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, m_code, lh, rh); }
+protected:
+  tree_code m_code;
 };
 
+static operator_div op_trunc_div (TRUNC_DIV_EXPR);
+static operator_div op_floor_div (FLOOR_DIV_EXPR);
+static operator_div op_round_div (ROUND_DIV_EXPR);
+static operator_div op_ceil_div (CEIL_DIV_EXPR);
+
 bool
 operator_div::wi_op_overflows (wide_int &res, tree type,
 			       const wide_int &w0, const wide_int &w1) const
@@ -2265,6 +2307,7 @@ class operator_exact_divide : public operator_div
 {
   using range_operator::op1_range;
 public:
+  operator_exact_divide () : operator_div (EXACT_DIV_EXPR) { }
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op2,
@@ -2314,6 +2357,8 @@ public:
 				tree type,
 				const wide_int &,
 				const wide_int &) const;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, LSHIFT_EXPR, lh, rh); }
 } op_lshift;
 
 class operator_rshift : public cross_product_operator
@@ -2343,6 +2388,8 @@ public:
 					   const irange &op1,
 					   const irange &op2,
 					   relation_kind rel) const;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, RSHIFT_EXPR, lh, rh); }
 } op_rshift;
 
 
@@ -2682,7 +2729,7 @@ private:
 			const irange &outer) const;
   void fold_pair (irange &r, unsigned index, const irange &inner,
 			   const irange &outer) const;
-};
+} op_cast;
 
 // Add a partial equivalence between the LHS and op1 for casts.
 
@@ -3026,6 +3073,8 @@ public:
 					  const irange &op1,
 					  const irange &op2,
 					  relation_kind) const;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, BIT_AND_EXPR, lh, rh); }
 private:
   void simple_op1_range_solver (irange &r, tree type,
 				const irange &lhs,
@@ -3524,6 +3573,8 @@ public:
 		        const wide_int &lh_ub,
 		        const wide_int &rh_lb,
 		        const wide_int &rh_ub) const;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, BIT_IOR_EXPR, lh, rh); }
 } op_bitwise_or;
 
 void
@@ -3636,6 +3687,8 @@ public:
 					const irange &op1_range,
 					const irange &op2_range,
 					relation_kind rel) const;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, BIT_XOR_EXPR, lh, rh); }
 } op_bitwise_xor;
 
 void
@@ -3777,6 +3830,8 @@ public:
 			  const irange &lhs,
 			  const irange &op1,
 			  relation_trio) const;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, TRUNC_MOD_EXPR, lh, rh); }
 } op_trunc_mod;
 
 void
@@ -4046,7 +4101,7 @@ public:
 					   const irange &op1,
 					   const irange &op2,
 					   relation_kind rel) const;
-};
+} op_ident;
 
 // Determine if there is a relationship between LHS and OP1.
 
@@ -4091,7 +4146,7 @@ public:
 			   const irange &op1,
 			   const irange &op2,
 			   relation_trio rel = TRIO_VARYING) const;
-};
+} op_unknown;
 
 bool
 operator_unknown::fold_range (irange &r, tree type,
@@ -4365,6 +4420,8 @@ public:
 			  const irange &lhs,
 			  const irange &op1,
 			  relation_trio = TRIO_VARYING) const;
+  void update_bitmask (irange &r, const irange &lh, const irange &rh) const
+    { update_known_bitmask (r, POINTER_PLUS_EXPR, lh, rh); }
 } op_pointer_plus;
 
 void
@@ -4436,7 +4493,7 @@ public:
   virtual void wi_fold (irange & r, tree type,
 			const wide_int &lh_lb, const wide_int &lh_ub,
 			const wide_int &rh_lb, const wide_int &rh_ub) const;
-};
+} op_ptr_min_max;
 
 void
 pointer_min_max_operator::wi_fold (irange &r, tree type,
@@ -4562,21 +4619,8 @@ range_op_table::set (enum tree_code code, range_operator &op)
 {
   gcc_checking_assert (m_range_tree[code] == NULL);
   m_range_tree[code] = &op;
-  gcc_checking_assert (op.m_code == ERROR_MARK || op.m_code == code);
-  op.m_code = code;
 }
 
-// Shared operators that require separate instantiations because they
-// do not share a common tree code.
-static operator_cast op_nop, op_convert;
-static operator_identity op_ssa, op_paren, op_obj_type;
-static operator_unknown op_realpart, op_imagpart;
-static pointer_min_max_operator op_ptr_min, op_ptr_max;
-static operator_div op_trunc_div;
-static operator_div op_floor_div;
-static operator_div op_round_div;
-static operator_div op_ceil_div;
-
 // Instantiate a range op table for integral operations.
 
 class integral_table : public range_op_table
@@ -4605,8 +4649,8 @@ integral_table::integral_table ()
   set (EXACT_DIV_EXPR, op_exact_div);
   set (LSHIFT_EXPR, op_lshift);
   set (RSHIFT_EXPR, op_rshift);
-  set (NOP_EXPR, op_nop);
-  set (CONVERT_EXPR, op_convert);
+  set (NOP_EXPR, op_cast);
+  set (CONVERT_EXPR, op_cast);
   set (TRUTH_AND_EXPR, op_logical_and);
   set (BIT_AND_EXPR, op_bitwise_and);
   set (TRUTH_OR_EXPR, op_logical_or);
@@ -4616,11 +4660,11 @@ integral_table::integral_table ()
   set (TRUTH_NOT_EXPR, op_logical_not);
   set (BIT_NOT_EXPR, op_bitwise_not);
   set (INTEGER_CST, op_integer_cst);
-  set (SSA_NAME, op_ssa);
-  set (PAREN_EXPR, op_paren);
-  set (OBJ_TYPE_REF, op_obj_type);
-  set (IMAGPART_EXPR, op_imagpart);
-  set (REALPART_EXPR, op_realpart);
+  set (SSA_NAME, op_ident);
+  set (PAREN_EXPR, op_ident);
+  set (OBJ_TYPE_REF, op_ident);
+  set (IMAGPART_EXPR, op_unknown);
+  set (REALPART_EXPR, op_unknown);
   set (POINTER_DIFF_EXPR, op_pointer_diff);
   set (ABS_EXPR, op_abs);
   set (ABSU_EXPR, op_absu);
@@ -4640,8 +4684,8 @@ pointer_table::pointer_table ()
 {
   set (BIT_AND_EXPR, op_pointer_and);
   set (BIT_IOR_EXPR, op_pointer_or);
-  set (MIN_EXPR, op_ptr_min);
-  set (MAX_EXPR, op_ptr_max);
+  set (MIN_EXPR, op_ptr_min_max);
+  set (MAX_EXPR, op_ptr_min_max);
   set (POINTER_PLUS_EXPR, op_pointer_plus);
 
   set (EQ_EXPR, op_equal);
@@ -4650,11 +4694,11 @@ pointer_table::pointer_table ()
   set (LE_EXPR, op_le);
   set (GT_EXPR, op_gt);
   set (GE_EXPR, op_ge);
-  set (SSA_NAME, op_ssa);
+  set (SSA_NAME, op_ident);
   set (INTEGER_CST, op_integer_cst);
   set (ADDR_EXPR, op_addr);
-  set (NOP_EXPR, op_nop);
-  set (CONVERT_EXPR, op_convert);
+  set (NOP_EXPR, op_cast);
+  set (CONVERT_EXPR, op_cast);
 
   set (BIT_NOT_EXPR, op_bitwise_not);
   set (BIT_XOR_EXPR, op_bitwise_xor);
diff --git a/gcc/range-op.h b/gcc/range-op.h
index 03ef6b98542..5bfbc89df52 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -50,7 +50,6 @@ class range_operator
 {
   friend class range_op_table;
 public:
-  range_operator () : m_code (ERROR_MARK) { }
   // Perform an operation between 2 ranges and return it.
   virtual bool fold_range (irange &r, tree type,
 			   const irange &lh,
@@ -114,9 +113,8 @@ protected:
 			       const wide_int &lb,
 			       const wide_int &ub,
 			       unsigned limit) const;
-
-  // Tree code of the range operator or ERROR_MARK if unknown.
-  tree_code m_code;
+  // Apply any bitmasks implied by these ranges.
+  virtual void update_bitmask (irange &, const irange &, const irange &) const;
 };
 
 // Like range_operator above, but for floating point operators.
-- 
2.40.1

From 9123f53a88d63e125132d016757321c3334fe62b Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacl...@redhat.com>
Date: Wed, 31 May 2023 12:31:53 -0400
Subject: [PATCH 02/11] Unify raneg_operators to one class.

range_operator and range_operator_float are 2 different classes, making
generlized dispatch difficult.  The distinction between what is a float
operator and what is an integral operator also blurs when some methods
have multiple types.  ie, casts : INT = FLOAT and FLOAT = INT

This patch unified all possible invocation patterns in one class, and
switches the float table to use the general range_op_table.

	* gimple-range-op.cc (cfn_constant_float_p): Change base class.
	(cfn_pass_through_arg1): Adjust using statemenmt.
	(cfn_signbit): Change base class, adjust using statement.
	(cfn_copysign): Ditto.
	(cfn_sqrt): Ditto.
	(cfn_sincos): Ditto.
	* range-op-float.cc (fold_range): Change class to range_operator.
	(rv_fold): Ditto.
	(op1_range): Ditto
	(op2_range): Ditto
	(lhs_op1_relation): Ditto.
	(lhs_op2_relation): Ditto.
	(op1_op2_relation): Ditto.
	(foperator_*): Ditto.
	(class float_table): New.  Inherit from range_op_table.
	(floating_tree_table) Change to range_op_table pointer.
	(class floating_op_table): Delete.
	* range-op.cc (operator_equal): Adjust using statement.
	(operator_not_equal): Ditto.
	(operator_lt, operator_le, operator_gt, operator_ge): Ditto.
	(operator_minus, operator_cast): Ditto.
	(operator_bitwise_and, pointer_plus_operator): Ditto.
	(get_float_handler): Change return type.
	* range-op.h (range_operator_float): Delete. Relocate all methods
	into class range_operator.
	(range_op_handler::m_float): Change type to range_operator.
	(floating_op_table): Delete.
	(floating_tree_table): Change type.
---
 gcc/gimple-range-op.cc |  27 ++---
 gcc/range-op-float.cc  | 222 +++++++++++++++++++----------------------
 gcc/range-op.cc        |  12 ++-
 gcc/range-op.h         | 124 +++++++++++------------
 4 files changed, 183 insertions(+), 202 deletions(-)

diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 594bd3043f0..0c32a1d2859 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -268,10 +268,10 @@ gimple_range_op_handler::calc_op2 (vrange &r, const vrange &lhs_range,
 // --------------------------------------------------------------------
 
 // Implement range operator for float CFN_BUILT_IN_CONSTANT_P.
-class cfn_constant_float_p : public range_operator_float
+class cfn_constant_float_p : public range_operator
 {
 public:
-  using range_operator_float::fold_range;
+  using range_operator::fold_range;
   virtual bool fold_range (irange &r, tree type, const frange &lh,
 			   const irange &, relation_trio) const
   {
@@ -319,6 +319,7 @@ class cfn_pass_through_arg1 : public range_operator
 {
 public:
   using range_operator::fold_range;
+  using range_operator::op1_range;
   virtual bool fold_range (irange &r, tree, const irange &lh,
 			   const irange &, relation_trio) const
   {
@@ -334,11 +335,11 @@ public:
 } op_cfn_pass_through_arg1;
 
 // Implement range operator for CFN_BUILT_IN_SIGNBIT.
-class cfn_signbit : public range_operator_float
+class cfn_signbit : public range_operator
 {
 public:
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
   virtual bool fold_range (irange &r, tree type, const frange &lh,
 			   const irange &, relation_trio) const override
   {
@@ -373,10 +374,10 @@ public:
 } op_cfn_signbit;
 
 // Implement range operator for CFN_BUILT_IN_COPYSIGN
-class cfn_copysign : public range_operator_float
+class cfn_copysign : public range_operator
 {
 public:
-  using range_operator_float::fold_range;
+  using range_operator::fold_range;
   virtual bool fold_range (frange &r, tree type, const frange &lh,
 			   const frange &rh, relation_trio) const override
   {
@@ -464,11 +465,11 @@ frange_mpfr_arg1 (REAL_VALUE_TYPE *res_low, REAL_VALUE_TYPE *res_high,
   return true;
 }
 
-class cfn_sqrt : public range_operator_float
+class cfn_sqrt : public range_operator
 {
 public:
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
   virtual bool fold_range (frange &r, tree type,
 			   const frange &lh, const frange &,
 			   relation_trio) const final override
@@ -599,11 +600,11 @@ public:
   }
 } op_cfn_sqrt;
 
-class cfn_sincos : public range_operator_float
+class cfn_sincos : public range_operator
 {
 public:
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
   cfn_sincos (combined_fn cfn) { m_cfn = cfn; }
   virtual bool fold_range (frange &r, tree type,
 			   const frange &lh, const frange &,
diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index a99a6b01ed8..faa8c439e51 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -49,7 +49,7 @@ along with GCC; see the file COPYING3.  If not see
 // Default definitions for floating point operators.
 
 bool
-range_operator_float::fold_range (frange &r, tree type,
+range_operator::fold_range (frange &r, tree type,
 				  const frange &op1, const frange &op2,
 				  relation_trio trio) const
 {
@@ -121,7 +121,7 @@ range_operator_float::fold_range (frange &r, tree type,
 // MAYBE_NAN is set to TRUE if, in addition to any result in LB or
 // UB, the final range has the possibility of a NAN.
 void
-range_operator_float::rv_fold (REAL_VALUE_TYPE &lb,
+range_operator::rv_fold (REAL_VALUE_TYPE &lb,
 			       REAL_VALUE_TYPE &ub,
 			       bool &maybe_nan,
 			       tree type ATTRIBUTE_UNUSED,
@@ -137,7 +137,7 @@ range_operator_float::rv_fold (REAL_VALUE_TYPE &lb,
 }
 
 bool
-range_operator_float::fold_range (irange &r ATTRIBUTE_UNUSED,
+range_operator::fold_range (irange &r ATTRIBUTE_UNUSED,
 				  tree type ATTRIBUTE_UNUSED,
 				  const frange &lh ATTRIBUTE_UNUSED,
 				  const irange &rh ATTRIBUTE_UNUSED,
@@ -147,7 +147,7 @@ range_operator_float::fold_range (irange &r ATTRIBUTE_UNUSED,
 }
 
 bool
-range_operator_float::fold_range (irange &r ATTRIBUTE_UNUSED,
+range_operator::fold_range (irange &r ATTRIBUTE_UNUSED,
 				  tree type ATTRIBUTE_UNUSED,
 				  const frange &lh ATTRIBUTE_UNUSED,
 				  const frange &rh ATTRIBUTE_UNUSED,
@@ -157,7 +157,7 @@ range_operator_float::fold_range (irange &r ATTRIBUTE_UNUSED,
 }
 
 bool
-range_operator_float::op1_range (frange &r ATTRIBUTE_UNUSED,
+range_operator::op1_range (frange &r ATTRIBUTE_UNUSED,
 				 tree type ATTRIBUTE_UNUSED,
 				 const frange &lhs ATTRIBUTE_UNUSED,
 				 const frange &op2 ATTRIBUTE_UNUSED,
@@ -167,7 +167,7 @@ range_operator_float::op1_range (frange &r ATTRIBUTE_UNUSED,
 }
 
 bool
-range_operator_float::op1_range (frange &r ATTRIBUTE_UNUSED,
+range_operator::op1_range (frange &r ATTRIBUTE_UNUSED,
 				 tree type ATTRIBUTE_UNUSED,
 				 const irange &lhs ATTRIBUTE_UNUSED,
 				 const frange &op2 ATTRIBUTE_UNUSED,
@@ -177,7 +177,7 @@ range_operator_float::op1_range (frange &r ATTRIBUTE_UNUSED,
 }
 
 bool
-range_operator_float::op2_range (frange &r ATTRIBUTE_UNUSED,
+range_operator::op2_range (frange &r ATTRIBUTE_UNUSED,
 				 tree type ATTRIBUTE_UNUSED,
 				 const frange &lhs ATTRIBUTE_UNUSED,
 				 const frange &op1 ATTRIBUTE_UNUSED,
@@ -187,7 +187,7 @@ range_operator_float::op2_range (frange &r ATTRIBUTE_UNUSED,
 }
 
 bool
-range_operator_float::op2_range (frange &r ATTRIBUTE_UNUSED,
+range_operator::op2_range (frange &r ATTRIBUTE_UNUSED,
 				 tree type ATTRIBUTE_UNUSED,
 				 const irange &lhs ATTRIBUTE_UNUSED,
 				 const frange &op1 ATTRIBUTE_UNUSED,
@@ -197,7 +197,7 @@ range_operator_float::op2_range (frange &r ATTRIBUTE_UNUSED,
 }
 
 relation_kind
-range_operator_float::lhs_op1_relation (const frange &lhs ATTRIBUTE_UNUSED,
+range_operator::lhs_op1_relation (const frange &lhs ATTRIBUTE_UNUSED,
 					const frange &op1 ATTRIBUTE_UNUSED,
 					const frange &op2 ATTRIBUTE_UNUSED,
 					relation_kind) const
@@ -206,7 +206,7 @@ range_operator_float::lhs_op1_relation (const frange &lhs ATTRIBUTE_UNUSED,
 }
 
 relation_kind
-range_operator_float::lhs_op1_relation (const irange &lhs ATTRIBUTE_UNUSED,
+range_operator::lhs_op1_relation (const irange &lhs ATTRIBUTE_UNUSED,
 					const frange &op1 ATTRIBUTE_UNUSED,
 					const frange &op2 ATTRIBUTE_UNUSED,
 					relation_kind) const
@@ -215,7 +215,7 @@ range_operator_float::lhs_op1_relation (const irange &lhs ATTRIBUTE_UNUSED,
 }
 
 relation_kind
-range_operator_float::lhs_op2_relation (const irange &lhs ATTRIBUTE_UNUSED,
+range_operator::lhs_op2_relation (const irange &lhs ATTRIBUTE_UNUSED,
 					const frange &op1 ATTRIBUTE_UNUSED,
 					const frange &op2 ATTRIBUTE_UNUSED,
 					relation_kind) const
@@ -224,7 +224,7 @@ range_operator_float::lhs_op2_relation (const irange &lhs ATTRIBUTE_UNUSED,
 }
 
 relation_kind
-range_operator_float::lhs_op2_relation (const frange &lhs ATTRIBUTE_UNUSED,
+range_operator::lhs_op2_relation (const frange &lhs ATTRIBUTE_UNUSED,
 					const frange &op1 ATTRIBUTE_UNUSED,
 					const frange &op2 ATTRIBUTE_UNUSED,
 					relation_kind) const
@@ -233,13 +233,7 @@ range_operator_float::lhs_op2_relation (const frange &lhs ATTRIBUTE_UNUSED,
 }
 
 relation_kind
-range_operator_float::op1_op2_relation (const irange &lhs ATTRIBUTE_UNUSED) const
-{
-  return VREL_VARYING;
-}
-
-relation_kind
-range_operator_float::op1_op2_relation (const frange &lhs ATTRIBUTE_UNUSED) const
+range_operator::op1_op2_relation (const frange &lhs ATTRIBUTE_UNUSED) const
 {
   return VREL_VARYING;
 }
@@ -546,10 +540,10 @@ build_gt (frange &r, tree type, const frange &val)
 }
 
 
-class foperator_identity : public range_operator_float
+class foperator_identity : public range_operator
 {
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
 public:
   bool fold_range (frange &r, tree type ATTRIBUTE_UNUSED,
 		   const frange &op1, const frange &op2 ATTRIBUTE_UNUSED,
@@ -568,12 +562,12 @@ public:
 public:
 } fop_identity;
 
-class foperator_equal : public range_operator_float
+class foperator_equal : public range_operator
 {
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
-  using range_operator_float::op2_range;
-  using range_operator_float::op1_op2_relation;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
+  using range_operator::op1_op2_relation;
 public:
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
@@ -697,11 +691,11 @@ foperator_equal::op1_range (frange &r, tree type,
   return true;
 }
 
-class foperator_not_equal : public range_operator_float
+class foperator_not_equal : public range_operator
 {
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
-  using range_operator_float::op1_op2_relation;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op1_op2_relation;
 public:
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
@@ -819,12 +813,12 @@ foperator_not_equal::op1_range (frange &r, tree type,
   return true;
 }
 
-class foperator_lt : public range_operator_float
+class foperator_lt : public range_operator
 {
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
-  using range_operator_float::op2_range;
-  using range_operator_float::op1_op2_relation;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
+  using range_operator::op1_op2_relation;
 public:
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
@@ -935,12 +929,12 @@ foperator_lt::op2_range (frange &r,
   return true;
 }
 
-class foperator_le : public range_operator_float
+class foperator_le : public range_operator
 {
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
-  using range_operator_float::op2_range;
-  using range_operator_float::op1_op2_relation;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
+  using range_operator::op1_op2_relation;
 public:
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
@@ -1045,12 +1039,12 @@ foperator_le::op2_range (frange &r,
   return true;
 }
 
-class foperator_gt : public range_operator_float
+class foperator_gt : public range_operator
 {
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
-  using range_operator_float::op2_range;
-  using range_operator_float::op1_op2_relation;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
+  using range_operator::op1_op2_relation;
 public:
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
@@ -1165,12 +1159,12 @@ foperator_gt::op2_range (frange &r,
   return true;
 }
 
-class foperator_ge : public range_operator_float
+class foperator_ge : public range_operator
 {
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
-  using range_operator_float::op2_range;
-  using range_operator_float::op1_op2_relation;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
+  using range_operator::op1_op2_relation;
 public:
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
@@ -1278,11 +1272,11 @@ foperator_ge::op2_range (frange &r, tree type,
 
 // UNORDERED_EXPR comparison.
 
-class foperator_unordered : public range_operator_float
+class foperator_unordered : public range_operator
 {
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
-  using range_operator_float::op2_range;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
@@ -1352,11 +1346,11 @@ foperator_unordered::op1_range (frange &r, tree type,
 
 // ORDERED_EXPR comparison.
 
-class foperator_ordered : public range_operator_float
+class foperator_ordered : public range_operator
 {
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
-  using range_operator_float::op2_range;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
@@ -1421,10 +1415,10 @@ foperator_ordered::op1_range (frange &r, tree type,
   return true;
 }
 
-class foperator_negate : public range_operator_float
+class foperator_negate : public range_operator
 {
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
 public:
   bool fold_range (frange &r, tree type,
 		   const frange &op1, const frange &op2,
@@ -1467,10 +1461,10 @@ public:
   }
 } fop_negate;
 
-class foperator_abs : public range_operator_float
+class foperator_abs : public range_operator
 {
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
 public:
   bool fold_range (frange &r, tree type,
 		   const frange &op1, const frange &,
@@ -1566,11 +1560,11 @@ foperator_abs::op1_range (frange &r, tree type,
   return true;
 }
 
-class foperator_unordered_lt : public range_operator_float
+class foperator_unordered_lt : public range_operator
 {
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
-  using range_operator_float::op2_range;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
@@ -1677,11 +1671,11 @@ foperator_unordered_lt::op2_range (frange &r, tree type,
   return true;
 }
 
-class foperator_unordered_le : public range_operator_float
+class foperator_unordered_le : public range_operator
 {
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
-  using range_operator_float::op2_range;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
@@ -1784,11 +1778,11 @@ foperator_unordered_le::op2_range (frange &r,
   return true;
 }
 
-class foperator_unordered_gt : public range_operator_float
+class foperator_unordered_gt : public range_operator
 {
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
-  using range_operator_float::op2_range;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
@@ -1895,11 +1889,11 @@ foperator_unordered_gt::op2_range (frange &r,
   return true;
 }
 
-class foperator_unordered_ge : public range_operator_float
+class foperator_unordered_ge : public range_operator
 {
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
-  using range_operator_float::op2_range;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
@@ -2005,11 +1999,11 @@ foperator_unordered_ge::op2_range (frange &r, tree type,
   return true;
 }
 
-class foperator_unordered_equal : public range_operator_float
+class foperator_unordered_equal : public range_operator
 {
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
-  using range_operator_float::op2_range;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
@@ -2086,11 +2080,11 @@ foperator_unordered_equal::op1_range (frange &r, tree type,
   return true;
 }
 
-class foperator_ltgt : public range_operator_float
+class foperator_ltgt : public range_operator
 {
-  using range_operator_float::fold_range;
-  using range_operator_float::op1_range;
-  using range_operator_float::op2_range;
+  using range_operator::fold_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   bool fold_range (irange &r, tree type,
 		   const frange &op1, const frange &op2,
@@ -2374,10 +2368,10 @@ float_widen_lhs_range (tree type, const frange &lhs)
   return ret;
 }
 
-class foperator_plus : public range_operator_float
+class foperator_plus : public range_operator
 {
-  using range_operator_float::op1_range;
-  using range_operator_float::op2_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool op1_range (frange &r, tree type,
 			  const frange &lhs,
@@ -2424,10 +2418,10 @@ private:
 } fop_plus;
 
 
-class foperator_minus : public range_operator_float
+class foperator_minus : public range_operator
 {
-  using range_operator_float::op1_range;
-  using range_operator_float::op2_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool op1_range (frange &r, tree type,
 			  const frange &lhs,
@@ -2476,7 +2470,7 @@ private:
 } fop_minus;
 
 
-class foperator_mult_div_base : public range_operator_float
+class foperator_mult_div_base : public range_operator
 {
 protected:
   // Given CP[0] to CP[3] floating point values rounded to -INF,
@@ -2503,8 +2497,8 @@ protected:
 
 class foperator_mult : public foperator_mult_div_base
 {
-  using range_operator_float::op1_range;
-  using range_operator_float::op2_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool op1_range (frange &r, tree type,
 			  const frange &lhs,
@@ -2659,8 +2653,8 @@ private:
 
 class foperator_div : public foperator_mult_div_base
 {
-  using range_operator_float::op1_range;
-  using range_operator_float::op2_range;
+  using range_operator::op1_range;
+  using range_operator::op2_range;
 public:
   virtual bool op1_range (frange &r, tree type,
 			  const frange &lhs,
@@ -2814,12 +2808,16 @@ private:
 } fop_div;
 
 // Instantiate a range_op_table for floating point operations.
-static floating_op_table global_floating_table;
+class float_table : public range_op_table
+{
+  public:
+    float_table ();
+} global_floating_table;
 
 // Pointer to the float table so the dispatch code can access it.
-floating_op_table *floating_tree_table = &global_floating_table;
+range_op_table *floating_tree_table = &global_floating_table;
 
-floating_op_table::floating_op_table ()
+float_table::float_table ()
 {
   set (SSA_NAME, fop_identity);
   set (PAREN_EXPR, fop_identity);
@@ -2852,24 +2850,6 @@ floating_op_table::floating_op_table ()
   set (RDIV_EXPR, fop_div);
 }
 
-// Return a pointer to the range_operator_float instance, if there is
-// one associated with tree_code CODE.
-
-range_operator_float *
-floating_op_table::operator[] (enum tree_code code)
-{
-  return m_range_tree[code];
-}
-
-// Add OP to the handler table for CODE.
-
-void
-floating_op_table::set (enum tree_code code, range_operator_float &op)
-{
-  gcc_checking_assert (m_range_tree[code] == NULL);
-  m_range_tree[code] = &op;
-}
-
 #if CHECKING_P
 #include "selftest.h"
 
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 2deca3bac93..203c30f6e94 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -556,6 +556,7 @@ class operator_equal : public range_operator
   using range_operator::fold_range;
   using range_operator::op1_range;
   using range_operator::op2_range;
+  using range_operator::op1_op2_relation;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -678,6 +679,7 @@ class operator_not_equal : public range_operator
   using range_operator::fold_range;
   using range_operator::op1_range;
   using range_operator::op2_range;
+  using range_operator::op1_op2_relation;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -860,6 +862,7 @@ class operator_lt :  public range_operator
   using range_operator::fold_range;
   using range_operator::op1_range;
   using range_operator::op2_range;
+  using range_operator::op1_op2_relation;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -982,6 +985,7 @@ class operator_le :  public range_operator
   using range_operator::fold_range;
   using range_operator::op1_range;
   using range_operator::op2_range;
+  using range_operator::op1_op2_relation;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -1101,6 +1105,7 @@ class operator_gt :  public range_operator
   using range_operator::fold_range;
   using range_operator::op1_range;
   using range_operator::op2_range;
+  using range_operator::op1_op2_relation;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -1219,6 +1224,7 @@ class operator_ge :  public range_operator
   using range_operator::fold_range;
   using range_operator::op1_range;
   using range_operator::op2_range;
+  using range_operator::op1_op2_relation;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -1647,6 +1653,7 @@ class operator_minus : public range_operator
   using range_operator::fold_range;
   using range_operator::op1_range;
   using range_operator::op2_range;
+  using range_operator::lhs_op1_relation;
 public:
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
@@ -2710,6 +2717,7 @@ class operator_cast: public range_operator
 {
   using range_operator::fold_range;
   using range_operator::op1_range;
+  using range_operator::lhs_op1_relation;
 public:
   virtual bool fold_range (irange &r, tree type,
 			   const irange &op1,
@@ -3055,6 +3063,7 @@ class operator_bitwise_and : public range_operator
 {
   using range_operator::op1_range;
   using range_operator::op2_range;
+  using range_operator::lhs_op1_relation;
 public:
   virtual bool op1_range (irange &r, tree type,
 			  const irange &lhs,
@@ -4410,6 +4419,7 @@ operator_addr_expr::op1_range (irange &r, tree type,
 
 class pointer_plus_operator : public range_operator
 {
+  using range_operator::op2_range;
 public:
   virtual void wi_fold (irange &r, tree type,
 		        const wide_int &lh_lb,
@@ -4719,7 +4729,7 @@ get_handler (enum tree_code code, tree type)
 
 // Return the floating point operator for CODE or NULL if none available.
 
-static inline range_operator_float *
+static inline range_operator *
 get_float_handler (enum tree_code code, tree)
 {
   return (*floating_tree_table)[code];
diff --git a/gcc/range-op.h b/gcc/range-op.h
index 5bfbc89df52..cad16f4cd20 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -45,6 +45,11 @@ along with GCC; see the file COPYING3.  If not see
 //     non-zero.  This is mostly for logical true false, but can serve other
 //     purposes.
 //       ie   0 = op1 - op2 implies op2 has the same range as op1.
+//
+// 4 - All supported range combinations are explicitly specified.
+//     Any desired combinations should be implemented for each operator.
+//     When new range classes are added, new matching prototypes should be
+//     added.
 
 class range_operator
 {
@@ -55,6 +60,18 @@ public:
 			   const irange &lh,
 			   const irange &rh,
 			   relation_trio = TRIO_VARYING) const;
+  virtual bool fold_range (frange &r, tree type,
+			   const frange &lh,
+			   const frange &rh,
+			   relation_trio = TRIO_VARYING) const;
+  virtual bool fold_range (irange &r, tree type,
+			   const frange &lh,
+			   const irange &rh,
+			   relation_trio = TRIO_VARYING) const;
+  virtual bool fold_range (irange &r, tree type,
+			   const frange &lh,
+			   const frange &rh,
+			   relation_trio = TRIO_VARYING) const;
 
   // Return the range for op[12] in the general case.  LHS is the range for
   // the LHS of the expression, OP[12]is the range for the other
@@ -71,10 +88,28 @@ public:
 			  const irange &lhs,
 			  const irange &op2,
 			  relation_trio = TRIO_VARYING) const;
+  virtual bool op1_range (frange &r, tree type,
+			  const frange &lhs,
+			  const frange &op2,
+			  relation_trio = TRIO_VARYING) const;
+  virtual bool op1_range (frange &r, tree type,
+			  const irange &lhs,
+			  const frange &op2,
+			  relation_trio = TRIO_VARYING) const;
+
+
   virtual bool op2_range (irange &r, tree type,
 			  const irange &lhs,
 			  const irange &op1,
 			  relation_trio = TRIO_VARYING) const;
+  virtual bool op2_range (frange &r, tree type,
+			  const frange &lhs,
+			  const frange &op1,
+			  relation_trio = TRIO_VARYING) const;
+  virtual bool op2_range (frange &r, tree type,
+			  const irange &lhs,
+			  const frange &op1,
+			  relation_trio = TRIO_VARYING) const;
 
   // The following routines are used to represent relations between the
   // various operations.  If the caller knows where the symbolics are,
@@ -84,11 +119,30 @@ public:
 					  const irange &op1,
 					  const irange &op2,
 					  relation_kind = VREL_VARYING) const;
+  virtual relation_kind lhs_op1_relation (const frange &lhs,
+					  const frange &op1,
+					  const frange &op2,
+					  relation_kind = VREL_VARYING) const;
+  virtual relation_kind lhs_op1_relation (const irange &lhs,
+					  const frange &op1,
+					  const frange &op2,
+					  relation_kind = VREL_VARYING) const;
+
   virtual relation_kind lhs_op2_relation (const irange &lhs,
 					  const irange &op1,
 					  const irange &op2,
 					  relation_kind = VREL_VARYING) const;
+  virtual relation_kind lhs_op2_relation (const frange &lhs,
+					  const frange &op1,
+					  const frange &op2,
+					  relation_kind = VREL_VARYING) const;
+  virtual relation_kind lhs_op2_relation (const irange &lhs,
+					  const frange &op1,
+					  const frange &op2,
+					  relation_kind = VREL_VARYING) const;
+
   virtual relation_kind op1_op2_relation (const irange &lhs) const;
+  virtual relation_kind op1_op2_relation (const frange &lhs) const;
 protected:
   // Perform an integral operation between 2 sub-ranges and return it.
   virtual void wi_fold (irange &r, tree type,
@@ -115,17 +169,8 @@ protected:
 			       unsigned limit) const;
   // Apply any bitmasks implied by these ranges.
   virtual void update_bitmask (irange &, const irange &, const irange &) const;
-};
-
-// Like range_operator above, but for floating point operators.
 
-class range_operator_float
-{
-public:
-  virtual bool fold_range (frange &r, tree type,
-			   const frange &lh,
-			   const frange &rh,
-			   relation_trio = TRIO_VARYING) const;
+  // Perform an float operation between 2 ranges and return it.
   virtual void rv_fold (REAL_VALUE_TYPE &lb, REAL_VALUE_TYPE &ub,
 			bool &maybe_nan,
 			tree type,
@@ -134,50 +179,6 @@ public:
 			const REAL_VALUE_TYPE &rh_lb,
 			const REAL_VALUE_TYPE &rh_ub,
 			relation_kind) const;
-  // Unary operations have the range of the LHS as op2.
-  virtual bool fold_range (irange &r, tree type,
-			   const frange &lh,
-			   const irange &rh,
-			   relation_trio = TRIO_VARYING) const;
-  virtual bool fold_range (irange &r, tree type,
-			   const frange &lh,
-			   const frange &rh,
-			   relation_trio = TRIO_VARYING) const;
-  virtual bool op1_range (frange &r, tree type,
-			  const frange &lhs,
-			  const frange &op2,
-			  relation_trio = TRIO_VARYING) const;
-  virtual bool op1_range (frange &r, tree type,
-			  const irange &lhs,
-			  const frange &op2,
-			  relation_trio = TRIO_VARYING) const;
-  virtual bool op2_range (frange &r, tree type,
-			  const frange &lhs,
-			  const frange &op1,
-			  relation_trio = TRIO_VARYING) const;
-  virtual bool op2_range (frange &r, tree type,
-			  const irange &lhs,
-			  const frange &op1,
-			  relation_trio = TRIO_VARYING) const;
-
-  virtual relation_kind lhs_op1_relation (const frange &lhs,
-					  const frange &op1,
-					  const frange &op2,
-					  relation_kind = VREL_VARYING) const;
-  virtual relation_kind lhs_op1_relation (const irange &lhs,
-					  const frange &op1,
-					  const frange &op2,
-					  relation_kind = VREL_VARYING) const;
-  virtual relation_kind lhs_op2_relation (const frange &lhs,
-					  const frange &op1,
-					  const frange &op2,
-					  relation_kind = VREL_VARYING) const;
-  virtual relation_kind lhs_op2_relation (const irange &lhs,
-					  const frange &op1,
-					  const frange &op2,
-					  relation_kind = VREL_VARYING) const;
-  virtual relation_kind op1_op2_relation (const irange &lhs) const;
-  virtual relation_kind op1_op2_relation (const frange &lhs) const;
 };
 
 class range_op_handler
@@ -212,7 +213,7 @@ protected:
   void set_op_handler (enum tree_code code, tree type);
   bool m_valid;
   range_operator *m_int;
-  range_operator_float *m_float;
+  range_operator *m_float;
 };
 
 extern bool range_cast (vrange &, tree type);
@@ -294,20 +295,9 @@ private:
   range_operator *m_range_tree[MAX_TREE_CODES];
 };
 
-// Like above, but for floating point operators.
-
-class floating_op_table
-{
-public:
-  floating_op_table ();
-  range_operator_float *operator[] (enum tree_code code);
-private:
-  void set (enum tree_code code, range_operator_float &op);
-  range_operator_float *m_range_tree[MAX_TREE_CODES];
-};
 
 // This holds the range op table for floating point operations.
-extern floating_op_table *floating_tree_table;
+extern range_op_table *floating_tree_table;
 
 extern range_operator *ptr_op_widen_mult_signed;
 extern range_operator *ptr_op_widen_mult_unsigned;
-- 
2.40.1

From d5e2d6eb39d0e1c74b1d0e8c389f62f5e22a0640 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacl...@redhat.com>
Date: Wed, 31 May 2023 13:10:31 -0400
Subject: [PATCH 03/11] Provide a new dispatch mechanism for range-ops.

Simplify range_op_handler to have a single range-operator pointer and
provide a more flexible dispatch mechanism for calls via generic vrange
classes.   This is more extensible for adding new classes of range support.

	* gimple-range-op.cc
	(gimple_range_op_handler::gimple_range_op_handler): Adjust.
	(gimple_range_op_handler::maybe_builtin_call): Adjust.
	* gimple-range-op.h (operand1, operand2): Use m_operator.
	* range-op.cc (integral_table, pointer_table): Relocate.
	(get_op_handler): Rename from get_handler and handle all types.
	(range_op_handler::range_op_handler): Relocate.
	(range_op_handler::set_op_handler): Relocate and adjust.
	(range_op_handler::range_op_handler): Relocate.
	(dispatch_trio): New.
	(RO_III, RO_IFI, RO_IFF, RO_FFF, RO_FIF, RO_FII): New consts.
	(range_op_handler::dispatch_kind): New.
	(range_op_handler::fold_range): Relocate and Use new dispatch value.
	(range_op_handler::op1_range): Ditto.
	(range_op_handler::op2_range): Ditto.
	(range_op_handler::lhs_op1_relation): Ditto.
	(range_op_handler::lhs_op2_relation): Ditto.
	(range_op_handler::op1_op2_relation): Ditto.
	(range_op_handler::set_op_handler): Use m_operator member.
	* range-op.h (range_op_handler::operator bool): Use m_operator.
	(range_op_handler::dispatch_kind): New.
	(range_op_handler::m_valid): Delete.
	(range_op_handler::m_int): Delete
	(range_op_handler::m_float): Delete
	(range_op_handler::m_operator): New.
	(range_op_table::operator[]): Relocate from .cc file.
	(range_op_table::set): Ditto.
	* value-range.h (class vrange): Make range_op_handler a friend.
---
 gcc/gimple-range-op.cc |  84 +++-----
 gcc/gimple-range-op.h  |   4 +-
 gcc/range-op.cc        | 474 ++++++++++++++++++++++-------------------
 gcc/range-op.h         |  27 ++-
 gcc/value-range.h      |   1 +
 5 files changed, 310 insertions(+), 280 deletions(-)

diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
index 0c32a1d2859..727cc2817c7 100644
--- a/gcc/gimple-range-op.cc
+++ b/gcc/gimple-range-op.cc
@@ -144,7 +144,7 @@ gimple_range_op_handler::gimple_range_op_handler (gimple *s)
   if (type)
     set_op_handler (code, type);
 
-  if (m_valid)
+  if (m_operator)
     switch (gimple_code (m_stmt))
       {
 	case GIMPLE_COND:
@@ -152,7 +152,7 @@ gimple_range_op_handler::gimple_range_op_handler (gimple *s)
 	  m_op2 = gimple_cond_rhs (m_stmt);
 	  // Check that operands are supported types.  One check is enough.
 	  if (!Value_Range::supports_type_p (TREE_TYPE (m_op1)))
-	    m_valid = false;
+	    m_operator = NULL;
 	  return;
 	case GIMPLE_ASSIGN:
 	  m_op1 = gimple_range_base_of_assignment (m_stmt);
@@ -171,7 +171,7 @@ gimple_range_op_handler::gimple_range_op_handler (gimple *s)
 	    m_op2 = gimple_assign_rhs2 (m_stmt);
 	  // Check that operands are supported types.  One check is enough.
 	  if ((m_op1 && !Value_Range::supports_type_p (TREE_TYPE (m_op1))))
-	    m_valid = false;
+	    m_operator = NULL;
 	  return;
 	default:
 	  gcc_unreachable ();
@@ -1199,7 +1199,6 @@ gimple_range_op_handler::maybe_non_standard ()
 	gcc_fallthrough ();
 	case WIDEN_MULT_EXPR:
 	{
-	  m_valid = false;
 	  m_op1 = gimple_assign_rhs1 (m_stmt);
 	  m_op2 = gimple_assign_rhs2 (m_stmt);
 	  tree ret = gimple_assign_lhs (m_stmt);
@@ -1216,14 +1215,13 @@ gimple_range_op_handler::maybe_non_standard ()
 	  if ((signed1 ^ signed2) && signed_ret)
 	    return;
 
-	  m_valid = true;
 	  if (signed2 && !signed1)
 	    std::swap (m_op1, m_op2);
 
 	  if (signed1 || signed2)
-	    m_int = signed_op;
+	    m_operator = signed_op;
 	  else
-	    m_int = unsigned_op;
+	    m_operator = unsigned_op;
 	  break;
 	}
 	default:
@@ -1252,47 +1250,41 @@ gimple_range_op_handler::maybe_builtin_call ()
     {
     case CFN_BUILT_IN_CONSTANT_P:
       m_op1 = gimple_call_arg (call, 0);
-      m_valid = true;
       if (irange::supports_p (TREE_TYPE (m_op1)))
-	m_int = &op_cfn_constant_p;
+	m_operator = &op_cfn_constant_p;
       else if (frange::supports_p (TREE_TYPE (m_op1)))
-	m_float = &op_cfn_constant_float_p;
+	m_operator = &op_cfn_constant_float_p;
       else
-	m_valid = false;
+	m_operator = NULL;
       break;
 
     CASE_FLT_FN (CFN_BUILT_IN_SIGNBIT):
       m_op1 = gimple_call_arg (call, 0);
-      m_float = &op_cfn_signbit;
-      m_valid = true;
+      m_operator = &op_cfn_signbit;
       break;
 
     CASE_CFN_COPYSIGN_ALL:
       m_op1 = gimple_call_arg (call, 0);
       m_op2 = gimple_call_arg (call, 1);
-      m_float = &op_cfn_copysign;
-      m_valid = true;
+      m_operator = &op_cfn_copysign;
       break;
 
     CASE_CFN_SQRT:
     CASE_CFN_SQRT_FN:
       m_op1 = gimple_call_arg (call, 0);
-      m_float = &op_cfn_sqrt;
-      m_valid = true;
+      m_operator = &op_cfn_sqrt;
       break;
 
     CASE_CFN_SIN:
     CASE_CFN_SIN_FN:
       m_op1 = gimple_call_arg (call, 0);
-      m_float = &op_cfn_sin;
-      m_valid = true;
+      m_operator = &op_cfn_sin;
       break;
 
     CASE_CFN_COS:
     CASE_CFN_COS_FN:
       m_op1 = gimple_call_arg (call, 0);
-      m_float = &op_cfn_cos;
-      m_valid = true;
+      m_operator = &op_cfn_cos;
       break;
 
     case CFN_BUILT_IN_TOUPPER:
@@ -1300,68 +1292,57 @@ gimple_range_op_handler::maybe_builtin_call ()
       // Only proceed If the argument is compatible with the LHS.
       m_op1 = gimple_call_arg (call, 0);
       if (range_compatible_p (type, TREE_TYPE (m_op1)))
-	{
-	  m_valid = true;
-	  m_int = (func == CFN_BUILT_IN_TOLOWER) ? &op_cfn_tolower
-						 : &op_cfn_toupper;
-	}
+	m_operator = (func == CFN_BUILT_IN_TOLOWER) ? &op_cfn_tolower
+						    : &op_cfn_toupper;
       break;
 
     CASE_CFN_FFS:
       m_op1 = gimple_call_arg (call, 0);
-      m_int = &op_cfn_ffs;
-      m_valid = true;
+      m_operator = &op_cfn_ffs;
       break;
 
     CASE_CFN_POPCOUNT:
       m_op1 = gimple_call_arg (call, 0);
-      m_int = &op_cfn_popcount;
-      m_valid = true;
+      m_operator = &op_cfn_popcount;
       break;
 
     CASE_CFN_CLZ:
       m_op1 = gimple_call_arg (call, 0);
-      m_valid = true;
       if (gimple_call_internal_p (call))
-	m_int = &op_cfn_clz_internal;
+	m_operator = &op_cfn_clz_internal;
       else
-	m_int = &op_cfn_clz;
+	m_operator = &op_cfn_clz;
       break;
 
     CASE_CFN_CTZ:
       m_op1 = gimple_call_arg (call, 0);
-      m_valid = true;
       if (gimple_call_internal_p (call))
-	m_int = &op_cfn_ctz_internal;
+	m_operator = &op_cfn_ctz_internal;
       else
-	m_int = &op_cfn_ctz;
+	m_operator = &op_cfn_ctz;
       break;
 
     CASE_CFN_CLRSB:
       m_op1 = gimple_call_arg (call, 0);
-      m_valid = true;
-      m_int = &op_cfn_clrsb;
+      m_operator = &op_cfn_clrsb;
       break;
 
     case CFN_UBSAN_CHECK_ADD:
       m_op1 = gimple_call_arg (call, 0);
       m_op2 = gimple_call_arg (call, 1);
-      m_valid = true;
-      m_int = &op_cfn_ubsan_add;
+      m_operator = &op_cfn_ubsan_add;
       break;
 
     case CFN_UBSAN_CHECK_SUB:
       m_op1 = gimple_call_arg (call, 0);
       m_op2 = gimple_call_arg (call, 1);
-      m_valid = true;
-      m_int = &op_cfn_ubsan_sub;
+      m_operator = &op_cfn_ubsan_sub;
       break;
 
     case CFN_UBSAN_CHECK_MUL:
       m_op1 = gimple_call_arg (call, 0);
       m_op2 = gimple_call_arg (call, 1);
-      m_valid = true;
-      m_int = &op_cfn_ubsan_mul;
+      m_operator = &op_cfn_ubsan_mul;
       break;
 
     case CFN_BUILT_IN_STRLEN:
@@ -1371,8 +1352,7 @@ gimple_range_op_handler::maybe_builtin_call ()
 					 == TYPE_PRECISION (TREE_TYPE (lhs))))
 	  {
 	    m_op1 = gimple_call_arg (call, 0);
-	    m_valid = true;
-	    m_int = &op_cfn_strlen;
+	    m_operator = &op_cfn_strlen;
 	  }
 	break;
       }
@@ -1384,21 +1364,18 @@ gimple_range_op_handler::maybe_builtin_call ()
       // This call will ensure all the asserts are triggered.
       oacc_get_ifn_dim_arg (call);
       m_op1 = gimple_call_arg (call, 0);
-      m_valid = true;
-      m_int = &op_cfn_goacc_dim_size;
+      m_operator = &op_cfn_goacc_dim_size;
       break;
 
     case CFN_GOACC_DIM_POS:
       // This call will ensure all the asserts are triggered.
       oacc_get_ifn_dim_arg (call);
       m_op1 = gimple_call_arg (call, 0);
-      m_valid = true;
-      m_int = &op_cfn_goacc_dim_pos;
+      m_operator = &op_cfn_goacc_dim_pos;
       break;
 
     CASE_CFN_PARITY:
-      m_valid = true;
-      m_int = &op_cfn_parity;
+      m_operator = &op_cfn_parity;
       break;
 
     default:
@@ -1406,9 +1383,8 @@ gimple_range_op_handler::maybe_builtin_call ()
 	unsigned arg;
 	if (gimple_call_fnspec (call).returns_arg (&arg) && arg == 0)
 	  {
-	    m_valid = true;
 	    m_op1 = gimple_call_arg (call, 0);
-	    m_int = &op_cfn_pass_through_arg1;
+	    m_operator = &op_cfn_pass_through_arg1;
 	  }
 	break;
       }
diff --git a/gcc/gimple-range-op.h b/gcc/gimple-range-op.h
index 1bf63c5ce6f..e7bb0095440 100644
--- a/gcc/gimple-range-op.h
+++ b/gcc/gimple-range-op.h
@@ -32,8 +32,8 @@ public:
   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; }
+  tree operand1 () const { gcc_checking_assert (m_operator); return m_op1; }
+  tree operand2 () const { gcc_checking_assert (m_operator); 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,
 		 relation_trio = TRIO_VARYING);
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 203c30f6e94..b24832922f0 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -48,6 +48,260 @@ along with GCC; see the file COPYING3.  If not see
 #include "range-op.h"
 #include "tree-ssa-ccp.h"
 
+// Instantiate a range op table for integral operations.
+
+class integral_table : public range_op_table
+{
+public:
+  integral_table ();
+} integral_tree_table;
+
+// Instantiate a range op table for pointer operations.
+
+class pointer_table : public range_op_table
+{
+public:
+  pointer_table ();
+} pointer_tree_table;
+
+
+// The tables are hidden and accessed via a simple extern function.
+
+range_operator *
+get_op_handler (enum tree_code code, tree type)
+{
+  // First check if there is a pointer specialization.
+  if (POINTER_TYPE_P (type))
+    return pointer_tree_table[code];
+  if (INTEGRAL_TYPE_P (type))
+    return integral_tree_table[code];
+  if (frange::supports_p (type))
+    return (*floating_tree_table)[code];
+  return NULL;
+}
+
+range_op_handler::range_op_handler ()
+{
+  m_operator = NULL;
+}
+
+void
+range_op_handler::set_op_handler (tree_code code, tree type)
+{
+  m_operator = get_op_handler (code, type);
+}
+
+range_op_handler::range_op_handler (tree_code code, tree type)
+{
+  set_op_handler (code, type);
+}
+
+// Create a dispatch pattern for value range discriminators LHS, OP1, and OP2.
+// This is used to produce a unique value for each dispatch pattern.  The
+// denser the values, the more efficient dispatch can be created via
+// jump tables.
+// Ensure the shifts are appropriate for the number of range types supported.
+// Current only INT and FLOAT are supported, so a shift of 1 is sufficient
+// producing a value of 0-7 value for dispatching.
+
+constexpr unsigned
+dispatch_trio (unsigned lhs, unsigned op1, unsigned op2)
+{
+  return ((lhs << 2) + (op1 << 1) + (op2));
+}
+
+// These are the supported dispatch patterns. These map to the parameter list
+// of the routines in range_operator.  Note the last 3 characters are
+// shorthand for the LHS, OP1, and OP2 range discriminator class.
+
+const unsigned RO_III =	dispatch_trio (VR_IRANGE, VR_IRANGE, VR_IRANGE);
+const unsigned RO_IFI = dispatch_trio (VR_IRANGE, VR_FRANGE, VR_IRANGE);
+const unsigned RO_IFF = dispatch_trio (VR_IRANGE, VR_FRANGE, VR_FRANGE);
+const unsigned RO_FFF = dispatch_trio (VR_FRANGE, VR_FRANGE, VR_FRANGE);
+const unsigned RO_FIF = dispatch_trio (VR_FRANGE, VR_IRANGE, VR_FRANGE);
+const unsigned RO_FII = dispatch_trio (VR_FRANGE, VR_IRANGE, VR_IRANGE);
+
+// Return a dispatch value for parameter types LHS, OP1 and OP2.
+
+unsigned
+range_op_handler::dispatch_kind (const vrange &lhs, const vrange &op1,
+				 const vrange& op2) const
+{
+  return dispatch_trio (lhs.m_discriminator, op1.m_discriminator,
+			op2.m_discriminator);
+}
+
+// Dispatch a call to fold_range based on the types of R, LH and RH.
+
+bool
+range_op_handler::fold_range (vrange &r, tree type,
+			      const vrange &lh,
+			      const vrange &rh,
+			      relation_trio rel) const
+{
+  gcc_checking_assert (m_operator);
+  switch (dispatch_kind (r, lh, rh))
+    {
+      case RO_III:
+	return m_operator->fold_range (as_a <irange> (r), type,
+				       as_a <irange> (lh),
+				       as_a <irange> (rh), rel);
+      case RO_IFI:
+	return m_operator->fold_range (as_a <irange> (r), type,
+				       as_a <frange> (lh),
+				       as_a <irange> (rh), rel);
+      case RO_IFF:
+	return m_operator->fold_range (as_a <irange> (r), type,
+				       as_a <frange> (lh),
+				       as_a <frange> (rh), rel);
+      case RO_FFF:
+	return m_operator->fold_range (as_a <frange> (r), type,
+				       as_a <frange> (lh),
+				       as_a <frange> (rh), rel);
+      default:
+	return false;
+    }
+}
+
+// Dispatch a call to op1_range based on the types of R, LHS and OP2.
+
+bool
+range_op_handler::op1_range (vrange &r, tree type,
+			     const vrange &lhs,
+			     const vrange &op2,
+			     relation_trio rel) const
+{
+  gcc_checking_assert (m_operator);
+
+  if (lhs.undefined_p ())
+    return false;
+  switch (dispatch_kind (r, lhs, op2))
+    {
+      case RO_III:
+	return m_operator->op1_range (as_a <irange> (r), type,
+				      as_a <irange> (lhs),
+				      as_a <irange> (op2), rel);
+      case RO_FIF:
+	return m_operator->op1_range (as_a <frange> (r), type,
+				      as_a <irange> (lhs),
+				      as_a <frange> (op2), rel);
+      case RO_FFF:
+	return m_operator->op1_range (as_a <frange> (r), type,
+				      as_a <frange> (lhs),
+				      as_a <frange> (op2), rel);
+      default:
+	return false;
+    }
+}
+
+// Dispatch a call to op2_range based on the types of R, LHS and OP1.
+
+bool
+range_op_handler::op2_range (vrange &r, tree type,
+			     const vrange &lhs,
+			     const vrange &op1,
+			     relation_trio rel) const
+{
+  gcc_checking_assert (m_operator);
+  if (lhs.undefined_p ())
+    return false;
+
+  switch (dispatch_kind (r, lhs, op1))
+    {
+      case RO_III:
+	return m_operator->op2_range (as_a <irange> (r), type,
+				      as_a <irange> (lhs),
+				      as_a <irange> (op1), rel);
+      case RO_FIF:
+	return m_operator->op2_range (as_a <frange> (r), type,
+				      as_a <irange> (lhs),
+				      as_a <frange> (op1), rel);
+      case RO_FFF:
+	return m_operator->op2_range (as_a <frange> (r), type,
+				      as_a <frange> (lhs),
+				      as_a <frange> (op1), rel);
+      default:
+	return false;
+    }
+}
+
+// Dispatch a call to lhs_op1_relation based on the types of LHS, OP1 and OP2.
+
+relation_kind
+range_op_handler::lhs_op1_relation (const vrange &lhs,
+				    const vrange &op1,
+				    const vrange &op2,
+				    relation_kind rel) const
+{
+  gcc_checking_assert (m_operator);
+
+  switch (dispatch_kind (lhs, op1, op2))
+    {
+      case RO_III:
+	return m_operator->lhs_op1_relation (as_a <irange> (lhs),
+					     as_a <irange> (op1),
+					     as_a <irange> (op2), rel);
+      case RO_IFF:
+	return m_operator->lhs_op1_relation (as_a <irange> (lhs),
+					     as_a <frange> (op1),
+					     as_a <frange> (op2), rel);
+      case RO_FFF:
+	return m_operator->lhs_op1_relation (as_a <frange> (lhs),
+					     as_a <frange> (op1),
+					     as_a <frange> (op2), rel);
+      default:
+	return VREL_VARYING;
+    }
+}
+
+// Dispatch a call to lhs_op2_relation based on the types of LHS, OP1 and OP2.
+
+relation_kind
+range_op_handler::lhs_op2_relation (const vrange &lhs,
+				    const vrange &op1,
+				    const vrange &op2,
+				    relation_kind rel) const
+{
+  gcc_checking_assert (m_operator);
+  switch (dispatch_kind (lhs, op1, op2))
+    {
+      case RO_III:
+	return m_operator->lhs_op2_relation (as_a <irange> (lhs),
+					     as_a <irange> (op1),
+					     as_a <irange> (op2), rel);
+      case RO_IFF:
+	return m_operator->lhs_op2_relation (as_a <irange> (lhs),
+					     as_a <frange> (op1),
+					     as_a <frange> (op2), rel);
+      case RO_FFF:
+	return m_operator->lhs_op2_relation (as_a <frange> (lhs),
+					     as_a <frange> (op1),
+					     as_a <frange> (op2), rel);
+      default:
+	return VREL_VARYING;
+    }
+}
+
+// Dispatch a call to op1_op2_relation based on the type of LHS.
+
+relation_kind
+range_op_handler::op1_op2_relation (const vrange &lhs) const
+{
+  gcc_checking_assert (m_operator);
+  switch (dispatch_kind (lhs, lhs, lhs))
+    {
+      case RO_III:
+	return m_operator->op1_op2_relation (as_a <irange> (lhs));
+
+      case RO_FFF:
+	return m_operator->op1_op2_relation (as_a <frange> (lhs));
+
+      default:
+	return VREL_VARYING;
+    }
+}
+
+
 // Convert irange bitmasks into a VALUE MASK pair suitable for calling CCP.
 
 static void
@@ -4612,33 +4866,6 @@ pointer_or_operator::wi_fold (irange &r, tree type,
     r.set_varying (type);
 }
 
-// Return a pointer to the range_operator instance, if there is one
-// associated with tree_code CODE.
-
-range_operator *
-range_op_table::operator[] (enum tree_code code)
-{
-  gcc_checking_assert (code > 0 && code < MAX_TREE_CODES);
-  return m_range_tree[code];
-}
-
-// Add OP to the handler table for CODE.
-
-void
-range_op_table::set (enum tree_code code, range_operator &op)
-{
-  gcc_checking_assert (m_range_tree[code] == NULL);
-  m_range_tree[code] = &op;
-}
-
-// Instantiate a range op table for integral operations.
-
-class integral_table : public range_op_table
-{
-public:
-  integral_table ();
-} integral_tree_table;
-
 integral_table::integral_table ()
 {
   set (EQ_EXPR, op_equal);
@@ -4682,14 +4909,6 @@ integral_table::integral_table ()
   set (ADDR_EXPR, op_addr);
 }
 
-// Instantiate a range op table for pointer operations.
-
-class pointer_table : public range_op_table
-{
-public:
-  pointer_table ();
-} pointer_tree_table;
-
 pointer_table::pointer_table ()
 {
   set (BIT_AND_EXPR, op_pointer_and);
@@ -4714,191 +4933,6 @@ pointer_table::pointer_table ()
   set (BIT_XOR_EXPR, op_bitwise_xor);
 }
 
-// The tables are hidden and accessed via a simple extern function.
-
-static inline range_operator *
-get_handler (enum tree_code code, tree type)
-{
-  // First check if there is a pointer specialization.
-  if (POINTER_TYPE_P (type))
-    return pointer_tree_table[code];
-  if (INTEGRAL_TYPE_P (type))
-    return integral_tree_table[code];
-  return NULL;
-}
-
-// Return the floating point operator for CODE or NULL if none available.
-
-static inline range_operator *
-get_float_handler (enum tree_code code, tree)
-{
-  return (*floating_tree_table)[code];
-}
-
-void
-range_op_handler::set_op_handler (tree_code code, tree type)
-{
-  if (irange::supports_p (type))
-    {
-      m_float = NULL;
-      m_int = get_handler (code, type);
-      m_valid = m_int != NULL;
-    }
-  else if (frange::supports_p (type))
-    {
-      m_int = NULL;
-      m_float = get_float_handler (code, type);
-      m_valid = m_float != NULL;
-    }
-  else
-    {
-      m_int = NULL;
-      m_float = NULL;
-      m_valid = false;
-    }
-}
-
-range_op_handler::range_op_handler ()
-{
-  m_int = NULL;
-  m_float = NULL;
-  m_valid = false;
-}
-
-range_op_handler::range_op_handler (tree_code code, tree type)
-{
-  set_op_handler (code, type);
-}
-
-
-bool
-range_op_handler::fold_range (vrange &r, tree type,
-			      const vrange &lh,
-			      const vrange &rh,
-			      relation_trio rel) const
-{
-  gcc_checking_assert (m_valid);
-  if (m_int)
-    return m_int->fold_range (as_a <irange> (r), type,
-			   as_a <irange> (lh),
-			   as_a <irange> (rh), rel);
-
-  if (is_a <irange> (r))
-    {
-      if (is_a <irange> (rh))
-	return m_float->fold_range (as_a <irange> (r), type,
-				    as_a <frange> (lh),
-				    as_a <irange> (rh), rel);
-      else
-	return m_float->fold_range (as_a <irange> (r), type,
-				    as_a <frange> (lh),
-				    as_a <frange> (rh), rel);
-    }
-  return m_float->fold_range (as_a <frange> (r), type,
-			      as_a <frange> (lh),
-			      as_a <frange> (rh), rel);
-}
-
-bool
-range_op_handler::op1_range (vrange &r, tree type,
-			     const vrange &lhs,
-			     const vrange &op2,
-			     relation_trio rel) const
-{
-  gcc_checking_assert (m_valid);
-
-  if (lhs.undefined_p ())
-    return false;
-  if (m_int)
-    return m_int->op1_range (as_a <irange> (r), type,
-			     as_a <irange> (lhs),
-			     as_a <irange> (op2), rel);
-
-  if (is_a <irange> (lhs))
-    return m_float->op1_range (as_a <frange> (r), type,
-			       as_a <irange> (lhs),
-			       as_a <frange> (op2), rel);
-  return m_float->op1_range (as_a <frange> (r), type,
-			     as_a <frange> (lhs),
-			     as_a <frange> (op2), rel);
-}
-
-bool
-range_op_handler::op2_range (vrange &r, tree type,
-			     const vrange &lhs,
-			     const vrange &op1,
-			     relation_trio rel) const
-{
-  gcc_checking_assert (m_valid);
-  if (lhs.undefined_p ())
-    return false;
-  if (m_int)
-    return m_int->op2_range (as_a <irange> (r), type,
-			     as_a <irange> (lhs),
-			     as_a <irange> (op1), rel);
-
-  if (is_a <irange> (lhs))
-    return m_float->op2_range (as_a <frange> (r), type,
-			       as_a <irange> (lhs),
-			       as_a <frange> (op1), rel);
-  return m_float->op2_range (as_a <frange> (r), type,
-			     as_a <frange> (lhs),
-			     as_a <frange> (op1), rel);
-}
-
-relation_kind
-range_op_handler::lhs_op1_relation (const vrange &lhs,
-				    const vrange &op1,
-				    const vrange &op2,
-				    relation_kind rel) const
-{
-  gcc_checking_assert (m_valid);
-  if (m_int)
-    return m_int->lhs_op1_relation (as_a <irange> (lhs),
-				    as_a <irange> (op1),
-				    as_a <irange> (op2), rel);
-
-  if (is_a <irange> (lhs))
-    return m_float->lhs_op1_relation (as_a <irange> (lhs),
-				 as_a <frange> (op1),
-				 as_a <frange> (op2), rel);
-  return m_float->lhs_op1_relation (as_a <frange> (lhs),
-			       as_a <frange> (op1),
-			       as_a <frange> (op2), rel);
-}
-
-relation_kind
-range_op_handler::lhs_op2_relation (const vrange &lhs,
-				    const vrange &op1,
-				    const vrange &op2,
-				    relation_kind rel) const
-{
-  gcc_checking_assert (m_valid);
-  if (m_int)
-    return m_int->lhs_op2_relation (as_a <irange> (lhs),
-				    as_a <irange> (op1),
-				    as_a <irange> (op2), rel);
-
-  if (is_a <irange> (lhs))
-    return m_float->lhs_op2_relation (as_a <irange> (lhs),
-				      as_a <frange> (op1),
-				      as_a <frange> (op2), rel);
-  return m_float->lhs_op2_relation (as_a <frange> (lhs),
-				      as_a <frange> (op1),
-				      as_a <frange> (op2), rel);
-}
-
-relation_kind
-range_op_handler::op1_op2_relation (const vrange &lhs) const
-{
-  gcc_checking_assert (m_valid);
-  if (m_int)
-    return m_int->op1_op2_relation (as_a <irange> (lhs));
-  if (is_a <irange> (lhs))
-    return m_float->op1_op2_relation (as_a <irange> (lhs));
-  return m_float->op1_op2_relation (as_a <frange> (lhs));
-}
-
 // Cast the range in R to TYPE.
 
 bool
diff --git a/gcc/range-op.h b/gcc/range-op.h
index cad16f4cd20..7af58736c3f 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -186,7 +186,7 @@ class range_op_handler
 public:
   range_op_handler ();
   range_op_handler (enum tree_code code, tree type);
-  inline operator bool () const { return m_valid; }
+  inline operator bool () const { return m_operator != NULL; }
 
   bool fold_range (vrange &r, tree type,
 		   const vrange &lh,
@@ -210,10 +210,10 @@ public:
 				  relation_kind = VREL_VARYING) const;
   relation_kind op1_op2_relation (const vrange &lhs) const;
 protected:
+  unsigned dispatch_kind (const vrange &lhs, const vrange &op1,
+			  const vrange& op2) const;
   void set_op_handler (enum tree_code code, tree type);
-  bool m_valid;
-  range_operator *m_int;
-  range_operator *m_float;
+  range_operator *m_operator;
 };
 
 extern bool range_cast (vrange &, tree type);
@@ -296,6 +296,25 @@ private:
 };
 
 
+// Return a pointer to the range_operator instance, if there is one
+// associated with tree_code CODE.
+
+inline range_operator *
+range_op_table::operator[] (enum tree_code code)
+{
+  gcc_checking_assert (code > 0 && code < MAX_TREE_CODES);
+  return m_range_tree[code];
+}
+
+// Add OP to the handler table for CODE.
+
+inline void
+range_op_table::set (enum tree_code code, range_operator &op)
+{
+  gcc_checking_assert (m_range_tree[code] == NULL);
+  m_range_tree[code] = &op;
+}
+
 // This holds the range op table for floating point operations.
 extern range_op_table *floating_tree_table;
 
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 2b4ebabe7c8..9103e9c41c7 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -77,6 +77,7 @@ class GTY((user)) vrange
   template <typename T> friend bool is_a (vrange &);
   friend class Value_Range;
   friend void streamer_write_vrange (struct output_block *, const vrange &);
+  friend class range_op_handler;
 public:
   virtual void accept (const class vrange_visitor &v) const = 0;
   virtual void set (tree, tree, value_range_kind = VR_RANGE);
-- 
2.40.1

Reply via email to