From df392fbd5d13c944479ed00fcb805e6f26d3fd4b Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Fri, 9 Jun 2023 12:58:57 -0400
Subject: [PATCH 01/31] Provide a unified range-op table.

Create a table to prepare for unifying all operations into a single table.
Move any operators which only occur in one table to the approriate
initialization routine.
Provide a mixed header file for range-ops with multiple categories.

	* range-op-float.cc (class float_table): Move to header.
	(float_table::float_table): Move float only operators to...
	(range_op_table::initialize_float_ops): Here.
	* range-op-mixed.h: New.
	* range-op.cc (integral_tree_table, pointer_tree_table): Moved
	to top of file.
	(float_tree_table): Moved from range-op-float.cc.
	(unified_tree_table): New.
	(unified_table::unified_table): New.  Call initialize routines.
	(get_op_handler): Check unified table first.
	(range_op_handler::range_op_handler): Handle no type constructor.
	(integral_table::integral_table): Move integral only operators to...
	(range_op_table::initialize_integral_ops): Here.
	(pointer_table::pointer_table): Move pointer only operators to...
	(range_op_table::initialize_pointer_ops): Here.
	* range-op.h (enum bool_range_state): Move to range-op-mixed.h.
	(get_bool_state): Ditto.
	(empty_range_varying): Ditto.
	(relop_early_resolve): Ditto.
	(class range_op_table): Add new init methods for range types.
	(class integral_table): Move declaration to here.
	(class pointer_table): Move declaration to here.
	(class float_table): Move declaration to here.
---
 gcc/range-op-float.cc | 29 +++++++-------
 gcc/range-op-mixed.h  | 78 +++++++++++++++++++++++++++++++++++++
 gcc/range-op.cc       | 89 +++++++++++++++++++++++++++++--------------
 gcc/range-op.h        | 89 ++++++++++++++++---------------------------
 4 files changed, 185 insertions(+), 100 deletions(-)
 create mode 100644 gcc/range-op-mixed.h

diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc
index bb10accd78f..8659217659c 100644
--- a/gcc/range-op-float.cc
+++ b/gcc/range-op-float.cc
@@ -45,6 +45,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "wide-int.h"
 #include "value-relation.h"
 #include "range-op.h"
+#include "range-op-mixed.h"
 
 // Default definitions for floating point operators.
 
@@ -2807,15 +2808,6 @@ private:
   }
 } fop_div;
 
-// Instantiate a range_op_table for floating point operations.
-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.
-range_op_table *floating_tree_table = &global_floating_table;
 
 float_table::float_table ()
 {
@@ -2833,6 +2825,19 @@ float_table::float_table ()
   set (LE_EXPR, fop_le);
   set (GT_EXPR, fop_gt);
   set (GE_EXPR, fop_ge);
+
+  set (ABS_EXPR, fop_abs);
+  set (NEGATE_EXPR, fop_negate);
+  set (PLUS_EXPR, fop_plus);
+  set (MINUS_EXPR, fop_minus);
+  set (MULT_EXPR, fop_mult);
+}
+
+// Initialize any pointer operators to the primary table
+
+void
+range_op_table::initialize_float_ops ()
+{
   set (UNLE_EXPR, fop_unordered_le);
   set (UNLT_EXPR, fop_unordered_lt);
   set (UNGE_EXPR, fop_unordered_ge);
@@ -2841,12 +2846,6 @@ float_table::float_table ()
   set (ORDERED_EXPR, fop_ordered);
   set (UNORDERED_EXPR, fop_unordered);
   set (LTGT_EXPR, fop_ltgt);
-
-  set (ABS_EXPR, fop_abs);
-  set (NEGATE_EXPR, fop_negate);
-  set (PLUS_EXPR, fop_plus);
-  set (MINUS_EXPR, fop_minus);
-  set (MULT_EXPR, fop_mult);
   set (RDIV_EXPR, fop_div);
 }
 
