From: Andrew MacLeod Date: Fri, 9 Jun 2023 16:58:57 +0000 (-0400) Subject: Provide a unified range-op table. X-Git-Tag: basepoints/gcc-15~8472 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=07767389fb390814d9b6142e9d0341b7b9fd1cc2;p=thirdparty%2Fgcc.git 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. --- diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc index bb10accd78f4..8659217659cb 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 000000000000..a78bc2ba59c2 --- /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 + and Aldy Hernandez . + +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 +. */ + +#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 44a95b20ffa8..4e00c9f439e3 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 2abec3299efa..0721d4a302d3 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;