From patchwork Wed Nov 24 11:40:07 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Biener X-Patchwork-Id: 48057 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 1BCDC3857C64 for ; Wed, 24 Nov 2021 11:40:38 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1BCDC3857C64 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1637754038; bh=RvRG8iAeejodao+VqrALruJ5+A+iQiZfJ41NTBJXaSY=; h=Date:To:Subject:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=hREIOgsl31PJmfqJhNI2H9bjgJbHJ3jjf2SYFarLPFGOpWxhFqXlKmc3QilpQ6W+s qPm54eEmWoWHGjoah7D8lkyFbaydvG1OPdsKmsi/EAdIuSpebeZRF3GH9f8Dy7r3qQ mv4yJ9LMXMIB7bMzx/OHTJc/fkMj3rU3z4/GW9hA= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by sourceware.org (Postfix) with ESMTPS id CC93C385840E for ; Wed, 24 Nov 2021 11:40:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org CC93C385840E Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 9DD931FD63; Wed, 24 Nov 2021 11:40:07 +0000 (UTC) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 7A85813A61; Wed, 24 Nov 2021 11:40:07 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id NdqwHJcknmGgCwAAMHmgww (envelope-from ); Wed, 24 Nov 2021 11:40:07 +0000 Date: Wed, 24 Nov 2021 12:40:07 +0100 (CET) To: gcc-patches@gcc.gnu.org Subject: [PATCH] tree-optimization/103168 - Improve VN of pure function calls Message-ID: <1o6qo129-2591-o7po-p67q-3ns82312sp7q@fhfr.qr> MIME-Version: 1.0 X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) 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: Richard Biener via Gcc-patches From: Richard Biener Reply-To: Richard Biener Cc: hubicka@ucw.cz Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" This improves value-numbering of calls that read memory, calls to const functions with aggregate arguments and calls to pure functions where the latter include const functions we demoted to pure for the fear of interposing with a less optimized version. Note that for pure functions we do not handle functions that access global memory. Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed. Richard. 2021-11-24 Richard Biener Jan Hubicka PR tree-optimization/103168 * ipa-modref.h (struct modref_summary): Add load_accesses. * ipa-modref.c (modref_summary::finalize): Initialize load_accesses. * tree-ssa-sccvn.c (visit_reference_op_call): Use modref info to walk the virtual use->def chain to CSE const/pure function calls possibly reading from memory. * g++.dg/tree-ssa/pr103168.C: New testcase. --- gcc/ipa-modref.c | 17 +++ gcc/ipa-modref.h | 2 + gcc/testsuite/g++.dg/tree-ssa/pr103168.C | 24 +++++ gcc/tree-ssa-sccvn.c | 126 +++++++++++++++++++++++ 4 files changed, 169 insertions(+) create mode 100644 gcc/testsuite/g++.dg/tree-ssa/pr103168.C diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index 79d7d774715..923ae6c1dd3 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -721,6 +721,23 @@ modref_summary::finalize (tree fun) break; } } + if (loads->every_base) + load_accesses = 1; + else + { + load_accesses = 0; + for (auto base_node : loads->bases) + { + if (base_node->every_ref) + load_accesses++; + else + for (auto ref_node : base_node->refs) + if (ref_node->every_access) + load_accesses++; + else + load_accesses += ref_node->accesses->length (); + } + } } /* Get function summary for FUNC if it exists, return NULL otherwise. */ diff --git a/gcc/ipa-modref.h b/gcc/ipa-modref.h index f868eb6de07..a0247f5449f 100644 --- a/gcc/ipa-modref.h +++ b/gcc/ipa-modref.h @@ -53,6 +53,8 @@ struct GTY(()) modref_summary /* Flags coputed by finalize method. */ + /* Total number of accesses in loads tree. */ + unsigned int load_accesses; /* global_memory_read is not set for functions calling functions with !binds_to_current_def which, after interposition, may read global memory but do nothing useful with it (except for crashing if some diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr103168.C b/gcc/testsuite/g++.dg/tree-ssa/pr103168.C new file mode 100644 index 00000000000..82924a3e3ce --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/pr103168.C @@ -0,0 +1,24 @@ +// { dg-do compile } +// { dg-options "-O2 -fdump-tree-fre1-details" } + +struct a +{ + int a; + static __attribute__ ((noinline)) + int ret (int v) {return v;} + + __attribute__ ((noinline)) + int inca () {return a++;} +}; + +int +test() +{ + struct a av; + av.a=1; + int val = av.ret (0) + av.inca(); + av.a=2; + return val + av.ret(0) + av.inca(); +} + +/* { dg-final { scan-tree-dump-times "Replaced a::ret" 1 "fre1" } } */ diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c index 149674e6a16..d31bf329d2e 100644 --- a/gcc/tree-ssa-sccvn.c +++ b/gcc/tree-ssa-sccvn.c @@ -71,6 +71,8 @@ along with GCC; see the file COPYING3. If not see #include "tree-ssa-loop-niter.h" #include "builtins.h" #include "fold-const-call.h" +#include "ipa-modref-tree.h" +#include "ipa-modref.h" #include "tree-ssa-sccvn.h" /* This algorithm is based on the SCC algorithm presented by Keith @@ -5084,12 +5086,136 @@ visit_reference_op_call (tree lhs, gcall *stmt) struct vn_reference_s vr1; vn_reference_t vnresult = NULL; tree vdef = gimple_vdef (stmt); + modref_summary *summary; /* Non-ssa lhs is handled in copy_reference_ops_from_call. */ if (lhs && TREE_CODE (lhs) != SSA_NAME) lhs = NULL_TREE; vn_reference_lookup_call (stmt, &vnresult, &vr1); + + /* If the lookup did not succeed for pure functions try to use + modref info to find a candidate to CSE to. */ + const unsigned accesses_limit = 8; + if (!vnresult + && !vdef + && lhs + && gimple_vuse (stmt) + && (((summary = get_modref_function_summary (stmt, NULL)) + && !summary->global_memory_read + && summary->load_accesses < accesses_limit) + || gimple_call_flags (stmt) & ECF_CONST)) + { + /* First search if we can do someting useful and build a + vector of all loads we have to check. */ + bool unknown_memory_access = false; + auto_vec accesses; + unsigned load_accesses = summary ? summary->load_accesses : 0; + if (!unknown_memory_access) + /* Add loads done as part of setting up the call arguments. + That's also necessary for CONST functions which will + not have a modref summary. */ + for (unsigned i = 0; i < gimple_call_num_args (stmt); ++i) + { + tree arg = gimple_call_arg (stmt, i); + if (TREE_CODE (arg) != SSA_NAME + && !is_gimple_min_invariant (arg)) + { + if (accesses.length () >= accesses_limit - load_accesses) + { + unknown_memory_access = true; + break; + } + accesses.quick_grow (accesses.length () + 1); + ao_ref_init (&accesses.last (), arg); + } + } + if (summary && !unknown_memory_access) + { + /* Add loads as analyzed by IPA modref. */ + for (auto base_node : summary->loads->bases) + if (unknown_memory_access) + break; + else for (auto ref_node : base_node->refs) + if (unknown_memory_access) + break; + else for (auto access_node : ref_node->accesses) + { + accesses.quick_grow (accesses.length () + 1); + ao_ref *r = &accesses.last (); + if (!access_node.get_ao_ref (stmt, r)) + { + /* Initialize a ref based on the argument and + unknown offset if possible. */ + tree arg = access_node.get_call_arg (stmt); + if (arg && TREE_CODE (arg) == SSA_NAME) + arg = SSA_VAL (arg); + if (arg + && TREE_CODE (arg) == ADDR_EXPR + && (arg = get_base_address (arg)) + && DECL_P (arg)) + { + ao_ref_init (r, arg); + r->ref = NULL_TREE; + r->base = arg; + } + else + { + unknown_memory_access = true; + break; + } + } + r->base_alias_set = base_node->base; + r->ref_alias_set = ref_node->ref; + } + } + + /* Walk the VUSE->VDEF chain optimistically trying to find an entry + for the call in the hashtable. */ + unsigned limit = (unknown_memory_access + ? 0 + : (param_sccvn_max_alias_queries_per_access + / (accesses.length () + 1))); + tree saved_vuse = vr1.vuse; + hashval_t saved_hashcode = vr1.hashcode; + while (limit > 0 && !vnresult && !SSA_NAME_IS_DEFAULT_DEF (vr1.vuse)) + { + vr1.hashcode = vr1.hashcode - SSA_NAME_VERSION (vr1.vuse); + gimple *def = SSA_NAME_DEF_STMT (vr1.vuse); + /* ??? We could use fancy stuff like in walk_non_aliased_vuses, but + do not bother for now. */ + if (is_a (def)) + break; + vr1.vuse = vuse_ssa_val (gimple_vuse (def)); + vr1.hashcode = vr1.hashcode + SSA_NAME_VERSION (vr1.vuse); + vn_reference_lookup_1 (&vr1, &vnresult); + limit--; + } + + /* If we found a candidate to CSE to verify it is valid. */ + if (vnresult && !accesses.is_empty ()) + { + tree vuse = vuse_ssa_val (gimple_vuse (stmt)); + while (vnresult && vuse != vr1.vuse) + { + gimple *def = SSA_NAME_DEF_STMT (vuse); + for (auto &ref : accesses) + { + /* ??? stmt_may_clobber_ref_p_1 does per stmt constant + analysis overhead that we might be able to cache. */ + if (stmt_may_clobber_ref_p_1 (def, &ref, true)) + { + vnresult = NULL; + break; + } + } + vuse = vuse_ssa_val (gimple_vuse (def)); + } + } + vr1.vuse = saved_vuse; + vr1.hashcode = saved_hashcode; + } + if (vnresult) { if (vnresult->result_vdef && vdef)