[COMMITTED,1/15] - Provide a unified range-op table.

Message ID f4d04b74-c27a-0129-7466-e19b4afdbcce@redhat.com
State Committed
Headers
Series [COMMITTED,1/15] - Provide a unified range-op table. |

Commit Message

Andrew MacLeod June 10, 2023, 12:33 a.m. UTC
  With all the operators unified under range_operator, I can now start 
moving them into a unified table rather than have them spread around in 
various type tables.

This patch creates a range_table for the unified operations, and has 
checks to ensure that if the operator comes from the unified table, it 
does not exist in any other table.  This is a sanity check for the 
duration of the transition. This patch also moves all the low hanging 
fruit opcodes which exist ion only one table directly into the unified 
table.

It also introduced range-op-mixed.h which will contain the class 
declarations for any "shared" operators so that each implementation file 
can see the decl.   It also contains the common routines from range-op.h 
that some of the operators need.

With the next patch , I will begin the transition, one opcode at a time, 
to the unified table.   By doing this in separate commits, we can easily 
isolate any potential problems that show up... not that I expect any, 
its fairly mechanical..but just in case.

This first set will move all the integer/float shared opcodes into the 
header file and into the unified table.  The foperator_* classes will be 
removed and the methods themselves will simply be renamed to implement 
the unified range_operator method.  The code will remain in 
range-op-float.cc for those implementations, and the integral versions 
will remain in range-op.cc.

All the patches bootstrap on x86_64-pc-linux-gnu and pass all 
regressions.  I wont add much more comment for most of them when they 
are equivalent in functionality.   Pushed.

Andrew
  

Patch

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