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
@@ -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);
}
new file mode 100644
@@ -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
@@ -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"
@@ -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