From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2136) id 20C6B3857BB5; Mon, 25 Jul 2022 18:55:35 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 20C6B3857BB5 MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="utf-8" From: Aldy Hernandez To: gcc-cvs@gcc.gnu.org Subject: [gcc r13-1829] Dispatch code for floating point range ops. X-Act-Checkin: gcc X-Git-Author: Aldy Hernandez X-Git-Refname: refs/heads/master X-Git-Oldrev: 838da6cf8d2c8574f5b626823b742032e656619d X-Git-Newrev: a6efab5fbc468b6f98a7522295b7991d2036588b Message-Id: <20220725185535.20C6B3857BB5@sourceware.org> Date: Mon, 25 Jul 2022 18:55:35 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 25 Jul 2022 18:55:35 -0000 https://gcc.gnu.org/g:a6efab5fbc468b6f98a7522295b7991d2036588b commit r13-1829-ga6efab5fbc468b6f98a7522295b7991d2036588b Author: Aldy Hernandez Date: Mon Jul 25 16:42:00 2022 +0200 Dispatch code for floating point range ops. This modifies the range-op dispatch code to handle floats. Also provided are the stub routines for the floating point range-ops, as we need something to dispatch to ;-). I am not ecstatic about the dispatch code, but there's no getting around having to switch on the tree code and type in some manner. All the other alternatives I played with ended up being slower, or harder to maintain. At least, this one is self-contained in the range_op_handler API, and less than 0.16% slower for VRP in our benchmarks. Tested on x86-64 Linux. gcc/ChangeLog: * Makefile.in (OBJS): Add range-op-float.o. * range-op.cc (get_float_handler): New. (range_op_handler::range_op_handler): Save code and type for delayed querying. (range_op_handler::oeprator bool): Move from header file, and add support for floats. (range_op_handler::fold_range): Add support for floats. (range_op_handler::op1_range): Same. (range_op_handler::op2_range): Same. (range_op_handler::lhs_op1_relation): Same. (range_op_handler::lhs_op2_relation): Same. (range_op_handler::op1_op2_relation): Same. * range-op.h (class range_operator_float): New. (class floating_op_table): New. * value-query.cc (range_query::get_tree_range): Add case for REAL_CST. * range-op-float.cc: New file. Diff: --- gcc/Makefile.in | 1 + gcc/range-op-float.cc | 206 ++++++++++++++++++++++++++++++++++++++++++++++++++ gcc/range-op.cc | 153 ++++++++++++++++++++++++++++++++----- gcc/range-op.h | 69 ++++++++++++++++- gcc/value-query.cc | 1 + 5 files changed, 407 insertions(+), 23 deletions(-) diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 001506f8abf..203f0a15187 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1548,6 +1548,7 @@ OBJS = \ profile-count.o \ range.o \ range-op.o \ + range-op-float.o \ read-md.o \ read-rtl.o \ read-rtl-function.o \ diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc new file mode 100644 index 00000000000..8e9d83e3827 --- /dev/null +++ b/gcc/range-op-float.cc @@ -0,0 +1,206 @@ +/* Floating point range operators. + Copyright (C) 2022 Free Software Foundation, Inc. + Contributed by 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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "insn-codes.h" +#include "rtl.h" +#include "tree.h" +#include "gimple.h" +#include "cfghooks.h" +#include "tree-pass.h" +#include "ssa.h" +#include "optabs-tree.h" +#include "gimple-pretty-print.h" +#include "diagnostic-core.h" +#include "flags.h" +#include "fold-const.h" +#include "stor-layout.h" +#include "calls.h" +#include "cfganal.h" +#include "gimple-iterator.h" +#include "gimple-fold.h" +#include "tree-eh.h" +#include "gimple-walk.h" +#include "tree-cfg.h" +#include "wide-int.h" +#include "value-relation.h" +#include "range-op.h" + +// Default definitions for floating point operators. + +bool +range_operator_float::fold_range (frange &r ATTRIBUTE_UNUSED, + tree type ATTRIBUTE_UNUSED, + const frange &lh ATTRIBUTE_UNUSED, + const frange &rh ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const +{ + return false; +} + +bool +range_operator_float::fold_range (irange &r ATTRIBUTE_UNUSED, + tree type ATTRIBUTE_UNUSED, + const frange &lh ATTRIBUTE_UNUSED, + const frange &rh ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const +{ + return false; +} + +bool +range_operator_float::op1_range (frange &r ATTRIBUTE_UNUSED, + tree type ATTRIBUTE_UNUSED, + const frange &lhs ATTRIBUTE_UNUSED, + const frange &op2 ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const +{ + return false; +} + +bool +range_operator_float::op1_range (frange &r ATTRIBUTE_UNUSED, + tree type ATTRIBUTE_UNUSED, + const irange &lhs ATTRIBUTE_UNUSED, + const frange &op2 ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const +{ + return false; +} + +bool +range_operator_float::op2_range (frange &r ATTRIBUTE_UNUSED, + tree type ATTRIBUTE_UNUSED, + const frange &lhs ATTRIBUTE_UNUSED, + const frange &op1 ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const +{ + return false; +} + +bool +range_operator_float::op2_range (frange &r ATTRIBUTE_UNUSED, + tree type ATTRIBUTE_UNUSED, + const irange &lhs ATTRIBUTE_UNUSED, + const frange &op1 ATTRIBUTE_UNUSED, + relation_kind rel ATTRIBUTE_UNUSED) const +{ + return false; +} + +relation_kind +range_operator_float::lhs_op1_relation (const frange &lhs ATTRIBUTE_UNUSED, + const frange &op1 ATTRIBUTE_UNUSED, + const frange &op2 ATTRIBUTE_UNUSED, + relation_kind) const +{ + return VREL_VARYING; +} + +relation_kind +range_operator_float::lhs_op1_relation (const irange &lhs ATTRIBUTE_UNUSED, + const frange &op1 ATTRIBUTE_UNUSED, + const frange &op2 ATTRIBUTE_UNUSED, + relation_kind) const +{ + return VREL_VARYING; +} + +relation_kind +range_operator_float::lhs_op2_relation (const irange &lhs ATTRIBUTE_UNUSED, + const frange &op1 ATTRIBUTE_UNUSED, + const frange &op2 ATTRIBUTE_UNUSED, + relation_kind) const +{ + return VREL_VARYING; +} + +relation_kind +range_operator_float::lhs_op2_relation (const frange &lhs ATTRIBUTE_UNUSED, + const frange &op1 ATTRIBUTE_UNUSED, + const frange &op2 ATTRIBUTE_UNUSED, + relation_kind) const +{ + return VREL_VARYING; +} + +relation_kind +range_operator_float::op1_op2_relation (const irange &lhs ATTRIBUTE_UNUSED) const +{ + return VREL_VARYING; +} + +class foperator_identity : public range_operator_float +{ + using range_operator_float::fold_range; + using range_operator_float::op1_range; + + bool fold_range (frange &r, tree type ATTRIBUTE_UNUSED, + const frange &op1, const frange &op2 ATTRIBUTE_UNUSED, + relation_kind) const final override + { + r = op1; + return true; + } + bool op1_range (frange &r, tree type ATTRIBUTE_UNUSED, + const frange &lhs, const frange &op2 ATTRIBUTE_UNUSED, + relation_kind) const final override + { + r = lhs; + return true; + } +public: +} fop_identity; + + +// Instantiate a range_op_table for floating point operations. +static floating_op_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; + +floating_op_table::floating_op_table () +{ + set (SSA_NAME, fop_identity); + set (PAREN_EXPR, fop_identity); + set (OBJ_TYPE_REF, fop_identity); + set (REAL_CST, fop_identity); +} + +// 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; +} diff --git a/gcc/range-op.cc b/gcc/range-op.cc index e184129f9af..dfdd971c90a 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -4152,28 +4152,56 @@ get_handler (enum tree_code code, tree type) return NULL; } +// Return the floating point operator for CODE or NULL if none available. + +static inline range_operator_float * +get_float_handler (enum tree_code code, tree) +{ + return (*floating_tree_table)[code]; +} + range_op_handler::range_op_handler (tree_code code, tree type) + : m_code (code), m_type (type) { - m_op = get_handler (code, type); } range_op_handler::range_op_handler (const gimple *s) { if (const gassign *ass = dyn_cast (s)) { - enum tree_code code = gimple_assign_rhs_code (ass); + m_code = gimple_assign_rhs_code (ass); // The LHS of a comparison is always an int, so we must look at // the operands. - if (TREE_CODE_CLASS (code) == tcc_comparison) - m_op = get_handler (code, TREE_TYPE (gimple_assign_rhs1 (ass))); + if (TREE_CODE_CLASS (m_code) == tcc_comparison) + m_type = TREE_TYPE (gimple_assign_rhs1 (ass)); else - m_op = get_handler (code, TREE_TYPE (gimple_assign_lhs (ass))); + m_type = TREE_TYPE (gimple_assign_lhs (ass)); } else if (const gcond *cond = dyn_cast (s)) - m_op = get_handler (gimple_cond_code (cond), - TREE_TYPE (gimple_cond_lhs (cond))); + { + m_code = gimple_cond_code (cond); + m_type = TREE_TYPE (gimple_cond_lhs (cond)); + } else - m_op = NULL; + { + // A null type means there is no handler for this combination, + // but the decision whether there is one or not, is delayed + // until operator bool below is queried. + m_code = NOP_EXPR; + m_type = nullptr; + } +} + +// Return TRUE if there is a handler available for the current +// combination of tree_code and type. + +range_op_handler::operator bool () const +{ + if (!m_type) + return false; + if (frange::supports_p (m_type)) + return get_float_handler (m_code, m_type); + return get_handler (m_code, m_type); } bool @@ -4182,10 +4210,24 @@ range_op_handler::fold_range (vrange &r, tree type, const vrange &rh, relation_kind rel) const { - if (is_a (lh)) - return m_op->fold_range (as_a (r), type, + if (irange::supports_p (m_type)) + { + range_operator *op = get_handler (m_code, m_type); + return op->fold_range (as_a (r), type, as_a (lh), as_a (rh), rel); + } + if (frange::supports_p (m_type)) + { + range_operator_float *op = get_float_handler (m_code, m_type); + if (is_a (r)) + return op->fold_range (as_a (r), type, + as_a (lh), + as_a (rh), rel); + return op->fold_range (as_a (r), type, + as_a (lh), + as_a (rh), rel); + } gcc_unreachable (); return false; } @@ -4196,10 +4238,24 @@ range_op_handler::op1_range (vrange &r, tree type, const vrange &op2, relation_kind rel) const { - if (is_a (r)) - return m_op->op1_range (as_a (r), type, + if (irange::supports_p (m_type)) + { + range_operator *op = get_handler (m_code, m_type); + return op->op1_range (as_a (r), type, as_a (lhs), as_a (op2), rel); + } + if (frange::supports_p (m_type)) + { + range_operator_float *op = get_float_handler (m_code, m_type); + if (is_a (lhs)) + return op->op1_range (as_a (r), type, + as_a (lhs), + as_a (op2), rel); + return op->op1_range (as_a (r), type, + as_a (lhs), + as_a (op2), rel); + } gcc_unreachable (); return false; } @@ -4210,10 +4266,24 @@ range_op_handler::op2_range (vrange &r, tree type, const vrange &op1, relation_kind rel) const { - if (is_a (r)) - return m_op->op2_range (as_a (r), type, + if (irange::supports_p (m_type)) + { + range_operator *op = get_handler (m_code, m_type); + return op->op2_range (as_a (r), type, as_a (lhs), as_a (op1), rel); + } + if (frange::supports_p (m_type)) + { + range_operator_float *op = get_float_handler (m_code, m_type); + if (is_a (lhs)) + return op->op2_range (as_a (r), type, + as_a (lhs), + as_a (op1), rel); + return op->op2_range (as_a (r), type, + as_a (lhs), + as_a (op1), rel); + } gcc_unreachable (); return false; } @@ -4224,9 +4294,24 @@ range_op_handler::lhs_op1_relation (const vrange &lhs, const vrange &op2, relation_kind rel) const { - if (is_a (op1)) - return m_op->lhs_op1_relation (as_a (lhs), - as_a (op1), as_a (op2), rel); + if (irange::supports_p (m_type)) + { + range_operator *op = get_handler (m_code, m_type); + return op->lhs_op1_relation (as_a (lhs), + as_a (op1), + as_a (op2), rel); + } + if (frange::supports_p (m_type)) + { + range_operator_float *op = get_float_handler (m_code, m_type); + if (is_a (lhs)) + return op->lhs_op1_relation (as_a (lhs), + as_a (op1), + as_a (op2), rel); + return op->lhs_op1_relation (as_a (lhs), + as_a (op1), + as_a (op2), rel); + } gcc_unreachable (); return VREL_VARYING; } @@ -4237,9 +4322,24 @@ range_op_handler::lhs_op2_relation (const vrange &lhs, const vrange &op2, relation_kind rel) const { - if (is_a (op1)) - return m_op->lhs_op2_relation (as_a (lhs), - as_a (op1), as_a (op2), rel); + if (irange::supports_p (m_type)) + { + range_operator *op = get_handler (m_code, m_type); + return op->lhs_op2_relation (as_a (lhs), + as_a (op1), + as_a (op2), rel); + } + if (frange::supports_p (m_type)) + { + range_operator_float *op = get_float_handler (m_code, m_type); + if (is_a (lhs)) + return op->lhs_op2_relation (as_a (lhs), + as_a (op1), + as_a (op2), rel); + return op->lhs_op2_relation (as_a (lhs), + as_a (op1), + as_a (op2), rel); + } gcc_unreachable (); return VREL_VARYING; } @@ -4247,7 +4347,18 @@ range_op_handler::lhs_op2_relation (const vrange &lhs, relation_kind range_op_handler::op1_op2_relation (const vrange &lhs) const { - return m_op->op1_op2_relation (as_a (lhs)); + if (irange::supports_p (m_type)) + { + range_operator *op = get_handler (m_code, m_type); + return op->op1_op2_relation (as_a (lhs)); + } + if (frange::supports_p (m_type)) + { + range_operator_float *op = get_float_handler (m_code, m_type); + return op->op1_op2_relation (as_a (lhs)); + } + gcc_unreachable (); + return VREL_VARYING; } // Cast the range in R to TYPE. diff --git a/gcc/range-op.h b/gcc/range-op.h index 262c796180d..37d9aa91c46 100644 --- a/gcc/range-op.h +++ b/gcc/range-op.h @@ -108,12 +108,61 @@ protected: const wide_int &rh_ub) 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_kind rel = VREL_VARYING) const; + virtual bool fold_range (irange &r, tree type, + const frange &lh, + const frange &rh, + relation_kind rel = VREL_VARYING) const; + virtual bool op1_range (frange &r, tree type, + const frange &lhs, + const frange &op2, + relation_kind rel = VREL_VARYING) const; + virtual bool op1_range (frange &r, tree type, + const irange &lhs, + const frange &op2, + relation_kind rel = VREL_VARYING) const; + virtual bool op2_range (frange &r, tree type, + const frange &lhs, + const frange &op1, + relation_kind rel = VREL_VARYING) const; + virtual bool op2_range (frange &r, tree type, + const irange &lhs, + const frange &op1, + relation_kind rel = 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 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; +}; + class range_op_handler { public: range_op_handler (enum tree_code code, tree type); range_op_handler (const gimple *s); - operator bool () const { return m_op; } + operator bool () const; bool fold_range (vrange &r, tree type, const vrange &lh, @@ -137,7 +186,8 @@ public: relation_kind = VREL_VARYING) const; relation_kind op1_op2_relation (const vrange &lhs) const; private: - range_operator *m_op; + enum tree_code m_code; + tree m_type; }; extern bool range_cast (vrange &, tree type); @@ -218,4 +268,19 @@ 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; + #endif // GCC_RANGE_OP_H diff --git a/gcc/value-query.cc b/gcc/value-query.cc index decf5aae1fe..4af8eca0172 100644 --- a/gcc/value-query.cc +++ b/gcc/value-query.cc @@ -211,6 +211,7 @@ range_query::get_tree_range (vrange &r, tree expr, gimple *stmt) switch (TREE_CODE (expr)) { case INTEGER_CST: + case REAL_CST: if (TREE_OVERFLOW_P (expr)) expr = drop_tree_overflow (expr); r.set (expr, expr);