From patchwork Thu Sep 22 18:56:29 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Andrew MacLeod X-Patchwork-Id: 57925 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 2057B3857C46 for ; Thu, 22 Sep 2022 18:57:24 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2057B3857C46 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1663873044; bh=mJ1WhW9AsBVAxd5cCTggc+MwGJPa4SSKJjstfEwSsZE=; h=Date:Subject:To:References:In-Reply-To:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=vrL/8AL3nrmAFj/iHqhkNSE12EGa2/O9Qe3P7sMaxY9WJuBRZH5LtPxG8g6lPWs2i DmS4pgSvgs4OWhWZXNDchhBGqOOTW5wz0cs03cfA9awyGlLbaLQUOlJot9OF/MfzZo ki3bicHvDfbnP4hlvYneKvxNiaTpNpBL7Oa2Tkdw= 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.129.124]) by sourceware.org (Postfix) with ESMTPS id F1FAF3858D38 for ; Thu, 22 Sep 2022 18:56:34 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org F1FAF3858D38 Received: from mail-il1-f199.google.com (mail-il1-f199.google.com [209.85.166.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-373-j-5ANvjcMymt8eVKuz0IOQ-1; Thu, 22 Sep 2022 14:56:33 -0400 X-MC-Unique: j-5ANvjcMymt8eVKuz0IOQ-1 Received: by mail-il1-f199.google.com with SMTP id c7-20020a056e020bc700b002e59be6ce85so6194778ilu.12 for ; Thu, 22 Sep 2022 11:56:33 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=in-reply-to:references:cc:to:from:content-language:subject :user-agent:mime-version:date:message-id:x-gm-message-state:from:to :cc:subject:date; bh=STZfviEEDRDJkKywvZnSMW+STbnK4vr6joSYOTS5iJw=; b=NaTssx7KPl6cStjbxEY4R8bwFCHkub7WSG5GSsEI+91IPdAOdtBBiZWubIZQ3YOwVB ZYjdl3gfJhCzQ0e7obnfXBdOe0C8vh4FGbOYlmKQcvIIJ01hI5KLGhTKkzZdPyx/f2KN TA2tOhqQ9jhUeU12DTTx9sHkK8cslepShWa6IaKxFmen9sdl41/E4aFv2BWIX2JUIyez MFaZ0iA0PGjAC04Fk20wcbJI2LgErbY3gRyG1C87weJjHFelkLKZXoIcNPi6zQOYzVPK Ccx6uxtLSOlNfmAeF8Ag5d+CCFAnpqimb31izVbeapmJ+h52j7kDhvqhuv4EwZEX5MaA 1H3g== X-Gm-Message-State: ACrzQf3rFYr8MLswGmrpsKjGNRG9ZuuEUrWld9T3NzGEeYMFqTdHtB0y MIM6Tr+Zb4JHDoUY3exOkybwTVXrcssmV+I+2f4/qazNvIaIq+nmVamvKnyY0l0btaoqkw9XYyi Cg/DoyPRO1HaH8mxiWtZH7PhIVFE2XQ053rKtV2p3HNxVLWCvziNbH9iqqAnHkHVWgW0OHg== X-Received: by 2002:a05:6638:430c:b0:35a:1c37:a343 with SMTP id bt12-20020a056638430c00b0035a1c37a343mr2766083jab.183.1663872992228; Thu, 22 Sep 2022 11:56:32 -0700 (PDT) X-Google-Smtp-Source: AMsMyM6VJqf5vOJoysUjTuJk/e1107CJyvhBDZjTUAiqETIgd8db828BdCd/N0ZRyH96DruVN8NmEw== X-Received: by 2002:a05:6638:430c:b0:35a:1c37:a343 with SMTP id bt12-20020a056638430c00b0035a1c37a343mr2766068jab.183.1663872991894; Thu, 22 Sep 2022 11:56:31 -0700 (PDT) Received: from ?IPV6:2607:fea8:a263:f600::3dbe? ([2607:fea8:a263:f600::3dbe]) by smtp.gmail.com with ESMTPSA id m5-20020a023c05000000b0035ad6807a98sm2467092jaa.119.2022.09.22.11.56.30 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 22 Sep 2022 11:56:31 -0700 (PDT) Message-ID: <6d24be24-0924-f56b-7dfe-18b251b42ed5@redhat.com> Date: Thu, 22 Sep 2022 14:56:29 -0400 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.2.1 Subject: [PATCH 03/17] Create gimple_range_op_handler in a new source file. To: gcc-patches References: <571782f9-72e6-5c30-da55-b8d62d3a153e@redhat.com> In-Reply-To: <571782f9-72e6-5c30-da55-b8d62d3a153e@redhat.com> X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Language: en-US X-Spam-Status: No, score=-12.4 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_LOW, 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: Andrew MacLeod via Gcc-patches From: Andrew MacLeod Reply-To: Andrew MacLeod Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Range-ops is meant to be IL independent.  Some gimple processing has be placed in range-ops, and some is located in gori.  Split it all into a file and isolate it in a new class gimple_range_op_handler. Bootstrapped on x86_64-pc-linux-gnu with no regressions.  Pushed. Andrew From 51ce06385bf259a092f830f1a6dcc4b98757919e Mon Sep 17 00:00:00 2001 From: Andrew MacLeod Date: Thu, 1 Sep 2022 10:34:55 -0400 Subject: [PATCH 03/17] Create gimple_range_op_handler in a new source file. Range-ops is meant to be IL independent. Some gimple processing has be placed in range-ops, and some is located in gori. Split it all into a file and isolate it in a new class gimple_range_op_handler. * Makefile.in (OBJS): Add gimple-range-op.o. * gimple-range-edge.cc (gimple_outgoing_range_stmt_p): Use gimple_range_op_handler. * gimple-range-fold.cc (gimple_range_base_of_assignment): Move to a method in gimple_range_op_handler. (gimple_range_operand1): Ditto. (gimple_range_operand2): Ditto. (fold_using_range::fold_stmt): Use gimple_range_op_handler. (fold_using_range::range_of_range_op): Ditto. (fold_using_range::relation_fold_and_or): Ditto. (fur_source::register_outgoing_edges): Ditto. (gimple_range_ssa_names): Relocate to gimple-range-op.cc. * gimple-range-fold.h: Adjust prototypes. * gimple-range-gori.cc (gimple_range_calc_op1): Move to a method in gimple_range_op_handler. (gimple_range_calc_op2): Ditto. (gori_compute::compute_operand_range): Use gimple_range_op_handler. (gori_compute::compute_logical_operands): Ditto. (compute_operand1_range): Ditto. (gori_compute::compute_operand2_range): Ditto. (gori_compute::compute_operand1_and_operand2_range): Ditto. * gimple-range-gori.h: Adjust protoypes. * gimple-range-op.cc: New. Supply gimple_range_op_handler methods. * gimple-range-op.h: New. Supply gimple_range_op_handler class. * gimple-range.cc (gimple_ranger::prefill_name): Use gimple_range_op_handler. (gimple_ranger::prefill_stmt_dependencies): Ditto. * gimple-range.h: Include gimple-range-op.h. * range-op.cc (range_op_handler::range_op_handler): Adjust and remove gimple * parameter option. * range-op.h: Adjust prototypes. --- gcc/Makefile.in | 1 + gcc/gimple-range-edge.cc | 2 +- gcc/gimple-range-fold.cc | 153 +++++------------------- gcc/gimple-range-fold.h | 12 +- gcc/gimple-range-gori.cc | 134 ++++++--------------- gcc/gimple-range-gori.h | 27 ++--- gcc/gimple-range-op.cc | 245 +++++++++++++++++++++++++++++++++++++++ gcc/gimple-range-op.h | 51 ++++++++ gcc/gimple-range.cc | 11 +- gcc/gimple-range.h | 2 +- gcc/range-op.cc | 37 ++---- gcc/range-op.h | 4 +- 12 files changed, 386 insertions(+), 293 deletions(-) create mode 100644 gcc/gimple-range-op.cc create mode 100644 gcc/gimple-range-op.h diff --git a/gcc/Makefile.in b/gcc/Makefile.in index a4689d52e36..59b67d99441 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1416,6 +1416,7 @@ OBJS = \ gimple-range-fold.o \ gimple-range-gori.o \ gimple-range-infer.o \ + gimple-range-op.o \ gimple-range-trace.o \ gimple-ssa-backprop.o \ gimple-ssa-isolate-paths.o \ diff --git a/gcc/gimple-range-edge.cc b/gcc/gimple-range-edge.cc index 194e8f87a4b..95deadffc55 100644 --- a/gcc/gimple-range-edge.cc +++ b/gcc/gimple-range-edge.cc @@ -43,7 +43,7 @@ gimple_outgoing_range_stmt_p (basic_block bb) if (!gsi_end_p (gsi)) { gimple *s = gsi_stmt (gsi); - if (is_a (s) && range_op_handler (s)) + if (is_a (s) && gimple_range_op_handler::supported_p (s)) return gsi_stmt (gsi); if (is_a (s)) return gsi_stmt (gsi); diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc index a45fc7ad4c6..addf3e7f254 100644 --- a/gcc/gimple-range-fold.cc +++ b/gcc/gimple-range-fold.cc @@ -42,7 +42,7 @@ along with GCC; see the file COPYING3. If not see #include "vr-values.h" #include "range.h" #include "value-query.h" -#include "range-op.h" +#include "gimple-range-op.h" #include "gimple-range.h" // Construct a fur_source, and set the m_query field. @@ -463,73 +463,6 @@ gimple_range_adjustment (vrange &res, const gimple *stmt) } } -// Return the base of the RHS of an assignment. - -static tree -gimple_range_base_of_assignment (const gimple *stmt) -{ - gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN); - tree op1 = gimple_assign_rhs1 (stmt); - if (gimple_assign_rhs_code (stmt) == ADDR_EXPR) - return get_base_address (TREE_OPERAND (op1, 0)); - return op1; -} - -// Return the first operand of this statement if it is a valid operand -// supported by ranges, otherwise return NULL_TREE. Special case is -// &(SSA_NAME expr), return the SSA_NAME instead of the ADDR expr. - -tree -gimple_range_operand1 (const gimple *stmt) -{ - gcc_checking_assert (range_op_handler (stmt)); - - switch (gimple_code (stmt)) - { - case GIMPLE_COND: - return gimple_cond_lhs (stmt); - case GIMPLE_ASSIGN: - { - tree base = gimple_range_base_of_assignment (stmt); - if (base && TREE_CODE (base) == MEM_REF) - { - // If the base address is an SSA_NAME, we return it - // here. This allows processing of the range of that - // name, while the rest of the expression is simply - // ignored. The code in range_ops will see the - // ADDR_EXPR and do the right thing. - tree ssa = TREE_OPERAND (base, 0); - if (TREE_CODE (ssa) == SSA_NAME) - return ssa; - } - return base; - } - default: - break; - } - return NULL; -} - -// Return the second operand of statement STMT, otherwise return NULL_TREE. - -tree -gimple_range_operand2 (const gimple *stmt) -{ - gcc_checking_assert (range_op_handler (stmt)); - - switch (gimple_code (stmt)) - { - case GIMPLE_COND: - return gimple_cond_rhs (stmt); - case GIMPLE_ASSIGN: - if (gimple_num_ops (stmt) >= 3) - return gimple_assign_rhs2 (stmt); - default: - break; - } - return NULL_TREE; -} - // Calculate a range for statement S and return it in R. If NAME is provided it // represents the SSA_NAME on the LHS of the statement. It is only required // if there is more than one lhs/output. If a range cannot @@ -551,8 +484,9 @@ fold_using_range::fold_stmt (vrange &r, gimple *s, fur_source &src, tree name) && gimple_assign_rhs_code (s) == ADDR_EXPR) return range_of_address (as_a (r), s, src); - if (range_op_handler (s)) - res = range_of_range_op (r, s, src); + gimple_range_op_handler handler (s); + if (handler) + res = range_of_range_op (r, handler, src); else if (is_a(s)) res = range_of_phi (r, as_a (s), src); else if (is_a(s)) @@ -587,17 +521,19 @@ fold_using_range::fold_stmt (vrange &r, gimple *s, fur_source &src, tree name) // If a range cannot be calculated, return false. bool -fold_using_range::range_of_range_op (vrange &r, gimple *s, fur_source &src) +fold_using_range::range_of_range_op (vrange &r, + gimple_range_op_handler &handler, + fur_source &src) { + gcc_checking_assert (handler); + gimple *s = handler.stmt (); tree type = gimple_range_type (s); if (!type) return false; - range_op_handler handler (s); - gcc_checking_assert (handler); - tree lhs = gimple_get_lhs (s); - tree op1 = gimple_range_operand1 (s); - tree op2 = gimple_range_operand2 (s); + tree lhs = handler.lhs (); + tree op1 = handler.operand1 (); + tree op2 = handler.operand2 (); Value_Range range1 (TREE_TYPE (op1)); Value_Range range2 (op2 ? TREE_TYPE (op2) : TREE_TYPE (op1)); @@ -1430,9 +1366,10 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s, else if (code != BIT_IOR_EXPR && code != TRUTH_OR_EXPR) return; - tree lhs = gimple_get_lhs (s); - tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (s)); - tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (s)); + gimple_range_op_handler handler (s); + tree lhs = handler.lhs (); + tree ssa1 = gimple_range_ssa_p (handler.operand1 ()); + tree ssa2 = gimple_range_ssa_p (handler.operand2 ()); // Deal with || and && only when there is a full set of symbolics. if (!lhs || !ssa1 || !ssa2 @@ -1448,18 +1385,18 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s, gimple *ssa1_stmt = SSA_NAME_DEF_STMT (ssa1); gimple *ssa2_stmt = SSA_NAME_DEF_STMT (ssa2); - range_op_handler handler1 (SSA_NAME_DEF_STMT (ssa1)); - range_op_handler handler2 (SSA_NAME_DEF_STMT (ssa2)); + gimple_range_op_handler handler1 (ssa1_stmt); + gimple_range_op_handler handler2 (ssa2_stmt); // If either handler is not present, no relation can be found. if (!handler1 || !handler2) return; // Both stmts will need to have 2 ssa names in the stmt. - tree ssa1_dep1 = gimple_range_ssa_p (gimple_range_operand1 (ssa1_stmt)); - tree ssa1_dep2 = gimple_range_ssa_p (gimple_range_operand2 (ssa1_stmt)); - tree ssa2_dep1 = gimple_range_ssa_p (gimple_range_operand1 (ssa2_stmt)); - tree ssa2_dep2 = gimple_range_ssa_p (gimple_range_operand2 (ssa2_stmt)); + tree ssa1_dep1 = gimple_range_ssa_p (handler1.operand1 ()); + tree ssa1_dep2 = gimple_range_ssa_p (handler1.operand2 ()); + tree ssa2_dep1 = gimple_range_ssa_p (handler2.operand1 ()); + tree ssa2_dep2 = gimple_range_ssa_p (handler2.operand2 ()); if (!ssa1_dep1 || !ssa1_dep2 || !ssa2_dep1 || !ssa2_dep2) return; @@ -1516,7 +1453,7 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge tree name; basic_block bb = gimple_bb (s); - range_op_handler handler (s); + gimple_range_op_handler handler (s); if (!handler) return; @@ -1529,7 +1466,6 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge e0 = NULL; } - if (e1) { // If this edge is never taken, ignore it. @@ -1544,8 +1480,8 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge // First, register the gcond itself. This will catch statements like // if (a_2 < b_5) - tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (s)); - tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (s)); + tree ssa1 = gimple_range_ssa_p (handler.operand1 ()); + tree ssa2 = gimple_range_ssa_p (handler.operand2 ()); if (ssa1 && ssa2) { if (e0) @@ -1575,11 +1511,11 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge if (TREE_CODE (TREE_TYPE (name)) != BOOLEAN_TYPE) continue; gimple *stmt = SSA_NAME_DEF_STMT (name); - range_op_handler handler (stmt); + gimple_range_op_handler handler (stmt); if (!handler) continue; - tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt)); - tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (stmt)); + tree ssa1 = gimple_range_ssa_p (handler.operand1 ()); + tree ssa2 = gimple_range_ssa_p (handler.operand2 ()); Value_Range r (TREE_TYPE (name)); if (ssa1 && ssa2) { @@ -1600,36 +1536,3 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge } } } - -// Given stmt S, fill VEC, up to VEC_SIZE elements, with relevant ssa-names -// on the statement. For efficiency, it is an error to not pass in enough -// elements for the vector. Return the number of ssa-names. - -unsigned -gimple_range_ssa_names (tree *vec, unsigned vec_size, gimple *stmt) -{ - tree ssa; - int count = 0; - - if (range_op_handler (stmt)) - { - gcc_checking_assert (vec_size >= 2); - if ((ssa = gimple_range_ssa_p (gimple_range_operand1 (stmt)))) - vec[count++] = ssa; - if ((ssa = gimple_range_ssa_p (gimple_range_operand2 (stmt)))) - vec[count++] = ssa; - } - else if (is_a (stmt) - && gimple_assign_rhs_code (stmt) == COND_EXPR) - { - gcc_checking_assert (vec_size >= 3); - gassign *st = as_a (stmt); - if ((ssa = gimple_range_ssa_p (gimple_assign_rhs1 (st)))) - vec[count++] = ssa; - if ((ssa = gimple_range_ssa_p (gimple_assign_rhs2 (st)))) - vec[count++] = ssa; - if ((ssa = gimple_range_ssa_p (gimple_assign_rhs3 (st)))) - vec[count++] = ssa; - } - return count; -} diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h index f2eab720213..ce18c66b8e7 100644 --- a/gcc/gimple-range-fold.h +++ b/gcc/gimple-range-fold.h @@ -96,15 +96,6 @@ range_compatible_p (tree type1, tree type2) && TYPE_SIGN (type1) == TYPE_SIGN (type2)); } -extern tree gimple_range_operand1 (const gimple *s); -extern tree gimple_range_operand2 (const gimple *s); - -// Given stmt S, fill VEC, up to VEC_SIZE elements, with relevant ssa-names -// on the statement. For efficiency, it is an error to not pass in enough -// elements for the vector. Return the number of ssa-names. - -unsigned gimple_range_ssa_names (tree *vec, unsigned vec_size, gimple *stmt); - // Source of all operands for fold_using_range and gori_compute. // It abstracts out the source of an operand so it can come from a stmt or // and edge or anywhere a derived class of fur_source wants. @@ -169,7 +160,8 @@ public: bool fold_stmt (vrange &r, gimple *s, class fur_source &src, tree name = NULL_TREE); protected: - bool range_of_range_op (vrange &r, gimple *s, fur_source &src); + bool range_of_range_op (vrange &r, gimple_range_op_handler &handler, + fur_source &src); bool range_of_call (vrange &r, gcall *call, fur_source &src); bool range_of_cond_expr (vrange &r, gassign* cond, fur_source &src); bool range_of_address (irange &r, gimple *s, fur_source &src); diff --git a/gcc/gimple-range-gori.cc b/gcc/gimple-range-gori.cc index 957b8d543fa..40b2f2f6ae9 100644 --- a/gcc/gimple-range-gori.cc +++ b/gcc/gimple-range-gori.cc @@ -29,83 +29,6 @@ along with GCC; see the file COPYING3. If not see #include "gimple-pretty-print.h" #include "gimple-range.h" -// Calculate what we can determine of the range of this unary -// statement's operand if the lhs of the expression has the range -// LHS_RANGE. Return false if nothing can be determined. - -bool -gimple_range_calc_op1 (vrange &r, const gimple *stmt, const vrange &lhs_range) -{ - gcc_checking_assert (gimple_num_ops (stmt) < 3); - // Give up on empty ranges. - if (lhs_range.undefined_p ()) - return false; - - // Unary operations require the type of the first operand in the - // second range position. - tree type = TREE_TYPE (gimple_range_operand1 (stmt)); - Value_Range type_range (type); - type_range.set_varying (type); - return range_op_handler (stmt).op1_range (r, type, lhs_range, type_range); -} - -// Calculate what we can determine of the range of this statement's -// first operand if the lhs of the expression has the range LHS_RANGE -// and the second operand has the range OP2_RANGE. Return false if -// nothing can be determined. - -bool -gimple_range_calc_op1 (vrange &r, const gimple *stmt, - const vrange &lhs_range, const vrange &op2_range) -{ - // Give up on empty ranges. - if (lhs_range.undefined_p ()) - return false; - - // Unary operation are allowed to pass a range in for second operand - // as there are often additional restrictions beyond the type which - // can be imposed. See operator_cast::op1_range(). - tree type = TREE_TYPE (gimple_range_operand1 (stmt)); - // If op2 is undefined, solve as if it is varying. - if (op2_range.undefined_p ()) - { - // This is sometimes invoked on single operand stmts. - if (gimple_num_ops (stmt) < 3) - return false; - tree op2_type = TREE_TYPE (gimple_range_operand2 (stmt)); - Value_Range trange (op2_type); - trange.set_varying (op2_type); - return range_op_handler (stmt).op1_range (r, type, lhs_range, trange); - } - return range_op_handler (stmt).op1_range (r, type, lhs_range, op2_range); -} - -// Calculate what we can determine of the range of this statement's -// second operand if the lhs of the expression has the range LHS_RANGE -// and the first operand has the range OP1_RANGE. Return false if -// nothing can be determined. - -bool -gimple_range_calc_op2 (vrange &r, const gimple *stmt, - const vrange &lhs_range, const vrange &op1_range) -{ - // Give up on empty ranges. - if (lhs_range.undefined_p ()) - return false; - - tree type = TREE_TYPE (gimple_range_operand2 (stmt)); - // If op1 is undefined, solve as if it is varying. - if (op1_range.undefined_p ()) - { - tree op1_type = TREE_TYPE (gimple_range_operand1 (stmt)); - Value_Range trange (op1_type); - trange.set_varying (op1_type); - return range_op_handler (stmt).op2_range (r, type, lhs_range, trange); - } - return range_op_handler (stmt).op2_range (r, type, lhs_range, - op1_range); -} - // Return TRUE if GS is a logical && or || expression. static inline bool @@ -695,17 +618,18 @@ gori_compute::compute_operand_range (vrange &r, gimple *stmt, if (is_a (stmt)) return compute_operand_range_switch (r, as_a (stmt), lhs, name, src); - if (!range_op_handler (stmt)) + gimple_range_op_handler handler (stmt); + if (!handler) return false; - tree op1 = gimple_range_ssa_p (gimple_range_operand1 (stmt)); - tree op2 = gimple_range_ssa_p (gimple_range_operand2 (stmt)); + tree op1 = gimple_range_ssa_p (handler.operand1 ()); + tree op2 = gimple_range_ssa_p (handler.operand2 ()); // Handle end of lookup first. if (op1 == name) - return compute_operand1_range (r, stmt, lhs, name, src); + return compute_operand1_range (r, handler, lhs, name, src); if (op2 == name) - return compute_operand2_range (r, stmt, lhs, name, src); + return compute_operand2_range (r, handler, lhs, name, src); // NAME is not in this stmt, but one of the names in it ought to be // derived from it. @@ -733,10 +657,10 @@ gori_compute::compute_operand_range (vrange &r, gimple *stmt, tree type = TREE_TYPE (name); Value_Range op1_trange (type), op1_frange (type); Value_Range op2_trange (type), op2_frange (type); - compute_logical_operands (op1_trange, op1_frange, stmt, + compute_logical_operands (op1_trange, op1_frange, handler, as_a (lhs), name, src, op1, op1_in_chain); - compute_logical_operands (op2_trange, op2_frange, stmt, + compute_logical_operands (op2_trange, op2_frange, handler, as_a (lhs), name, src, op2, op2_in_chain); res = logical_combine (r, @@ -748,11 +672,11 @@ gori_compute::compute_operand_range (vrange &r, gimple *stmt, } // Follow the appropriate operands now. else if (op1_in_chain && op2_in_chain) - res = compute_operand1_and_operand2_range (r, stmt, lhs, name, src); + res = compute_operand1_and_operand2_range (r, handler, lhs, name, src); else if (op1_in_chain) - res = compute_operand1_range (r, stmt, lhs, name, src); + res = compute_operand1_range (r, handler, lhs, name, src); else if (op2_in_chain) - res = compute_operand2_range (r, stmt, lhs, name, src); + res = compute_operand2_range (r, handler, lhs, name, src); else gcc_unreachable (); @@ -944,13 +868,14 @@ gori_compute::logical_combine (vrange &r, enum tree_code code, void gori_compute::compute_logical_operands (vrange &true_range, vrange &false_range, - gimple *stmt, + gimple_range_op_handler &handler, const irange &lhs, tree name, fur_source &src, tree op, bool op_in_chain) { + gimple *stmt = handler.stmt (); gimple *src_stmt = gimple_range_ssa_p (op) ? SSA_NAME_DEF_STMT (op) : NULL; - if (!op_in_chain || !src_stmt || chain_import_p (gimple_get_lhs (stmt), op)) + if (!op_in_chain || !src_stmt || chain_import_p (handler.lhs (), op)) { // If op is not in the def chain, or defined in this block, // use its known value on entry to the block. @@ -999,12 +924,15 @@ gori_compute::compute_logical_operands (vrange &true_range, vrange &false_range, // R, or false if no range could be calculated. bool -gori_compute::compute_operand1_range (vrange &r, gimple *stmt, +gori_compute::compute_operand1_range (vrange &r, + gimple_range_op_handler &handler, const vrange &lhs, tree name, fur_source &src) { - tree op1 = gimple_range_operand1 (stmt); - tree op2 = gimple_range_operand2 (stmt); + gimple *stmt = handler.stmt (); + tree op1 = handler.operand1 (); + tree op2 = handler.operand2 (); + Value_Range op1_range (TREE_TYPE (op1)); Value_Range tmp (TREE_TYPE (op1)); Value_Range op2_range (op2 ? TREE_TYPE (op2) : TREE_TYPE (op1)); @@ -1016,7 +944,7 @@ gori_compute::compute_operand1_range (vrange &r, gimple *stmt, if (op2) { src.get_operand (op2_range, op2); - if (!gimple_range_calc_op1 (tmp, stmt, lhs, op2_range)) + if (!handler.calc_op1 (tmp, lhs, op2_range)) return false; } else @@ -1024,7 +952,7 @@ gori_compute::compute_operand1_range (vrange &r, gimple *stmt, // We pass op1_range to the unary operation. Nomally it's a // hidden range_for_type parameter, but sometimes having the // actual range can result in better information. - if (!gimple_range_calc_op1 (tmp, stmt, lhs, op1_range)) + if (!handler.calc_op1 (tmp, lhs, op1_range)) return false; } @@ -1079,12 +1007,15 @@ gori_compute::compute_operand1_range (vrange &r, gimple *stmt, // R, or false if no range could be calculated. bool -gori_compute::compute_operand2_range (vrange &r, gimple *stmt, +gori_compute::compute_operand2_range (vrange &r, + gimple_range_op_handler &handler, const vrange &lhs, tree name, fur_source &src) { - tree op1 = gimple_range_operand1 (stmt); - tree op2 = gimple_range_operand2 (stmt); + gimple *stmt = handler.stmt (); + tree op1 = handler.operand1 (); + tree op2 = handler.operand2 (); + Value_Range op1_range (TREE_TYPE (op1)); Value_Range op2_range (TREE_TYPE (op2)); Value_Range tmp (TREE_TYPE (op2)); @@ -1093,7 +1024,7 @@ gori_compute::compute_operand2_range (vrange &r, gimple *stmt, src.get_operand (op2_range, op2); // Intersect with range for op2 based on lhs and op1. - if (!gimple_range_calc_op2 (tmp, stmt, lhs, op1_range)) + if (!handler.calc_op2 (tmp, lhs, op1_range)) return false; unsigned idx; @@ -1148,7 +1079,8 @@ gori_compute::compute_operand2_range (vrange &r, gimple *stmt, bool gori_compute::compute_operand1_and_operand2_range (vrange &r, - gimple *stmt, + gimple_range_op_handler + &handler, const vrange &lhs, tree name, fur_source &src) @@ -1157,11 +1089,11 @@ gori_compute::compute_operand1_and_operand2_range (vrange &r, // Calculate a good a range for op2. Since op1 == op2, this will // have already included whatever the actual range of name is. - if (!compute_operand2_range (op_range, stmt, lhs, name, src)) + if (!compute_operand2_range (op_range, handler, lhs, name, src)) return false; // Now get the range thru op1. - if (!compute_operand1_range (r, stmt, lhs, name, src)) + if (!compute_operand1_range (r, handler, lhs, name, src)) return false; // Both operands have to be simultaneously true, so perform an intersection. diff --git a/gcc/gimple-range-gori.h b/gcc/gimple-range-gori.h index 3d57ab94624..0c776ef853f 100644 --- a/gcc/gimple-range-gori.h +++ b/gcc/gimple-range-gori.h @@ -170,17 +170,18 @@ private: tree name, class fur_source &src); bool compute_operand_range_switch (vrange &r, gswitch *s, const vrange &lhs, tree name, fur_source &src); - bool compute_operand1_range (vrange &r, gimple *stmt, const vrange &lhs, - tree name, fur_source &src); - bool compute_operand2_range (vrange &r, gimple *stmt, const vrange &lhs, - tree name, fur_source &src); - bool compute_operand1_and_operand2_range (vrange &r, gimple *stmt, + bool compute_operand1_range (vrange &r, gimple_range_op_handler &handler, + const vrange &lhs, tree name, fur_source &src); + bool compute_operand2_range (vrange &r, gimple_range_op_handler &handler, + const vrange &lhs, tree name, fur_source &src); + bool compute_operand1_and_operand2_range (vrange &r, + gimple_range_op_handler &handler, const vrange &lhs, tree name, fur_source &src); void compute_logical_operands (vrange &true_range, vrange &false_range, - gimple *stmt, const irange &lhs, - tree name, fur_source &src, tree op, - bool op_in_chain); + gimple_range_op_handler &handler, + const irange &lhs, tree name, fur_source &src, + tree op, bool op_in_chain); bool logical_combine (vrange &r, enum tree_code code, const irange &lhs, const vrange &op1_true, const vrange &op1_false, const vrange &op2_true, const vrange &op2_false); @@ -192,16 +193,6 @@ private: int m_not_executable_flag; }; -// These routines provide a GIMPLE interface to the range-ops code. -extern bool gimple_range_calc_op1 (vrange &r, const gimple *s, - const vrange &lhs_range); -extern bool gimple_range_calc_op1 (vrange &r, const gimple *s, - const vrange &lhs_range, - const vrange &op2_range); -extern bool gimple_range_calc_op2 (vrange &r, const gimple *s, - const vrange &lhs_range, - const vrange &op1_range); - // For each name that is an import into BB's exports.. #define FOR_EACH_GORI_IMPORT_NAME(gori, bb, name) \ for (gori_export_iterator iter ((gori).imports ((bb))); \ diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc new file mode 100644 index 00000000000..f03125a0fc5 --- /dev/null +++ b/gcc/gimple-range-op.cc @@ -0,0 +1,245 @@ +/* Code for GIMPLE range op related routines. + Copyright (C) 2019-2022 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 +. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "backend.h" +#include "insn-codes.h" +#include "tree.h" +#include "gimple.h" +#include "ssa.h" +#include "gimple-pretty-print.h" +#include "optabs-tree.h" +#include "gimple-iterator.h" +#include "gimple-fold.h" +#include "wide-int.h" +#include "fold-const.h" +#include "case-cfn-macros.h" +#include "omp-general.h" +#include "cfgloop.h" +#include "tree-ssa-loop.h" +#include "tree-scalar-evolution.h" +#include "langhooks.h" +#include "vr-values.h" +#include "range.h" +#include "value-query.h" +#include "gimple-range.h" + +// Given stmt S, fill VEC, up to VEC_SIZE elements, with relevant ssa-names +// on the statement. For efficiency, it is an error to not pass in enough +// elements for the vector. Return the number of ssa-names. + +unsigned +gimple_range_ssa_names (tree *vec, unsigned vec_size, gimple *stmt) +{ + tree ssa; + int count = 0; + + gimple_range_op_handler handler (stmt); + if (handler) + { + gcc_checking_assert (vec_size >= 2); + if ((ssa = gimple_range_ssa_p (handler.operand1 ()))) + vec[count++] = ssa; + if ((ssa = gimple_range_ssa_p (handler.operand2 ()))) + vec[count++] = ssa; + } + else if (is_a (stmt) + && gimple_assign_rhs_code (stmt) == COND_EXPR) + { + gcc_checking_assert (vec_size >= 3); + gassign *st = as_a (stmt); + if ((ssa = gimple_range_ssa_p (gimple_assign_rhs1 (st)))) + vec[count++] = ssa; + if ((ssa = gimple_range_ssa_p (gimple_assign_rhs2 (st)))) + vec[count++] = ssa; + if ((ssa = gimple_range_ssa_p (gimple_assign_rhs3 (st)))) + vec[count++] = ssa; + } + return count; +} + +// Return the base of the RHS of an assignment. + +static tree +gimple_range_base_of_assignment (const gimple *stmt) +{ + gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN); + tree op1 = gimple_assign_rhs1 (stmt); + if (gimple_assign_rhs_code (stmt) == ADDR_EXPR) + return get_base_address (TREE_OPERAND (op1, 0)); + return op1; +} + +// If statement is supported by range-ops, set the CODE and return the TYPE. + +static tree +get_code_and_type (gimple *s, enum tree_code &code) +{ + tree type = NULL_TREE; + code = NOP_EXPR; + + if (const gassign *ass = dyn_cast (s)) + { + 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) + type = TREE_TYPE (gimple_assign_rhs1 (ass)); + else + type = TREE_TYPE (gimple_assign_lhs (ass)); + } + else if (const gcond *cond = dyn_cast (s)) + { + code = gimple_cond_code (cond); + type = TREE_TYPE (gimple_cond_lhs (cond)); + } + return type; +} + +// If statement S has a supported range_op handler return TRUE. + +bool +gimple_range_op_handler::supported_p (gimple *s) +{ + enum tree_code code; + tree type = get_code_and_type (s, code); + return (type && range_op_handler (code, type)); +} + +// Construct a handler object for statement S. + +gimple_range_op_handler::gimple_range_op_handler (gimple *s) +{ + enum tree_code code; + tree type = get_code_and_type (s, code); + m_stmt = s; + if (type) + set_op_handler (code, type); + + if (m_valid) + switch (gimple_code (m_stmt)) + { + case GIMPLE_COND: + m_op1 = gimple_cond_lhs (m_stmt); + m_op2 = gimple_cond_rhs (m_stmt); + break; + case GIMPLE_ASSIGN: + m_op1 = gimple_range_base_of_assignment (m_stmt); + if (m_op1 && TREE_CODE (m_op1) == MEM_REF) + { + // If the base address is an SSA_NAME, we return it + // here. This allows processing of the range of that + // name, while the rest of the expression is simply + // ignored. The code in range_ops will see the + // ADDR_EXPR and do the right thing. + tree ssa = TREE_OPERAND (m_op1, 0); + if (TREE_CODE (ssa) == SSA_NAME) + m_op1 = ssa; + } + if (gimple_num_ops (m_stmt) >= 3) + m_op2 = gimple_assign_rhs2 (m_stmt); + else + m_op2 = NULL_TREE; + break; + default: + m_op1 = NULL_TREE; + m_op2 = NULL_TREE; + break; + } +} + +// Calculate what we can determine of the range of this unary +// statement's operand if the lhs of the expression has the range +// LHS_RANGE. Return false if nothing can be determined. + +bool +gimple_range_op_handler::calc_op1 (vrange &r, const vrange &lhs_range) +{ + gcc_checking_assert (gimple_num_ops (m_stmt) < 3); + // Give up on empty ranges. + if (lhs_range.undefined_p ()) + return false; + + // Unary operations require the type of the first operand in the + // second range position. + tree type = TREE_TYPE (operand1 ()); + Value_Range type_range (type); + type_range.set_varying (type); + return op1_range (r, type, lhs_range, type_range); +} + +// Calculate what we can determine of the range of this statement's +// first operand if the lhs of the expression has the range LHS_RANGE +// and the second operand has the range OP2_RANGE. Return false if +// nothing can be determined. + +bool +gimple_range_op_handler::calc_op1 (vrange &r, const vrange &lhs_range, + const vrange &op2_range) +{ + // Give up on empty ranges. + if (lhs_range.undefined_p ()) + return false; + + // Unary operation are allowed to pass a range in for second operand + // as there are often additional restrictions beyond the type which + // can be imposed. See operator_cast::op1_range(). + tree type = TREE_TYPE (operand1 ()); + // If op2 is undefined, solve as if it is varying. + if (op2_range.undefined_p ()) + { + // This is sometimes invoked on single operand stmts. + if (gimple_num_ops (m_stmt) < 3) + return false; + tree op2_type = TREE_TYPE (operand2 ()); + Value_Range trange (op2_type); + trange.set_varying (op2_type); + return op1_range (r, type, lhs_range, trange); + } + return op1_range (r, type, lhs_range, op2_range); +} + +// Calculate what we can determine of the range of this statement's +// second operand if the lhs of the expression has the range LHS_RANGE +// and the first operand has the range OP1_RANGE. Return false if +// nothing can be determined. + +bool +gimple_range_op_handler::calc_op2 (vrange &r, const vrange &lhs_range, + const vrange &op1_range) +{ + // Give up on empty ranges. + if (lhs_range.undefined_p ()) + return false; + + tree type = TREE_TYPE (operand2 ()); + // If op1 is undefined, solve as if it is varying. + if (op1_range.undefined_p ()) + { + tree op1_type = TREE_TYPE (operand1 ()); + Value_Range trange (op1_type); + trange.set_varying (op1_type); + return op2_range (r, type, lhs_range, trange); + } + return op2_range (r, type, lhs_range, op1_range); +} diff --git a/gcc/gimple-range-op.h b/gcc/gimple-range-op.h new file mode 100644 index 00000000000..8bc0a8fbe11 --- /dev/null +++ b/gcc/gimple-range-op.h @@ -0,0 +1,51 @@ +/* Header file for the GIMPLE range-op interface. + Copyright (C) 2022 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_GIMPLE_RANGE_OP_H +#define GCC_GIMPLE_RANGE_OP_H + +#include "range-op.h" + + +class gimple_range_op_handler : public range_op_handler +{ +public: + static bool supported_p (gimple *s); + gimple_range_op_handler (gimple *s); + inline gimple *stmt () const { return m_stmt; } + inline tree lhs () const { return gimple_get_lhs (m_stmt); } + tree operand1 () const { gcc_checking_assert (m_valid); return m_op1; } + tree operand2 () const { gcc_checking_assert (m_valid); return m_op2; } + bool calc_op1 (vrange &r, const vrange &lhs_range); + bool calc_op1 (vrange &r, const vrange &lhs_range, const vrange &op2_range); + bool calc_op2 (vrange &r, const vrange &lhs_range, const vrange &op1_range); +private: + gimple *m_stmt; + tree m_op1, m_op2; +}; + +// Given stmt S, fill VEC, up to VEC_SIZE elements, with relevant ssa-names +// on the statement. For efficiency, it is an error to not pass in enough +// elements for the vector. Return the number of ssa-names. + +unsigned gimple_range_ssa_names (tree *vec, unsigned vec_size, gimple *stmt); + +#endif // GCC_GIMPLE_RANGE_OP_H diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc index eb347eee45b..d67d6499c78 100644 --- a/gcc/gimple-range.cc +++ b/gcc/gimple-range.cc @@ -341,7 +341,7 @@ gimple_ranger::prefill_name (vrange &r, tree name) if (!gimple_range_ssa_p (name)) return; gimple *stmt = SSA_NAME_DEF_STMT (name); - if (!range_op_handler (stmt) && !is_a (stmt)) + if (!gimple_range_op_handler::supported_p (stmt) && !is_a (stmt)) return; bool current; @@ -364,7 +364,7 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa) gcc_checking_assert (stmt && gimple_bb (stmt)); // Only pre-process range-ops and phis. - if (!range_op_handler (stmt) && !is_a (stmt)) + if (!gimple_range_op_handler::supported_p (stmt) && !is_a (stmt)) return; // Mark where on the stack we are starting. @@ -422,14 +422,15 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa) } else { - gcc_checking_assert (range_op_handler (stmt)); - tree op = gimple_range_operand2 (stmt); + gimple_range_op_handler handler (stmt); + gcc_checking_assert (handler); + tree op = handler.operand2 (); if (op) { Value_Range r (TREE_TYPE (op)); prefill_name (r, op); } - op = gimple_range_operand1 (stmt); + op = handler.operand1 (); if (op) { Value_Range r (TREE_TYPE (op)); diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h index 34f61025ac3..8b2ff5685e5 100644 --- a/gcc/gimple-range.h +++ b/gcc/gimple-range.h @@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see #include "range.h" #include "value-query.h" -#include "range-op.h" +#include "gimple-range-op.h" #include "gimple-range-trace.h" #include "gimple-range-edge.h" #include "gimple-range-fold.h" diff --git a/gcc/range-op.cc b/gcc/range-op.cc index f642b3f26de..9ae42b8331f 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -4182,42 +4182,19 @@ range_op_handler::set_op_handler (tree_code code, tree type) } } -range_op_handler::range_op_handler (tree_code code, tree type) +range_op_handler::range_op_handler () { - set_op_handler (code, type); + m_int = NULL; + m_float = NULL; + m_valid = false; } -range_op_handler::range_op_handler (const gimple *s) +range_op_handler::range_op_handler (tree_code code, tree type) { - tree_code code = NOP_EXPR; - tree type = NULL_TREE; - - if (const gassign *ass = dyn_cast (s)) - { - 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) - type = TREE_TYPE (gimple_assign_rhs1 (ass)); - else - type = TREE_TYPE (gimple_assign_lhs (ass)); - } - else if (const gcond *cond = dyn_cast (s)) - { - code = gimple_cond_code (cond); - type = TREE_TYPE (gimple_cond_lhs (cond)); - } - - if (!type) - { - m_int = NULL; - m_float = NULL; - m_valid = false; - } - else - set_op_handler (code, type); + set_op_handler (code, type); } + bool range_op_handler::fold_range (vrange &r, tree type, const vrange &lh, diff --git a/gcc/range-op.h b/gcc/range-op.h index 56c57c46a8e..b4b5101a9e0 100644 --- a/gcc/range-op.h +++ b/gcc/range-op.h @@ -160,8 +160,8 @@ public: class range_op_handler { public: + range_op_handler (); range_op_handler (enum tree_code code, tree type); - range_op_handler (const gimple *s); inline operator bool () const { return m_valid; } bool fold_range (vrange &r, tree type, @@ -185,7 +185,7 @@ public: const vrange &op2, relation_kind = VREL_VARYING) const; relation_kind op1_op2_relation (const vrange &lhs) const; -private: +protected: void set_op_handler (enum tree_code code, tree type); bool m_valid; range_operator *m_int; -- 2.37.3