From patchwork Sat Nov 12 01:47:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Jambor X-Patchwork-Id: 19079 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a5d:6687:0:0:0:0:0 with SMTP id l7csp1063290wru; Fri, 11 Nov 2022 17:52:42 -0800 (PST) X-Google-Smtp-Source: AA0mqf42vr4LaUVg/6s89ai/I3Xg+nEkfLfPHnlxD1BkY8ZiROLidk2M/muzSkL56NOCO8W/TMQx X-Received: by 2002:a50:ec8c:0:b0:462:719:3372 with SMTP id e12-20020a50ec8c000000b0046207193372mr3765198edr.361.1668217962357; Fri, 11 Nov 2022 17:52:42 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1668217962; cv=none; d=google.com; s=arc-20160816; b=a0Lf53ABMhYS7Hgd+OKYL7n4pev23pSu1zQZpJcF1lL6W9/GjDrGVMn0QMHNQcu9Nv NXOSLARSyjHZoSUAYqPbT3Zs2Rozf1EN+F3fN28RQtgHtAAT3C0deW+TBJPakW63lef9 l0QM1veiYsNbEOEqJZZ4veoJI7yniUMaZ/09qaxcpSR1mV3B7yZCDVkvUZvbCk3DxVej /tZjYcv6gE/My2a5KMWKw0i9Cpg/CfoSkVA0roVa7sX0Tt4TeCHvg5gFTGgis0n3HOeI 9hOoGFA7KTU/i/lrDfqDc6xFtEZzXXzYlVcQomoZLqY8YGu/aBf6CPBo67Dcqwbl6uyo UCuw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:mime-version:message-id:date :user-agent:subject:cc:to:from:dkim-signature:dkim-signature :dmarc-filter:delivered-to; bh=96yuyE2F21GicB1NpsykOKa1A75JfNAuS+e4305+8js=; b=zXca7BiO6WwPvzv+53QDB8MVS6139dC5RcJ9lkg/ihnfZyfjcDXuxpp8LadkafaJTy qJMUaDauIwP7q7h+QQRlQOoCfB6ywET9zGxlwJBF1Hbh7VIE7DICXxwaKkLq+6Rxal4M R6xv9inohd1OCDUrxPeLmGJYXbym4Asvb6Z4aUEfQTUYEGX3w6JUY48kWpHB2OAPHiji RmgqpouYmlcGRhilSnofyt9u8jbyh88S7QDnMUJKKikA0IH1HxDpjSLypyuegibCd1iw vmZ+3Ue3hSNqSXHGtxOdfN7x1MwMBeIIwbjUdkJERgpF+9PqGCEDql5fwPBcebhCThhc +AzQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@suse.cz header.s=susede2_rsa header.b=L92PDO25; dkim=neutral (no key) header.i=@suse.cz; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from sourceware.org (server2.sourceware.org. [8.43.85.97]) by mx.google.com with ESMTPS id qb24-20020a1709077e9800b0078db5170767si3959688ejc.18.2022.11.11.17.52.42 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 11 Nov 2022 17:52:42 -0800 (PST) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) client-ip=8.43.85.97; Authentication-Results: mx.google.com; dkim=pass header.i=@suse.cz header.s=susede2_rsa header.b=L92PDO25; dkim=neutral (no key) header.i=@suse.cz; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 8.43.85.97 as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D02FA3959CB1 for ; Sat, 12 Nov 2022 01:48:45 +0000 (GMT) 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 773353899047 for ; Sat, 12 Nov 2022 01:47:36 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 773353899047 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=suse.cz Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=suse.cz 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 9F82B1F381; Sat, 12 Nov 2022 01:47:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.cz; s=susede2_rsa; t=1668217655; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type; bh=96yuyE2F21GicB1NpsykOKa1A75JfNAuS+e4305+8js=; b=L92PDO25PnspeENE+aLXXdvf1V1XZuEA/p8J6cgUZPJah58YJFydAHHfGXRYySJNKShso/ gaFm50j+K1QX3+yM+aV0OZGkIwUh+NmkgzvwZvAyK66ivr8rCfd9oASmW+tEQ8gtEAAjUK gKn6zh3kKx9Sn/Uqkkgv88tooTbfEJY= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.cz; s=susede2_ed25519; t=1668217655; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type; bh=96yuyE2F21GicB1NpsykOKa1A75JfNAuS+e4305+8js=; b=r85pl1mngxtkbUXGkuxxYxUn9EEwgDBOP0GREWThNbo+/w7Y38hFgtVEgbW4bCI1fy3UN7 aFdHizX0VjS5J3BQ== 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 8D8D513A08; Sat, 12 Nov 2022 01:47:35 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id nG1gIjf7bmO7ZAAAMHmgww (envelope-from ); Sat, 12 Nov 2022 01:47:35 +0000 From: Martin Jambor To: GCC Patches Cc: Jan Hubicka , Jan Hubicka Subject: [PATCH 10/12] ipa-sra: Forward propagation of sizes which are safe to dereference User-Agent: Notmuch/0.37 (https://notmuchmail.org) Emacs/28.1 (x86_64-suse-linux-gnu) Date: Sat, 12 Nov 2022 02:47:35 +0100 Message-ID: MIME-Version: 1.0 X-Spam-Status: No, score=-11.8 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.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: , Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1749253317822694364?= X-GMAIL-MSGID: =?utf-8?q?1749253317822694364?= Hi, the previous patch established a way to propagate information about parameters from callers to callees (even though then the actual splitting is done in the opposite direction), this patch adds to that information about size of the parameters that is known to be safe to dereference in the callers - the information currently does not come from actual dereferences but only when we pass a reference to a known declaration, but we can use e.g. dereferences in BBs dominating the call, for example too, if we decide it is worth it. References which look like splitting candidates but are not always dereferenced are - assuming the dereferences are not improbable - not discarded straight away but only marked as conditionally dereferenceable. IPA phase then makes sure that they stay candidates only if all incoming edges have big enough known-to-be-safe size. Bootstrapped and tested on x86_64-linux. OK for master? Thanks, Martin gcc/ChangeLog: 2022-11-11 Martin Jambor * ipa-sra.cc (isra_param_desc): New fields safe_size, conditionally_dereferenceable and safe_size_set. (struct gensum_param_desc): New field conditionally_dereferenceable. (struct isra_param_flow): Updated comment of field unit_size. (ipa_sra_function_summaries::duplicate): Copy the new fields. (isra_call_summary::dump): Dump unit_size when representing safe_size. (dump_gensum_param_descriptor): Dump new flag. (dump_isra_param_descriptor): Dump new fields. (isra_analyze_call): Fill unit_size when it represents known safe size. (check_gensum_access): Instead of disqualifying pointers which are not always dereference, mark them as conditionally dereferencable if loads are frequent enough. (process_scan_results): Copy the conditionally_dereferenceable flag. (isra_write_node_summary): Stream new fields, or assert they are not initialized yet. (isra_read_node_info): Stream new fields. (update_safe_size): New function. (propagate_param_hints_accross_call): Propagate safe_sizes. (propagate_hints_to_all_callees): New function. (adjust_parameter_descriptions): Check conditionally_dereferenceable candidates, rework dumping. (ipa_sra_analysis): Move most of hint propagation for one node to propagate_hints_to_all_callees. Add another loop to stabilize within SCCs and another one to verify. gcc/testsuite/ChangeLog: 2022-11-11 Martin Jambor * gcc.dg/ipa/ipa-sra-26.c: New test. * gcc.dg/ipa/ipa-sra-27.c: Likewise. * gcc.dg/ipa/ipa-sra-28.c: Likewise. --- gcc/ipa-sra.cc | 253 ++++++++++++++++++++------ gcc/testsuite/gcc.dg/ipa/ipa-sra-26.c | 31 ++++ gcc/testsuite/gcc.dg/ipa/ipa-sra-27.c | 49 +++++ gcc/testsuite/gcc.dg/ipa/ipa-sra-28.c | 51 ++++++ 4 files changed, 328 insertions(+), 56 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-sra-26.c create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-sra-27.c create mode 100644 gcc/testsuite/gcc.dg/ipa/ipa-sra-28.c diff --git a/gcc/ipa-sra.cc b/gcc/ipa-sra.cc index c35c0d7162a..93fceeafc73 100644 --- a/gcc/ipa-sra.cc +++ b/gcc/ipa-sra.cc @@ -173,6 +173,10 @@ struct GTY(()) isra_param_desc unsigned param_size_limit : ISRA_ARG_SIZE_LIMIT_BITS; /* Sum of unit sizes of all certain replacements. */ unsigned size_reached : ISRA_ARG_SIZE_LIMIT_BITS; + /* Minimum offset that is known to be safe to dereference because of callers + pass pointers to DECLs of at least this size or because of dereferences in + callers. */ + unsigned safe_size : ISRA_ARG_SIZE_LIMIT_BITS; /* A parameter that is used only in call arguments and can be removed if all concerned actual arguments are removed. */ @@ -185,6 +189,12 @@ struct GTY(()) isra_param_desc not construct the argument just to pass it to calls. Only meaningful for by_ref parameters. */ unsigned not_specially_constructed : 1; + /* Only meaningful for by_ref parameters. If set, this parameter can only be + a split candidate if all callers pass pointers that are known to point to + a chunk of memory large enough to contain all accesses. */ + unsigned conditionally_dereferenceable : 1; + /* Set when safe_size has been updated from at least one caller. */ + unsigned safe_size_set : 1; }; /* Structure used when generating summaries that describes a parameter. */ @@ -220,6 +230,10 @@ struct gensum_param_desc without performing further checks (for example because it is a REFERENCE_TYPE)? */ bool safe_ref; + /* Only meaningful for by_ref parameters. If set, this parameter can only be + a split candidate if all callers pass pointers that are known to point to + a chunk of memory large enough to contain all accesses. */ + bool conditionally_dereferenceable; /* The number of this parameter as they are ordered in function decl. */ int param_number; @@ -332,10 +346,12 @@ struct isra_param_flow /* Offset within the formal parameter. */ unsigned unit_offset; - /* Size of the portion of the formal parameter that is being passed. */ + /* When aggregate_pass_through is set, this is the size of the portion of an + aggregate formal parameter that is being passed. Otherwise, this is size + of pointed to memory that is known to be valid be dereferenced. */ unsigned unit_size : ISRA_ARG_SIZE_LIMIT_BITS; - /* True when the value of this actual copy is a portion of a formal + /* True when the value of this actual argument is a portion of a formal parameter. */ unsigned aggregate_pass_through : 1; /* True when the value of this actual copy is a verbatim pass through of an @@ -425,10 +441,13 @@ ipa_sra_function_summaries::duplicate (cgraph_node *, cgraph_node *, d->param_size_limit = s->param_size_limit; d->size_reached = s->size_reached; + d->safe_size = s->safe_size; d->locally_unused = s->locally_unused; d->split_candidate = s->split_candidate; d->by_ref = s->by_ref; d->not_specially_constructed = s->not_specially_constructed; + d->conditionally_dereferenceable = s->conditionally_dereferenceable; + d->safe_size_set = s->safe_size_set; unsigned acc_count = vec_safe_length (s->accesses); vec_safe_reserve_exact (d->accesses, acc_count); @@ -537,6 +556,8 @@ isra_call_summary::dump (FILE *f) fprintf (f, " Aggregate pass through from the param given above, " "unit offset: %u , unit size: %u\n", ipf->unit_offset, ipf->unit_size); + else if (ipf->unit_size > 0) + fprintf (f, " Known dereferenceable size: %u\n", ipf->unit_size); if (ipf->pointer_pass_through) fprintf (f, " Pointer pass through from the param given above, " "safe_to_import_accesses: %u\n", ipf->safe_to_import_accesses); @@ -717,8 +738,11 @@ dump_gensum_param_descriptor (FILE *f, gensum_param_desc *desc) return; } if (desc->by_ref) - fprintf (f, " %s by_ref with %u pass throughs\n", - desc->safe_ref ? "safe" : "unsafe", desc->ptr_pt_count); + fprintf (f, " %s%s by_ref with %u pass throughs\n", + desc->safe_ref ? "safe" : "unsafe", + desc->conditionally_dereferenceable + ? " conditionally_dereferenceable" : " ok", + desc->ptr_pt_count); for (gensum_param_access *acc = desc->accesses; acc; acc = acc->next_sibling) dump_gensum_access (f, acc, 2); @@ -756,16 +780,23 @@ dump_isra_param_descriptor (FILE *f, isra_param_desc *desc, bool hints) } if (!desc->split_candidate) { - fprintf (f, " not a candidate for splitting\n"); + fprintf (f, " not a candidate for splitting"); + if (hints && desc->by_ref && desc->safe_size_set) + fprintf (f, ", safe_size: %u", (unsigned) desc->safe_size); + fprintf (f, "\n"); return; } fprintf (f, " param_size_limit: %u, size_reached: %u%s", desc->param_size_limit, desc->size_reached, desc->by_ref ? ", by_ref" : ""); + if (desc->by_ref && desc->conditionally_dereferenceable) + fprintf (f, ", conditionally_dereferenceable"); if (hints) { if (desc->by_ref && !desc->not_specially_constructed) fprintf (f, ", args_specially_constructed"); + if (desc->by_ref && desc->safe_size_set) + fprintf (f, ", safe_size: %u", (unsigned) desc->safe_size); } fprintf (f, "\n"); @@ -2085,8 +2116,19 @@ isra_analyze_call (cgraph_edge *cs) bool reverse; tree base = get_ref_base_and_extent (TREE_OPERAND (arg, 0), &poffset, &psize, &pmax_size, &reverse); - /* TODO: Next patch will need the offset too, so we cannot use - get_base_address. */ + HOST_WIDE_INT offset; + unsigned HOST_WIDE_INT ds; + if (DECL_P (base) + && (poffset.is_constant (&offset)) + && tree_fits_uhwi_p (DECL_SIZE (base)) + && ((ds = tree_to_uhwi (DECL_SIZE (base)) - offset) + < ISRA_ARG_SIZE_LIMIT * BITS_PER_UNIT)) + { + csum->init_inputs (count); + gcc_assert (!csum->m_arg_flow[i].aggregate_pass_through); + csum->m_arg_flow[i].unit_size = ds / BITS_PER_UNIT; + } + if (TREE_CODE (base) == VAR_DECL && !TREE_STATIC (base) && !loaded_decls->contains (base)) @@ -2308,9 +2350,14 @@ check_gensum_access (struct function *fun, tree parm, gensum_param_desc *desc, int idx = (entry_bb_index * unsafe_by_ref_count + desc->deref_index); if ((access->offset + access->size) > bb_dereferences[idx]) { - disqualify_split_candidate (desc, "Would create a possibly " - "illegal dereference in a caller."); - return true; + if (!dereference_probable_p (fun, access)) + { + disqualify_split_candidate (desc, "Would create a possibly " + "illegal dereference in a " + "caller."); + return true; + } + desc->conditionally_dereferenceable = true; } } } @@ -2539,6 +2586,7 @@ process_scan_results (cgraph_node *node, struct function *fun, d->locally_unused = s->locally_unused; d->split_candidate = s->split_candidate; d->by_ref = s->by_ref; + d->conditionally_dereferenceable = s->conditionally_dereferenceable; for (gensum_param_access *acc = s->accesses; acc; @@ -2693,11 +2741,14 @@ isra_write_node_summary (output_block *ob, cgraph_node *node) } streamer_write_uhwi (ob, desc->param_size_limit); streamer_write_uhwi (ob, desc->size_reached); + gcc_assert (desc->safe_size == 0); bitpack_d bp = bitpack_create (ob->main_stream); bp_pack_value (&bp, desc->locally_unused, 1); bp_pack_value (&bp, desc->split_candidate, 1); bp_pack_value (&bp, desc->by_ref, 1); gcc_assert (!desc->not_specially_constructed); + bp_pack_value (&bp, desc->conditionally_dereferenceable, 1); + gcc_assert (!desc->safe_size_set); streamer_write_bitpack (&bp); } bitpack_d bp = bitpack_create (ob->main_stream); @@ -2814,11 +2865,14 @@ isra_read_node_info (struct lto_input_block *ib, cgraph_node *node, } desc->param_size_limit = streamer_read_uhwi (ib); desc->size_reached = streamer_read_uhwi (ib); + desc->safe_size = 0; bitpack_d bp = streamer_read_bitpack (ib); desc->locally_unused = bp_unpack_value (&bp, 1); desc->split_candidate = bp_unpack_value (&bp, 1); desc->by_ref = bp_unpack_value (&bp, 1); desc->not_specially_constructed = 0; + desc->conditionally_dereferenceable = bp_unpack_value (&bp, 1); + desc->safe_size_set = 0; } bitpack_d bp = streamer_read_bitpack (ib); ifs->m_candidate = bp_unpack_value (&bp, 1); @@ -3265,44 +3319,65 @@ isra_mark_caller_param_used (isra_func_summary *from_ifs, int input_idx, } } -/* Set all param hints in DESC to the pessimistic values. */ +/* Combine safe_size of DESC with SIZE and return true if it has changed. */ -static void +static bool +update_safe_size (isra_param_desc *desc, unsigned size) +{ + if (!desc->safe_size_set) + { + desc->safe_size_set = 1; + desc->safe_size = size; + return true; + } + if (desc->safe_size <= size) + return false; + desc->safe_size = size; + return true; +} + +/* Set all param hints in DESC to the pessimistic values. Return true if any + hints that need to potentially trigger further propagation have changed. */ + +static bool flip_all_hints_pessimistic (isra_param_desc *desc) { desc->not_specially_constructed = true; - - return; + return update_safe_size (desc, 0); } -/* Because we have not analyzed a caller, go over all parameter int flags of - NODE and turn them pessimistic. */ +/* Because we have not analyzed or otherwise problematic caller, go over all + parameter int flags of IFS describing a call graph node of a calllee and + turn them pessimistic. Return true if any hints that need to potentially + trigger further propagation have changed. */ -static void -flip_all_param_hints_pessimistic (cgraph_node *node) +static bool +flip_all_param_hints_pessimistic (isra_func_summary *ifs) { - isra_func_summary *ifs = func_sums->get (node); if (!ifs || !ifs->m_candidate) - return; + return false; + bool ret = false; unsigned param_count = vec_safe_length (ifs->m_parameters); for (unsigned i = 0; i < param_count; i++) - flip_all_hints_pessimistic (&(*ifs->m_parameters)[i]); + ret |= flip_all_hints_pessimistic (&(*ifs->m_parameters)[i]); - return; + return ret; } -/* Propagate hints accross edge CS which ultimately leads to CALLEE. */ +/* Propagate hints accross edge CS which ultimately leads to a node described + by TO_IFS. Return true if any hints of the callee which should potentially + trigger further propagation have changed. */ -static void -propagate_param_hints (cgraph_edge *cs, cgraph_node *callee) +static bool +propagate_param_hints_accross_call (cgraph_edge *cs, isra_func_summary *to_ifs) { - isra_call_summary *csum = call_sums->get (cs); - isra_func_summary *to_ifs = func_sums->get (callee); if (!to_ifs || !to_ifs->m_candidate) - return; + return false; + isra_call_summary *csum = call_sums->get (cs); + bool ret = false; unsigned args_count = csum->m_arg_flow.length (); unsigned param_count = vec_safe_length (to_ifs->m_parameters); @@ -3311,14 +3386,62 @@ propagate_param_hints (cgraph_edge *cs, cgraph_node *callee) isra_param_desc *desc = &(*to_ifs->m_parameters)[i]; if (i >= args_count) { - flip_all_hints_pessimistic (desc); + ret |= flip_all_hints_pessimistic (desc); continue; } - if (desc->by_ref && !csum->m_arg_flow[i].constructed_for_calls) - desc->not_specially_constructed = true; + if (desc->by_ref) + { + isra_param_flow *ipf = &csum->m_arg_flow[i]; + + if (!ipf->constructed_for_calls) + desc->not_specially_constructed = true; + + if (ipf->pointer_pass_through) + { + isra_func_summary *from_ifs = func_sums->get (cs->caller); + int srcidx = get_single_param_flow_source (ipf); + if (vec_safe_length (from_ifs->m_parameters) > (unsigned) srcidx) + { + isra_param_desc *src_d = &(*from_ifs->m_parameters)[srcidx]; + if (src_d->safe_size_set) + ret |= update_safe_size (desc, src_d->safe_size); + } + else + ret |= update_safe_size (desc, 0); + } + else if (!ipf->aggregate_pass_through) + ret |= update_safe_size (desc, ipf->unit_size); + else + /* LTOing type-mismatched programs can end up here. */ + ret |= update_safe_size (desc, 0); + } + } + return ret; +} + +/* Propagate hints from NODE described by FROM_IFS to all its (dorect) callees, + push those that may need re-visiting onto STACK. */ + +static void +propagate_hints_to_all_callees (cgraph_node *node, isra_func_summary *from_ifs, + vec *stack) +{ + for (cgraph_edge *cs = node->callees; cs; cs = cs->next_callee) + { + enum availability availability; + cgraph_node *callee = cs->callee->function_symbol (&availability); + isra_func_summary *to_ifs = func_sums->get (callee); + if (!from_ifs) + { + if (flip_all_param_hints_pessimistic (to_ifs) + && ipa_edge_within_scc (cs)) + isra_push_node_to_stack (callee, to_ifs, stack); + } + else if (propagate_param_hints_accross_call (cs, to_ifs) + && ipa_edge_within_scc (cs)) + isra_push_node_to_stack (callee, to_ifs, stack); } - return; } /* Propagate information that any parameter is not used only locally within a @@ -3990,7 +4113,8 @@ adjust_parameter_descriptions (cgraph_node *node, isra_func_summary *ifs) check_surviving = true; cinfo->param_adjustments->get_surviving_params (&surviving_params); } - bool dumped_first = false; + auto_vec dump_dead_indices; + auto_vec dump_bad_cond_indices; for (unsigned i = 0; i < len; i++) { isra_param_desc *desc = &(*ifs->m_parameters)[i]; @@ -4009,19 +4133,23 @@ adjust_parameter_descriptions (cgraph_node *node, isra_func_summary *ifs) desc->split_candidate = false; if (dump_file && (dump_flags & TDF_DETAILS)) - { - if (!dumped_first) - { - fprintf (dump_file, - "The following parameters of %s are dead on " - "arrival:", node->dump_name ()); - dumped_first = true; - } - fprintf (dump_file, " %u", i); - } + dump_dead_indices.safe_push (i); } else { + if (desc->split_candidate && desc->conditionally_dereferenceable) + { + gcc_assert (desc->safe_size_set); + for (param_access *pa : *desc->accesses) + if ((pa->unit_offset + pa->unit_size) > desc->safe_size) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + dump_bad_cond_indices.safe_push (i); + desc->split_candidate = false; + break; + } + } + if (desc->split_candidate) { if (desc->by_ref && !desc->not_specially_constructed) @@ -4039,8 +4167,22 @@ adjust_parameter_descriptions (cgraph_node *node, isra_func_summary *ifs) } } - if (dumped_first) - fprintf (dump_file, "\n"); + if (!dump_dead_indices.is_empty ()) + { + fprintf (dump_file, "The following parameters of %s are dead on arrival:", + node->dump_name ()); + for (unsigned i : dump_dead_indices) + fprintf (dump_file, " %u", i); + fprintf (dump_file, "\n"); + } + if (!dump_bad_cond_indices.is_empty ()) + { + fprintf (dump_file, "The following parameters of %s are not safe to " + "derefernce in all callers:", node->dump_name ()); + for (unsigned i : dump_bad_cond_indices) + fprintf (dump_file, " %u", i); + fprintf (dump_file, "\n"); + } return ret; } @@ -4121,17 +4263,16 @@ ipa_sra_analysis (void) for (cgraph_node *v : cycle_nodes) { isra_func_summary *ifs = func_sums->get (v); - for (cgraph_edge *cs = v->callees; cs; cs = cs->next_callee) - { - enum availability availability; - cgraph_node *callee = cs->callee->function_symbol (&availability); - if (!ifs) - { - flip_all_param_hints_pessimistic (callee); - continue; - } - propagate_param_hints (cs, callee); - } + propagate_hints_to_all_callees (v, ifs, &stack); + } + + while (!stack.is_empty ()) + { + cgraph_node *node = stack.pop (); + isra_func_summary *ifs = func_sums->get (node); + gcc_checking_assert (ifs && ifs->m_queued); + ifs->m_queued = false; + propagate_hints_to_all_callees (node, ifs, &stack); } cycle_nodes.release (); diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-26.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-26.c new file mode 100644 index 00000000000..08a40da1482 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-26.c @@ -0,0 +1,31 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-ipa-sra-details" } */ + +struct S +{ + short a, b, c; +}; + +extern int gc; +extern int *arr; + +static void __attribute__((noinline)) +foo (struct S *p) +{ + for (int i = 0; i < gc; i++) + arr += p->b; +} + +void +bar (short a, short b, short c) +{ + struct S s; + s.a = a; + s.b = b; + s.c = c; + foo (&s); + return; +} + +/* { dg-final { scan-ipa-dump "Will split parameter" "sra" } } */ + diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-27.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-27.c new file mode 100644 index 00000000000..b815e8a83b1 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-27.c @@ -0,0 +1,49 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-ipa-sra-details" } */ + +struct S +{ + short a, b, c; +}; + +extern int gc; +extern int *arr; + +static void __attribute__((noinline)) +foo (struct S *p) +{ + for (int i = 0; i < gc; i++) + arr += p->b; +} + +static void __attribute__((noinline)) +baz (struct S *p) +{ + foo (p); + gc = p->a + p->c; +} + +void +bar (short a, short b, short c) +{ + struct S s; + s.a = a; + s.b = b; + s.c = c; + foo (&s); + return; +} + +void +bar2 (short a, short b, short c) +{ + struct S s; + s.a = a; + s.b = b; + s.c = c; + baz (&s); + return; +} + +/* { dg-final { scan-ipa-dump-times "Will split parameter" 2 "sra" } } */ + diff --git a/gcc/testsuite/gcc.dg/ipa/ipa-sra-28.c b/gcc/testsuite/gcc.dg/ipa/ipa-sra-28.c new file mode 100644 index 00000000000..d77d33a3608 --- /dev/null +++ b/gcc/testsuite/gcc.dg/ipa/ipa-sra-28.c @@ -0,0 +1,51 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-ipa-sra-details" } */ + +struct S +{ + short a, b, c; +}; + +volatile int gc; +volatile int *arr; + +static void __attribute__((noinline)) +foo (struct S *p) +{ + for (int i = 0; i < gc; i++) + arr += p->b; +} + +void +bar (short a, short b, short c) +{ + struct S s; + s.a = a; + s.b = b; + s.c = c; + foo (&s); + return; +} + +void +baz (void) +{ + foo ((struct S *) 0); +} + +void __attribute__((noipa)) +confuse (void) +{ + gc = 0; + baz (); +} + +int +main (int argc, char **argv) +{ + confuse (); + return 0; +} + +/* { dg-final { scan-ipa-dump-not "Will split parameter" "sra" } } */ +