From patchwork Wed Nov 20 16:23:28 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Hubicka X-Patchwork-Id: 1198325 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-514185-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=ucw.cz Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="x1LFHI9U"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 47J7Kp5VPmz9sPW for ; Thu, 21 Nov 2019 03:23:41 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=iBBuNP5Cn5kfCAi61Z9iusbIlmm4AMBec54K81jdIJ7Fp7y/Dfhxn NRxUBxIFuUu+voDuWPIfoPVAxQrsnUlukWqzXnb/wqZh+G2dA3xFO+X7QZosoraP O5xTG4v0Tv9QEX1BfQnbIjSrCC0MjJTidAWQce/m27xpccFFw0kn4Y= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=5BcubR3XULDctuSml3beEnmDVJg=; b=x1LFHI9UCEPiFJD94t/B BPeC1K7xLJkvh1Zni/yhndvCZHlsmaLcAVVmPnoGMogafrmgmExxQOx4gHen2/O7 jxb9RHJrzkVNFJ8e+WzQpHCCmneQvNTyhv9Uno6yL2PZuYZj3Vdv2rA+WhUPdLJ6 Soi+yHV8eIUF4H3yxLq+BeI= Received: (qmail 83740 invoked by alias); 20 Nov 2019 16:23:33 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 83730 invoked by uid 89); 20 Nov 2019 16:23:33 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-10.0 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS autolearn=ham version=3.3.1 spammy=es, nonNULL, cgraph_edg, inlined_to X-HELO: nikam.ms.mff.cuni.cz Received: from nikam.ms.mff.cuni.cz (HELO nikam.ms.mff.cuni.cz) (195.113.20.16) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Wed, 20 Nov 2019 16:23:31 +0000 Received: by nikam.ms.mff.cuni.cz (Postfix, from userid 16202) id 26050288018; Wed, 20 Nov 2019 17:23:28 +0100 (CET) Date: Wed, 20 Nov 2019 17:23:28 +0100 From: Jan Hubicka To: gcc-patches@gcc.gnu.org Subject: Optimize allocations for evaluate_properties_for_edges Message-ID: <20191120162328.gca2s6b7usxegm2h@kam.mff.cuni.cz> MIME-Version: 1.0 Content-Disposition: inline User-Agent: NeoMutt/20170113 (1.7.2) Hi, this patch avoids malloc traffic in evaluate_properties_for_edge which allocates vectors holding known values, aggregates and polyorphic contextes. I made the vector allocated by a caller who can place them at stack using auto_vec. The patch also adds logic to avoid calculation and clearing of these vectors for parameters which are not used. I realize that API for evaluate_properties_for_edge became somewhat ugly with adding a lot of additional stuff. I will clean it up next stage1. With this patch we still do a lot of allocations to hold ipa_agg_value_set::items which are vectors within vectors. I wonder how much of this work would go away if we would further track what parameters are being used as aggregates? Bootstrapped/regtested x86_64-linux, will commit it shortly. Honza * ipa-fnsummary.c (evaluate_conditions_for_known_args): Be ready for some vectors to not be allocated. (evaluate_properties_for_edge): Document better; make known_vals and known_aggs caller allocated; avoid determining values of parameters which are not used. (ipa_merge_fn_summary_after_inlining): Pre allocate known_vals and known_aggs. * ipa-inline-analysis.c (do_estimate_edge_time): Likewise. (do_estimate_edge_size): Likewise. (do_estimate_edge_hints): Likewise. Index: ipa-fnsummary.c =================================================================== --- ipa-fnsummary.c (revision 278464) +++ ipa-fnsummary.c (working copy) @@ -329,7 +329,7 @@ evaluate_conditions_for_known_args (stru for (i = 0; vec_safe_iterate (info->conds, i, &c); i++) { - tree val; + tree val = NULL; tree res; int j; struct expr_eval_op *op; @@ -338,14 +338,8 @@ evaluate_conditions_for_known_args (stru (especially for K&R style programs). So bound check here (we assume known_aggs vector, if non-NULL, has the same length as known_vals). */ - gcc_checking_assert (!known_aggs.exists () + gcc_checking_assert (!known_aggs.length () || !known_vals.length () || (known_vals.length () == known_aggs.length ())); - if (c->operand_num >= (int) known_vals.length ()) - { - clause |= 1 << (i + predicate::first_dynamic_condition); - nonspec_clause |= 1 << (i + predicate::first_dynamic_condition); - continue; - } if (c->agg_contents) { @@ -353,19 +347,24 @@ evaluate_conditions_for_known_args (stru if (c->code == predicate::changed && !c->by_ref + && c->operand_num < (int)known_vals.length () && (known_vals[c->operand_num] == error_mark_node)) continue; - if (known_aggs.exists ()) + if (c->operand_num < (int)known_aggs.length ()) { agg = &known_aggs[c->operand_num]; - val = ipa_find_agg_cst_for_param (agg, known_vals[c->operand_num], + val = ipa_find_agg_cst_for_param (agg, + c->operand_num + < (int) known_vals.length () + ? known_vals[c->operand_num] + : NULL, c->offset, c->by_ref); } else val = NULL_TREE; } - else + else if (c->operand_num < (int) known_vals.length ()) { val = known_vals[c->operand_num]; if (val == error_mark_node && c->code != predicate::changed) @@ -491,7 +490,18 @@ evaluate_conditions_for_known_args (stru } -/* Work out what conditions might be true at invocation of E. */ +/* Work out what conditions might be true at invocation of E. + Compute costs for inlined edge if INLINE_P is true. + + Return in CLAUSE_PTR the evaluated condistions and in NONSPEC_CLAUSE_PTR + (if non-NULL) conditions evaluated for nonspecialized clone called + in a given context. + + KNOWN_VALS_PTR and KNOWN_AGGS_PTR must be non-NULL and will be filled by + known canstant and aggregate values of parameters. + + KNOWN_CONTEXT_PTR, if non-NULL, will be filled by polymorphic call contexts + of parameter used by a polymorphic call. */ void evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, @@ -504,113 +514,141 @@ evaluate_properties_for_edge (struct cgr { struct cgraph_node *callee = e->callee->ultimate_alias_target (); class ipa_fn_summary *info = ipa_fn_summaries->get (callee); - vec known_vals = vNULL; auto_vec known_value_ranges; - vec known_aggs = vNULL; class ipa_edge_args *args; if (clause_ptr) *clause_ptr = inline_p ? 0 : 1 << predicate::not_inlined_condition; - if (known_vals_ptr) - known_vals_ptr->create (0); - if (known_contexts_ptr) - known_contexts_ptr->create (0); if (ipa_node_params_sum && !e->call_stmt_cannot_inline_p - && ((clause_ptr && info->conds) || known_vals_ptr || known_contexts_ptr) + && (info->conds || known_contexts_ptr) && (args = IPA_EDGE_REF (e)) != NULL) { struct cgraph_node *caller; - class ipa_node_params *caller_parms_info, *callee_pi; + class ipa_node_params *caller_parms_info, *callee_pi = NULL; class ipa_call_summary *es = ipa_call_summaries->get (e); int i, count = ipa_get_cs_argument_count (args); - if (e->caller->inlined_to) - caller = e->caller->inlined_to; - else - caller = e->caller; - caller_parms_info = IPA_NODE_REF (caller); - callee_pi = IPA_NODE_REF (callee); - - if (count && (info->conds || known_vals_ptr)) - known_vals.safe_grow_cleared (count); - if (count && info->conds) - known_value_ranges.safe_grow_cleared (count); - if (count && (info->conds || known_aggs_ptr)) - known_aggs.safe_grow_cleared (count); - if (count && known_contexts_ptr) - known_contexts_ptr->safe_grow_cleared (count); + if (count) + { + if (e->caller->inlined_to) + caller = e->caller->inlined_to; + else + caller = e->caller; + caller_parms_info = IPA_NODE_REF (caller); + callee_pi = IPA_NODE_REF (callee); + + /* Watch for thunks. */ + if (callee_pi) + /* Watch for variadic functions. */ + count = MIN (count, ipa_get_param_count (callee_pi)); + } if (callee_pi) for (i = 0; i < count; i++) { struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, i); - tree cst = ipa_value_from_jfunc (caller_parms_info, jf, - ipa_get_type (callee_pi, i)); - if (!cst && e->call_stmt - && i < (int)gimple_call_num_args (e->call_stmt)) + if (ipa_is_param_used_by_indirect_call (callee_pi, i) + || ipa_is_param_used_by_ipa_predicates (callee_pi, i)) { - cst = gimple_call_arg (e->call_stmt, i); - if (!is_gimple_min_invariant (cst)) - cst = NULL; - } - if (cst) - { - gcc_checking_assert (TREE_CODE (cst) != TREE_BINFO); - if (known_vals.exists ()) - known_vals[i] = cst; + /* Determine if we know constant value of the parameter. */ + tree cst = ipa_value_from_jfunc (caller_parms_info, jf, + ipa_get_type (callee_pi, i)); + + if (!cst && e->call_stmt + && i < (int)gimple_call_num_args (e->call_stmt)) + { + cst = gimple_call_arg (e->call_stmt, i); + if (!is_gimple_min_invariant (cst)) + cst = NULL; + } + if (cst) + { + gcc_checking_assert (TREE_CODE (cst) != TREE_BINFO); + if (!known_vals_ptr->length ()) + vec_safe_grow_cleared (known_vals_ptr, count); + (*known_vals_ptr)[i] = cst; + } + else if (inline_p && !es->param[i].change_prob) + { + if (!known_vals_ptr->length ()) + vec_safe_grow_cleared (known_vals_ptr, count); + (*known_vals_ptr)[i] = error_mark_node; + } + + /* If we failed to get simple constant, try value range. */ + if ((!cst || TREE_CODE (cst) != INTEGER_CST) + && ipa_is_param_used_by_ipa_predicates (callee_pi, i)) + { + value_range vr + = ipa_value_range_from_jfunc (caller_parms_info, e, jf, + ipa_get_type (callee_pi, + i)); + if (!vr.undefined_p () && !vr.varying_p ()) + { + if (!known_value_ranges.length ()) + known_value_ranges.safe_grow_cleared (count); + known_value_ranges[i] = vr; + } + } + + /* Determine known aggregate values. */ + ipa_agg_value_set agg + = ipa_agg_value_set_from_jfunc (caller_parms_info, + caller, &jf->agg); + if (agg.items.length ()) + { + if (!known_aggs_ptr->length ()) + vec_safe_grow_cleared (known_aggs_ptr, count); + (*known_aggs_ptr)[i] = agg; + } } - else if (inline_p && !es->param[i].change_prob) - known_vals[i] = error_mark_node; - if (known_contexts_ptr) - (*known_contexts_ptr)[i] - = ipa_context_from_jfunc (caller_parms_info, e, i, jf); - - known_aggs[i] = ipa_agg_value_set_from_jfunc (caller_parms_info, - caller, &jf->agg); - if (info->conds) - known_value_ranges[i] - = ipa_value_range_from_jfunc (caller_parms_info, e, jf, - ipa_get_type (callee_pi, i)); + /* For calls used in polymorphic calls we further determine + polymorphic call context. */ + if (known_contexts_ptr + && ipa_is_param_used_by_polymorphic_call (callee_pi, i)) + { + ipa_polymorphic_call_context + ctx = ipa_context_from_jfunc (caller_parms_info, e, i, jf); + if (!ctx.useless_p ()) + { + if (!known_contexts_ptr->length ()) + known_contexts_ptr->safe_grow_cleared (count); + (*known_contexts_ptr)[i] + = ipa_context_from_jfunc (caller_parms_info, e, i, jf); + } + } } else - gcc_assert (callee->thunk.thunk_p); + gcc_assert (!count || callee->thunk.thunk_p); } - else if (e->call_stmt && !e->call_stmt_cannot_inline_p - && ((clause_ptr && info->conds) || known_vals_ptr)) + else if (e->call_stmt && !e->call_stmt_cannot_inline_p && info->conds) { int i, count = (int)gimple_call_num_args (e->call_stmt); - if (count && (info->conds || known_vals_ptr)) - known_vals.safe_grow_cleared (count); for (i = 0; i < count; i++) { tree cst = gimple_call_arg (e->call_stmt, i); if (!is_gimple_min_invariant (cst)) cst = NULL; if (cst) - known_vals[i] = cst; + { + if (!known_vals_ptr->length ()) + vec_safe_grow_cleared (known_vals_ptr, count); + (*known_vals_ptr)[i] = cst; + } } } evaluate_conditions_for_known_args (callee, inline_p, - known_vals, + *known_vals_ptr, known_value_ranges, - known_aggs, clause_ptr, + *known_aggs_ptr, + clause_ptr, nonspec_clause_ptr); - - if (known_vals_ptr) - *known_vals_ptr = known_vals; - else - known_vals.release (); - - if (known_aggs_ptr) - *known_aggs_ptr = known_aggs; - else - ipa_release_agg_values (known_aggs); } @@ -3645,8 +3683,12 @@ ipa_merge_fn_summary_after_inlining (str info->fp_expressions |= callee_info->fp_expressions; if (callee_info->conds) - evaluate_properties_for_edge (edge, true, &clause, - NULL, NULL, NULL, NULL); + { + auto_vec known_vals; + auto_vec known_aggs; + evaluate_properties_for_edge (edge, true, &clause, NULL, + &known_vals, NULL, &known_aggs); + } if (ipa_node_params_sum && callee_info->conds) { class ipa_edge_args *args = IPA_EDGE_REF (edge); Index: ipa-inline-analysis.c =================================================================== --- ipa-inline-analysis.c (revision 278464) +++ ipa-inline-analysis.c (working copy) @@ -186,9 +186,9 @@ do_estimate_edge_time (struct cgraph_edg ipa_hints hints; struct cgraph_node *callee; clause_t clause, nonspec_clause; - vec known_vals; - vec known_contexts; - vec known_aggs; + auto_vec known_vals; + auto_vec known_contexts; + auto_vec known_aggs; class ipa_call_summary *es = ipa_call_summaries->get (edge); int min_size = -1; @@ -256,7 +256,6 @@ do_estimate_edge_time (struct cgraph_edg : edge->caller->count.ipa ()))) hints |= INLINE_HINT_known_hot; - ctx.release (); gcc_checking_assert (size >= 0); gcc_checking_assert (time >= 0); @@ -308,9 +307,9 @@ do_estimate_edge_size (struct cgraph_edg int size; struct cgraph_node *callee; clause_t clause, nonspec_clause; - vec known_vals; - vec known_contexts; - vec known_aggs; + auto_vec known_vals; + auto_vec known_contexts; + auto_vec known_aggs; /* When we do caching, use do_estimate_edge_time to populate the entry. */ @@ -333,7 +332,6 @@ do_estimate_edge_size (struct cgraph_edg ipa_call_context ctx (callee, clause, nonspec_clause, known_vals, known_contexts, known_aggs, vNULL); ctx.estimate_size_and_time (&size, NULL, NULL, NULL, NULL); - ctx.release (); return size; } @@ -347,9 +345,9 @@ do_estimate_edge_hints (struct cgraph_ed ipa_hints hints; struct cgraph_node *callee; clause_t clause, nonspec_clause; - vec known_vals; - vec known_contexts; - vec known_aggs; + auto_vec known_vals; + auto_vec known_contexts; + auto_vec known_aggs; /* When we do caching, use do_estimate_edge_time to populate the entry. */ @@ -372,7 +370,6 @@ do_estimate_edge_hints (struct cgraph_ed ipa_call_context ctx (callee, clause, nonspec_clause, known_vals, known_contexts, known_aggs, vNULL); ctx.estimate_size_and_time (NULL, NULL, NULL, NULL, &hints); - ctx.release (); hints |= simple_edge_hints (edge); return hints; }