diff --git a/gcc/range-op-mixed.h b/gcc/range-op-mixed.h
new file mode 100644
index 00000000000..a78bc2ba59c
--- /dev/null
+++ b/gcc/range-op-mixed.h
@@ -0,0 +1,78 @@
+/* Header file for mixed range operator class.
+   Copyright (C) 2017-2023 Free Software Foundation, Inc.
+   Contributed by Andrew MacLeod <amacleod@redhat.com>
+   and Aldy Hernandez <aldyh@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
+
+#ifndef GCC_RANGE_OP_MIXED_H
+#define GCC_RANGE_OP_MIXED_H
+
+enum bool_range_state { BRS_FALSE, BRS_TRUE, BRS_EMPTY, BRS_FULL };
+bool_range_state get_bool_state (vrange &r, const vrange &lhs, tree val_type);
+
+// If the range of either op1 or op2 is undefined, set the result to
+// varying and return TRUE.  If the caller truly cares about a result,
+// they should pass in a varying if it has an undefined that it wants
+// treated as a varying.
+
+inline bool
+empty_range_varying (vrange &r, tree type,
+		     const vrange &op1, const vrange & op2)
+{
+  if (op1.undefined_p () || op2.undefined_p ())
+    {
+      r.set_varying (type);
+      return true;
+    }
+  else
+    return false;
+}
+
+// For relation opcodes, first try to see if the supplied relation
+// forces a true or false result, and return that.
+// Then check for undefined operands.  If none of this applies,
+// return false.
+
+inline bool
+relop_early_resolve (irange &r, tree type, const vrange &op1,
+		     const vrange &op2, relation_trio trio,
+		     relation_kind my_rel)
+{
+  relation_kind rel = trio.op1_op2 ();
+  // If known relation is a complete subset of this relation, always true.
+  if (relation_union (rel, my_rel) == my_rel)
+    {
+      r = range_true (type);
+      return true;
+    }
+
+  // If known relation has no subset of this relation, always false.
+  if (relation_intersect (rel, my_rel) == VREL_UNDEFINED)
+    {
+      r = range_false (type);
+      return true;
+    }
+
+  // If either operand is undefined, return VARYING.
+  if (empty_range_varying (r, type, op1, op2))
+    return true;
+
+  return false;
+}
+
+#endif // GCC_RANGE_OP_MIXED_H
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 44a95b20ffa..4e00c9f439e 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -47,36 +47,48 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-relation.h"
 #include "range-op.h"
 #include "tree-ssa-ccp.h"
+#include "range-op-mixed.h"
 
-// Instantiate a range op table for integral operations.
+integral_table integral_tree_table;
+pointer_table pointer_tree_table;
+float_table float_tree_table;
 
-class integral_table : public range_op_table
+// Instantiate a range_op_table for unified operations.
+class unified_table : public range_op_table
 {
-public:
-  integral_table ();
-} integral_tree_table;
+  public:
+    unified_table ();
+} unified_tree_table;
 
-// Instantiate a range op table for pointer operations.
+// Invoke the initialization routines for each class of range.
 
-class pointer_table : public range_op_table
+unified_table::unified_table ()
 {
-public:
-  pointer_table ();
-} pointer_tree_table;
-
+  initialize_integral_ops ();
+  initialize_pointer_ops ();
+  initialize_float_ops ();
+}
 
 // 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 (unified_tree_table[code])
+    {
+      // Should not be in any other table if it is in the unified table.
+      gcc_checking_assert (!pointer_tree_table[code]);
+      gcc_checking_assert (!integral_tree_table[code]);
+      gcc_checking_assert (!float_tree_table[code]);
+      return unified_tree_table[code];
+    }
+
   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 float_tree_table[code];
   return NULL;
 }
 
@@ -96,6 +108,13 @@ range_op_handler::range_op_handler (tree_code code, tree type)
   set_op_handler (code, type);
 }
 
+// Constructing without a type must come from the unified table.
+
+range_op_handler::range_op_handler (tree_code code)
+{
+  m_operator = unified_tree_table[code];
+}
+
 // Create a dispatch pattern for value range discriminators LHS, OP1, and OP2.
 // This is used to produce a unique value for each dispatch pattern.  Shift
 // values are based on the size of the m_discriminator field in value_range.h.
@@ -4875,6 +4894,26 @@ integral_table::integral_table ()
   set (MIN_EXPR, op_min);
   set (MAX_EXPR, op_max);
   set (MULT_EXPR, op_mult);
+  set (NOP_EXPR, op_cast);
+  set (CONVERT_EXPR, op_cast);
+  set (BIT_AND_EXPR, op_bitwise_and);
+  set (BIT_IOR_EXPR, op_bitwise_or);
+  set (BIT_XOR_EXPR, op_bitwise_xor);
+  set (BIT_NOT_EXPR, op_bitwise_not);
+  set (INTEGER_CST, op_integer_cst);
+  set (SSA_NAME, op_ident);
+  set (PAREN_EXPR, op_ident);
+  set (OBJ_TYPE_REF, op_ident);
+  set (ABS_EXPR, op_abs);
+  set (NEGATE_EXPR, op_negate);
+  set (ADDR_EXPR, op_addr);
+}
+
+// Initialize any integral operators to the primary table
+
+void
+range_op_table::initialize_integral_ops ()
+{
   set (TRUNC_DIV_EXPR, op_trunc_div);
   set (FLOOR_DIV_EXPR, op_floor_div);
   set (ROUND_DIV_EXPR, op_round_div);
@@ -4882,27 +4921,13 @@ 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_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);
-  set (BIT_IOR_EXPR, op_bitwise_or);
-  set (BIT_XOR_EXPR, op_bitwise_xor);
   set (TRUNC_MOD_EXPR, op_trunc_mod);
   set (TRUTH_NOT_EXPR, op_logical_not);
-  set (BIT_NOT_EXPR, op_bitwise_not);
-  set (INTEGER_CST, op_integer_cst);
-  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);
-  set (NEGATE_EXPR, op_negate);
-  set (ADDR_EXPR, op_addr);
 }
 
 pointer_table::pointer_table ()
@@ -4911,7 +4936,6 @@ pointer_table::pointer_table ()
   set (BIT_IOR_EXPR, op_pointer_or);
   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);
   set (NE_EXPR, op_not_equal);
@@ -4929,6 +4953,15 @@ pointer_table::pointer_table ()
   set (BIT_XOR_EXPR, op_bitwise_xor);
 }
 
+// Initialize any pointer operators to the primary table
+
+void
+range_op_table::initialize_pointer_ops ()
+{
+  set (POINTER_PLUS_EXPR, op_pointer_plus);
+  set (POINTER_DIFF_EXPR, op_pointer_diff);
+}
+
 #if CHECKING_P
 #include "selftest.h"
 
diff --git a/gcc/range-op.h b/gcc/range-op.h
index 2abec3299ef..0721d4a302d 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -186,6 +186,7 @@ class range_op_handler
 public:
   range_op_handler ();
   range_op_handler (enum tree_code code, tree type);
+  range_op_handler (enum tree_code code);
   inline operator bool () const { return m_operator != NULL; }
 
   bool fold_range (vrange &r, tree type,
@@ -272,69 +273,18 @@ relation_kind le_op1_op2_relation (const irange &lhs);
 relation_kind gt_op1_op2_relation (const irange &lhs);
 relation_kind ge_op1_op2_relation (const irange &lhs);
 
-enum bool_range_state { BRS_FALSE, BRS_TRUE, BRS_EMPTY, BRS_FULL };
-bool_range_state get_bool_state (vrange &r, const vrange &lhs, tree val_type);
-
-// If the range of either op1 or op2 is undefined, set the result to
-// varying and return TRUE.  If the caller truly cares about a result,
-// they should pass in a varying if it has an undefined that it wants
-// treated as a varying.
-
-inline bool
-empty_range_varying (vrange &r, tree type,
-		     const vrange &op1, const vrange & op2)
-{
-  if (op1.undefined_p () || op2.undefined_p ())
-    {
-      r.set_varying (type);
-      return true;
-    }
-  else
-    return false;
-}
-
-// For relation opcodes, first try to see if the supplied relation
-// forces a true or false result, and return that.
-// Then check for undefined operands.  If none of this applies,
-// return false.
-
-inline bool
-relop_early_resolve (irange &r, tree type, const vrange &op1,
-		     const vrange &op2, relation_trio trio,
-		     relation_kind my_rel)
-{
-  relation_kind rel = trio.op1_op2 ();
-  // If known relation is a complete subset of this relation, always true.
-  if (relation_union (rel, my_rel) == my_rel)
-    {
-      r = range_true (type);
-      return true;
-    }
-
-  // If known relation has no subset of this relation, always false.
-  if (relation_intersect (rel, my_rel) == VREL_UNDEFINED)
-    {
-      r = range_false (type);
-      return true;
-    }
-
-  // If either operand is undefined, return VARYING.
-  if (empty_range_varying (r, type, op1, op2))
-    return true;
-
-  return false;
-}
-
 // 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:
+protected:
   range_operator *m_range_tree[MAX_TREE_CODES];
+  void initialize_integral_ops ();
+  void initialize_pointer_ops ();
+  void initialize_float_ops ();
 };
 
 
@@ -357,8 +307,33 @@ range_op_table::set (enum tree_code code, range_operator &op)
   m_range_tree[code] = &op;
 }
 
-// This holds the range op table for floating point operations.
-extern range_op_table *floating_tree_table;
+// This holds the range op tables
+
+class integral_table : public range_op_table
+{
+public:
+  integral_table ();
+};
+extern integral_table integral_tree_table;
+
+// Instantiate a range op table for pointer operations.
+
+class pointer_table : public range_op_table
+{
+public:
+  pointer_table ();
+};
+extern pointer_table pointer_tree_table;
+
+// Instantiate a range_op_table for floating point operations.
+class float_table : public range_op_table
+{
+  public:
+    float_table ();
+};
+extern float_table float_tree_table;
+
+
 
 extern range_operator *ptr_op_widen_mult_signed;
 extern range_operator *ptr_op_widen_mult_unsigned;
-- 
2.40.1

