From patchwork Mon Jul 25 18:08:09 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aldy Hernandez X-Patchwork-Id: 56314 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E9355383A313 for ; Mon, 25 Jul 2022 18:08:57 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org E9355383A313 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1658772537; bh=Hr/i+mnA3sUjrNx5wH7O94pqrA5sCH51Tc2MXt7m6l8=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=OlMhIt7F4pO4tJvGdzWPjqcFIerG1amP+4CxBqYvpAT0CU0Iiq9C6dktDUVAqIGvQ 7ff+G54sgCg3ZmqrzlIhX8Rm44nz550JE7V9tLh2QucxM26XNYmnfc1JyFCrcHZJwK R7kgPZVq2m70qO5NZZZij7hvRHmj8hm0nz1UI5WU= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id CE71838582AE for ; Mon, 25 Jul 2022 18:08:27 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org CE71838582AE Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-654-vnII2UQQM0mvfy11GGyZmw-1; Mon, 25 Jul 2022 14:08:24 -0400 X-MC-Unique: vnII2UQQM0mvfy11GGyZmw-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 0A58380418F for ; Mon, 25 Jul 2022 18:08:24 +0000 (UTC) Received: from abulafia.quesejoda.com (unknown [10.39.195.31]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 6A7D82026D64; Mon, 25 Jul 2022 18:08:23 +0000 (UTC) Received: from abulafia.quesejoda.com (localhost [127.0.0.1]) by abulafia.quesejoda.com (8.17.1/8.17.1) with ESMTPS id 26PI8K712200163 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NOT); Mon, 25 Jul 2022 20:08:21 +0200 Received: (from aldyh@localhost) by abulafia.quesejoda.com (8.17.1/8.17.1/Submit) id 26PI8KPg2200162; Mon, 25 Jul 2022 20:08:20 +0200 To: GCC patches Subject: [PATCH] Dispatch code for floating point range ops. Date: Mon, 25 Jul 2022 20:08:09 +0200 Message-Id: <20220725180809.2200125-1-aldyh@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.7 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Aldy Hernandez via Gcc-patches From: Aldy Hernandez Reply-To: Aldy Hernandez Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" 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. I will push this once a final round of testing finishes 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. --- 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(-) create mode 100644 gcc/range-op-float.cc 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);