From patchwork Mon Sep 7 19:32:44 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Jambor X-Patchwork-Id: 1359229 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=2620:52:3:1:0:246e:9693:128c; helo=sourceware.org; envelope-from=gcc-patches-bounces@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=suse.cz Received: from sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4BldjS6LP4z9sSP for ; Tue, 8 Sep 2020 05:32:59 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id C53EB393C86C; Mon, 7 Sep 2020 19:32:52 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by sourceware.org (Postfix) with ESMTPS id E6541386186A for ; Mon, 7 Sep 2020 19:32:45 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org E6541386186A Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=suse.cz Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=mjambor@suse.cz X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.221.27]) by mx2.suse.de (Postfix) with ESMTP id 61D20ACCF for ; Mon, 7 Sep 2020 19:32:45 +0000 (UTC) From: Martin Jambor To: GCC Patches Subject: [PATCH 1/6] ipa: Bundle vectors describing argument values User-Agent: Notmuch/0.30 (https://notmuchmail.org) Emacs/26.3 (x86_64-suse-linux-gnu) Date: Mon, 07 Sep 2020 21:32:44 +0200 Message-ID: MIME-Version: 1.0 X-Spam-Status: No, score=-3038.0 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) 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: , Cc: Jan Hubicka Errors-To: gcc-patches-bounces@gcc.gnu.org Sender: "Gcc-patches" Hi, this large patch is mostly mechanical change which aims to replace uses of separate vectors about known scalar values (usually called known_vals or known_csts), known aggregate values (known_aggs), known virtual call contexts (known_contexts) and known value ranges (known_value_ranges) with uses of either new type ipa_call_arg_values or ipa_auto_call_arg_values, both of which simply contain these vectors inside them. The need for two distinct types comes from the fact that when the vectors are constructed from jump functions or lattices, we really should use auto_vecs with embedded storage allocated on stack. On the other hand, the bundle in ipa_call_context can be allocated on heap when in cache, one time for each call_graph node. ipa_call_context is constructible from ipa_auto_call_arg_values but then its vectors must not be resized, otherwise the vectors will stop pointing to the stack ones. Unfortunately, I don't think the structure embedded in ipa_call_context can be made constant because we need to manipulate and deallocate it when in cache. Last week I bootstrapped and tested (and LTO-bootstrapped) this patch individually, this week I did so for the whole patch set. OK for trunk? Thanks, Martin gcc/ChangeLog: 2020-09-01 Martin Jambor * ipa-prop.h (ipa_auto_call_arg_values): New type. (class ipa_call_arg_values): Likewise. (ipa_get_indirect_edge_target): Replaced vector arguments with ipa_call_arg_values in declaration. Added an overload for ipa_auto_call_arg_values. * ipa-fnsummary.h (ipa_call_context): Removed members m_known_vals, m_known_contexts, m_known_aggs, duplicate_from, release and equal_to, new members m_avals, store_to_cache and equivalent_to_p. Adjusted construcotr arguments. (estimate_ipcp_clone_size_and_time): Replaced vector arguments with ipa_auto_call_arg_values in declaration. (evaluate_properties_for_edge): Likewise. * ipa-cp.c (ipa_get_indirect_edge_target): Adjusted to work on ipa_call_arg_values rather than on separate vectors. Added an overload for ipa_auto_call_arg_values. (devirtualization_time_bonus): Adjusted to work on ipa_auto_call_arg_values rather than on separate vectors. (gather_context_independent_values): Adjusted to work on ipa_auto_call_arg_values rather than on separate vectors. (perform_estimation_of_a_value): Likewise. (estimate_local_effects): Likewise. (modify_known_vectors_with_val): Adjusted both variants to work on ipa_auto_call_arg_values and rename them to copy_known_vectors_add_val. (decide_about_value): Adjusted to work on ipa_call_arg_values rather than on separate vectors. (decide_whether_version_node): Likewise. * ipa-fnsummary.c (evaluate_conditions_for_known_args): Likewise. (evaluate_properties_for_edge): Likewise. (ipa_fn_summary_t::duplicate): Likewise. (estimate_edge_devirt_benefit): Adjusted to work on ipa_call_arg_values rather than on separate vectors. (estimate_edge_size_and_time): Likewise. (estimate_calls_size_and_time_1): Likewise. (summarize_calls_size_and_time): Adjusted calls to estimate_edge_size_and_time. (estimate_calls_size_and_time): Adjusted to work on ipa_call_arg_values rather than on separate vectors. (ipa_call_context::ipa_call_context): Construct from a pointer to ipa_auto_call_arg_values instead of inividual vectors. (ipa_call_context::duplicate_from): Adjusted to access vectors within m_avals. (ipa_call_context::release): Likewise. (ipa_call_context::equal_to): Likewise. (ipa_call_context::estimate_size_and_time): Adjusted to work on ipa_call_arg_values rather than on separate vectors. (estimate_ipcp_clone_size_and_time): Adjusted to work with ipa_auto_call_arg_values rather than on separate vectors. (ipa_merge_fn_summary_after_inlining): Likewise. Adjusted call to estimate_edge_size_and_time. (ipa_update_overall_fn_summary): Adjusted call to estimate_edge_size_and_time. * ipa-inline-analysis.c (do_estimate_edge_time): Adjusted to work with ipa_auto_call_arg_values rather than with separate vectors. (do_estimate_edge_size): Likewise. (do_estimate_edge_hints): Likewise. * ipa-prop.c (ipa_auto_call_arg_values::~ipa_auto_call_arg_values): New destructor. --- gcc/ipa-cp.c | 245 ++++++++++----------- gcc/ipa-fnsummary.c | 446 +++++++++++++++++--------------------- gcc/ipa-fnsummary.h | 27 +-- gcc/ipa-inline-analysis.c | 41 +--- gcc/ipa-prop.c | 10 + gcc/ipa-prop.h | 112 +++++++++- 6 files changed, 452 insertions(+), 429 deletions(-) diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index b3e7d41ea10..292dd7e5bdf 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -3117,30 +3117,40 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie, return target; } - -/* If an indirect edge IE can be turned into a direct one based on KNOWN_CSTS, - KNOWN_CONTEXTS (which can be vNULL) or KNOWN_AGGS (which also can be vNULL) - return the destination. */ +/* If an indirect edge IE can be turned into a direct one based on data in + AVALS, return the destination. Store into *SPECULATIVE a boolean determinig + whether the discovered target is only speculative guess. */ tree ipa_get_indirect_edge_target (struct cgraph_edge *ie, - vec known_csts, - vec known_contexts, - vec known_aggs, + ipa_call_arg_values *avals, bool *speculative) { - return ipa_get_indirect_edge_target_1 (ie, known_csts, known_contexts, - known_aggs, NULL, speculative); + return ipa_get_indirect_edge_target_1 (ie, avals->m_known_vals, + avals->m_known_contexts, + avals->m_known_aggs, + NULL, speculative); } -/* Calculate devirtualization time bonus for NODE, assuming we know KNOWN_CSTS - and KNOWN_CONTEXTS. */ +/* The same functionality as above overloaded for ipa_auto_call_arg_values. */ + +tree +ipa_get_indirect_edge_target (struct cgraph_edge *ie, + ipa_auto_call_arg_values *avals, + bool *speculative) +{ + return ipa_get_indirect_edge_target_1 (ie, avals->m_known_vals, + avals->m_known_contexts, + avals->m_known_aggs, + NULL, speculative); +} + +/* Calculate devirtualization time bonus for NODE, assuming we know information + about arguments stored in AVALS. */ static int devirtualization_time_bonus (struct cgraph_node *node, - vec known_csts, - vec known_contexts, - vec known_aggs) + ipa_auto_call_arg_values *avals) { struct cgraph_edge *ie; int res = 0; @@ -3153,8 +3163,7 @@ devirtualization_time_bonus (struct cgraph_node *node, tree target; bool speculative; - target = ipa_get_indirect_edge_target (ie, known_csts, known_contexts, - known_aggs, &speculative); + target = ipa_get_indirect_edge_target (ie, avals, &speculative); if (!target) continue; @@ -3306,32 +3315,27 @@ context_independent_aggregate_values (class ipcp_param_lattices *plats) return res; } -/* Allocate KNOWN_CSTS, KNOWN_CONTEXTS and, if non-NULL, KNOWN_AGGS and - populate them with values of parameters that are known independent of the - context. INFO describes the function. If REMOVABLE_PARAMS_COST is - non-NULL, the movement cost of all removable parameters will be stored in - it. */ +/* Grow vectors in AVALS and fill them with information about values of + parameters that are known to be independent of the context. Only calculate + m_known_aggs if CALCULATE_AGGS is true. INFO describes the function. If + REMOVABLE_PARAMS_COST is non-NULL, the movement cost of all removable + parameters will be stored in it. + + TODO: Also grow context independent value range vectors. */ static bool gather_context_independent_values (class ipa_node_params *info, - vec *known_csts, - vec - *known_contexts, - vec *known_aggs, + ipa_auto_call_arg_values *avals, + bool calculate_aggs, int *removable_params_cost) { int i, count = ipa_get_param_count (info); bool ret = false; - known_csts->create (0); - known_contexts->create (0); - known_csts->safe_grow_cleared (count, true); - known_contexts->safe_grow_cleared (count, true); - if (known_aggs) - { - known_aggs->create (0); - known_aggs->safe_grow_cleared (count, true); - } + avals->m_known_vals.safe_grow_cleared (count, true); + avals->m_known_contexts.safe_grow_cleared (count, true); + if (calculate_aggs) + avals->m_known_aggs.safe_grow_cleared (count, true); if (removable_params_cost) *removable_params_cost = 0; @@ -3345,7 +3349,7 @@ gather_context_independent_values (class ipa_node_params *info, { ipcp_value *val = lat->values; gcc_checking_assert (TREE_CODE (val->value) != TREE_BINFO); - (*known_csts)[i] = val->value; + avals->m_known_vals[i] = val->value; if (removable_params_cost) *removable_params_cost += estimate_move_cost (TREE_TYPE (val->value), false); @@ -3363,15 +3367,15 @@ gather_context_independent_values (class ipa_node_params *info, /* Do not account known context as reason for cloning. We can see if it permits devirtualization. */ if (ctxlat->is_single_const ()) - (*known_contexts)[i] = ctxlat->values->value; + avals->m_known_contexts[i] = ctxlat->values->value; - if (known_aggs) + if (calculate_aggs) { vec agg_items; struct ipa_agg_value_set *agg; agg_items = context_independent_aggregate_values (plats); - agg = &(*known_aggs)[i]; + agg = &avals->m_known_aggs[i]; agg->items = agg_items; agg->by_ref = plats->aggs_by_ref; ret |= !agg_items.is_empty (); @@ -3381,25 +3385,23 @@ gather_context_independent_values (class ipa_node_params *info, return ret; } -/* Perform time and size measurement of NODE with the context given in - KNOWN_CSTS, KNOWN_CONTEXTS and KNOWN_AGGS, calculate the benefit and cost - given BASE_TIME of the node without specialization, REMOVABLE_PARAMS_COST of - all context-independent removable parameters and EST_MOVE_COST of estimated - movement of the considered parameter and store it into VAL. */ +/* Perform time and size measurement of NODE with the context given in AVALS, + calculate the benefit compared to the node without specialization and store + it into VAL. Take into account REMOVABLE_PARAMS_COST of all + context-independent or unused removable parameters and EST_MOVE_COST, the + estimated movement of the considered parameter. */ static void -perform_estimation_of_a_value (cgraph_node *node, vec known_csts, - vec known_contexts, - vec known_aggs, - int removable_params_cost, - int est_move_cost, ipcp_value_base *val) +perform_estimation_of_a_value (cgraph_node *node, + ipa_auto_call_arg_values *avals, + int removable_params_cost, int est_move_cost, + ipcp_value_base *val) { int size, time_benefit; sreal time, base_time; ipa_hints hints; - estimate_ipcp_clone_size_and_time (node, known_csts, known_contexts, - known_aggs, &size, &time, + estimate_ipcp_clone_size_and_time (node, avals, &size, &time, &base_time, &hints); base_time -= time; if (base_time > 65535) @@ -3412,8 +3414,7 @@ perform_estimation_of_a_value (cgraph_node *node, vec known_csts, time_benefit = 0; else time_benefit = base_time.to_int () - + devirtualization_time_bonus (node, known_csts, known_contexts, - known_aggs) + + devirtualization_time_bonus (node, avals) + hint_time_bonus (node, hints) + removable_params_cost + est_move_cost; @@ -3454,9 +3455,6 @@ estimate_local_effects (struct cgraph_node *node) { class ipa_node_params *info = IPA_NODE_REF (node); int i, count = ipa_get_param_count (info); - vec known_csts; - vec known_contexts; - vec known_aggs; bool always_const; int removable_params_cost; @@ -3466,11 +3464,10 @@ estimate_local_effects (struct cgraph_node *node) if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "\nEstimating effects for %s.\n", node->dump_name ()); - always_const = gather_context_independent_values (info, &known_csts, - &known_contexts, &known_aggs, + ipa_auto_call_arg_values avals; + always_const = gather_context_independent_values (info, &avals, true, &removable_params_cost); - int devirt_bonus = devirtualization_time_bonus (node, known_csts, - known_contexts, known_aggs); + int devirt_bonus = devirtualization_time_bonus (node, &avals); if (always_const || devirt_bonus || (removable_params_cost && node->can_change_signature)) { @@ -3482,8 +3479,7 @@ estimate_local_effects (struct cgraph_node *node) init_caller_stats (&stats); node->call_for_symbol_thunks_and_aliases (gather_caller_stats, &stats, false); - estimate_ipcp_clone_size_and_time (node, known_csts, known_contexts, - known_aggs, &size, &time, + estimate_ipcp_clone_size_and_time (node, &avals, &size, &time, &base_time, &hints); time -= devirt_bonus; time -= hint_time_bonus (node, hints); @@ -3536,18 +3532,17 @@ estimate_local_effects (struct cgraph_node *node) if (lat->bottom || !lat->values - || known_csts[i]) + || avals.m_known_vals[i]) continue; for (val = lat->values; val; val = val->next) { gcc_checking_assert (TREE_CODE (val->value) != TREE_BINFO); - known_csts[i] = val->value; + avals.m_known_vals[i] = val->value; int emc = estimate_move_cost (TREE_TYPE (val->value), true); - perform_estimation_of_a_value (node, known_csts, known_contexts, - known_aggs, - removable_params_cost, emc, val); + perform_estimation_of_a_value (node, &avals, removable_params_cost, + emc, val); if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -3559,7 +3554,7 @@ estimate_local_effects (struct cgraph_node *node) val->local_time_benefit, val->local_size_cost); } } - known_csts[i] = NULL_TREE; + avals.m_known_vals[i] = NULL_TREE; } for (i = 0; i < count; i++) @@ -3574,15 +3569,14 @@ estimate_local_effects (struct cgraph_node *node) if (ctxlat->bottom || !ctxlat->values - || !known_contexts[i].useless_p ()) + || !avals.m_known_contexts[i].useless_p ()) continue; for (val = ctxlat->values; val; val = val->next) { - known_contexts[i] = val->value; - perform_estimation_of_a_value (node, known_csts, known_contexts, - known_aggs, - removable_params_cost, 0, val); + avals.m_known_contexts[i] = val->value; + perform_estimation_of_a_value (node, &avals, removable_params_cost, + 0, val); if (dump_file && (dump_flags & TDF_DETAILS)) { @@ -3594,20 +3588,18 @@ estimate_local_effects (struct cgraph_node *node) val->local_time_benefit, val->local_size_cost); } } - known_contexts[i] = ipa_polymorphic_call_context (); + avals.m_known_contexts[i] = ipa_polymorphic_call_context (); } for (i = 0; i < count; i++) { class ipcp_param_lattices *plats = ipa_get_parm_lattices (info, i); - struct ipa_agg_value_set *agg; - struct ipcp_agg_lattice *aglat; if (plats->aggs_bottom || !plats->aggs) continue; - agg = &known_aggs[i]; - for (aglat = plats->aggs; aglat; aglat = aglat->next) + ipa_agg_value_set *agg = &avals.m_known_aggs[i]; + for (ipcp_agg_lattice *aglat = plats->aggs; aglat; aglat = aglat->next) { ipcp_value *val; if (aglat->bottom || !aglat->values @@ -3624,8 +3616,7 @@ estimate_local_effects (struct cgraph_node *node) item.value = val->value; agg->items.safe_push (item); - perform_estimation_of_a_value (node, known_csts, known_contexts, - known_aggs, + perform_estimation_of_a_value (node, &avals, removable_params_cost, 0, val); if (dump_file && (dump_flags & TDF_DETAILS)) @@ -3645,10 +3636,6 @@ estimate_local_effects (struct cgraph_node *node) } } } - - known_csts.release (); - known_contexts.release (); - ipa_release_agg_values (known_aggs); } @@ -5372,31 +5359,34 @@ copy_useful_known_contexts (vec known_contexts) return vNULL; } -/* Copy KNOWN_CSTS and modify the copy according to VAL and INDEX. If - non-empty, replace KNOWN_CONTEXTS with its copy too. */ +/* Copy known scalar values from AVALS into KNOWN_CSTS and modify the copy + according to VAL and INDEX. If non-empty, replace KNOWN_CONTEXTS with its + copy too. */ static void -modify_known_vectors_with_val (vec *known_csts, - vec *known_contexts, - ipcp_value *val, - int index) +copy_known_vectors_add_val (ipa_auto_call_arg_values *avals, + vec *known_csts, + vec *known_contexts, + ipcp_value *val, int index) { - *known_csts = known_csts->copy (); - *known_contexts = copy_useful_known_contexts (*known_contexts); + *known_csts = avals->m_known_vals.copy (); + *known_contexts = copy_useful_known_contexts (avals->m_known_contexts); (*known_csts)[index] = val->value; } -/* Replace KNOWN_CSTS with its copy. Also copy KNOWN_CONTEXTS and modify the - copy according to VAL and INDEX. */ +/* Copy known scalar values from AVALS into KNOWN_CSTS. Similarly, copy + contexts to KNOWN_CONTEXTS and modify the copy according to VAL and + INDEX. */ static void -modify_known_vectors_with_val (vec *known_csts, - vec *known_contexts, - ipcp_value *val, - int index) +copy_known_vectors_add_val (ipa_auto_call_arg_values *avals, + vec *known_csts, + vec *known_contexts, + ipcp_value *val, + int index) { - *known_csts = known_csts->copy (); - *known_contexts = known_contexts->copy (); + *known_csts = avals->m_known_vals.copy (); + *known_contexts = avals->m_known_contexts.copy (); (*known_contexts)[index] = val->value; } @@ -5433,16 +5423,15 @@ ipcp_val_agg_replacement_ok_p (ipa_agg_replacement_value *, return offset == -1; } -/* Decide whether to create a special version of NODE for value VAL of parameter - at the given INDEX. If OFFSET is -1, the value is for the parameter itself, - otherwise it is stored at the given OFFSET of the parameter. KNOWN_CSTS, - KNOWN_CONTEXTS and KNOWN_AGGS describe the other already known values. */ +/* Decide whether to create a special version of NODE for value VAL of + parameter at the given INDEX. If OFFSET is -1, the value is for the + parameter itself, otherwise it is stored at the given OFFSET of the + parameter. AVALS describes the other already known values. */ template static bool decide_about_value (struct cgraph_node *node, int index, HOST_WIDE_INT offset, - ipcp_value *val, vec known_csts, - vec known_contexts) + ipcp_value *val, ipa_auto_call_arg_values *avals) { struct ipa_agg_replacement_value *aggvals; int freq_sum, caller_count; @@ -5492,13 +5481,16 @@ decide_about_value (struct cgraph_node *node, int index, HOST_WIDE_INT offset, fprintf (dump_file, " Creating a specialized node of %s.\n", node->dump_name ()); + vec known_csts; + vec known_contexts; + callers = gather_edges_for_value (val, node, caller_count); if (offset == -1) - modify_known_vectors_with_val (&known_csts, &known_contexts, val, index); + copy_known_vectors_add_val (avals, &known_csts, &known_contexts, val, index); else { - known_csts = known_csts.copy (); - known_contexts = copy_useful_known_contexts (known_contexts); + known_csts = avals->m_known_vals.copy (); + known_contexts = copy_useful_known_contexts (avals->m_known_contexts); } find_more_scalar_values_for_callers_subset (node, known_csts, callers); find_more_contexts_for_caller_subset (node, &known_contexts, callers); @@ -5522,8 +5514,6 @@ decide_whether_version_node (struct cgraph_node *node) { class ipa_node_params *info = IPA_NODE_REF (node); int i, count = ipa_get_param_count (info); - vec known_csts; - vec known_contexts; bool ret = false; if (count == 0) @@ -5533,8 +5523,8 @@ decide_whether_version_node (struct cgraph_node *node) fprintf (dump_file, "\nEvaluating opportunities for %s.\n", node->dump_name ()); - gather_context_independent_values (info, &known_csts, &known_contexts, - NULL, NULL); + ipa_auto_call_arg_values avals; + gather_context_independent_values (info, &avals, false, NULL); for (i = 0; i < count;i++) { @@ -5543,12 +5533,11 @@ decide_whether_version_node (struct cgraph_node *node) ipcp_lattice *ctxlat = &plats->ctxlat; if (!lat->bottom - && !known_csts[i]) + && !avals.m_known_vals[i]) { ipcp_value *val; for (val = lat->values; val; val = val->next) - ret |= decide_about_value (node, i, -1, val, known_csts, - known_contexts); + ret |= decide_about_value (node, i, -1, val, &avals); } if (!plats->aggs_bottom) @@ -5557,22 +5546,20 @@ decide_whether_version_node (struct cgraph_node *node) ipcp_value *val; for (aglat = plats->aggs; aglat; aglat = aglat->next) if (!aglat->bottom && aglat->values - /* If the following is false, the one value is in - known_aggs. */ + /* If the following is false, the one value has been considered + for cloning for all contexts. */ && (plats->aggs_contain_variable || !aglat->is_single_const ())) for (val = aglat->values; val; val = val->next) - ret |= decide_about_value (node, i, aglat->offset, val, - known_csts, known_contexts); + ret |= decide_about_value (node, i, aglat->offset, val, &avals); } if (!ctxlat->bottom - && known_contexts[i].useless_p ()) + && avals.m_known_contexts[i].useless_p ()) { ipcp_value *val; for (val = ctxlat->values; val; val = val->next) - ret |= decide_about_value (node, i, -1, val, known_csts, - known_contexts); + ret |= decide_about_value (node, i, -1, val, &avals); } info = IPA_NODE_REF (node); @@ -5595,11 +5582,9 @@ decide_whether_version_node (struct cgraph_node *node) if (!adjust_callers_for_value_intersection (callers, node)) { /* If node is not called by anyone, or all its caller edges are - self-recursive, the node is not really be in use, no need to - do cloning. */ + self-recursive, the node is not really in use, no need to do + cloning. */ callers.release (); - known_csts.release (); - known_contexts.release (); info->do_clone_for_all_contexts = false; return ret; } @@ -5608,6 +5593,9 @@ decide_whether_version_node (struct cgraph_node *node) fprintf (dump_file, " - Creating a specialized node of %s " "for all known contexts.\n", node->dump_name ()); + vec known_csts = avals.m_known_vals.copy (); + vec known_contexts + = copy_useful_known_contexts (avals.m_known_contexts); find_more_scalar_values_for_callers_subset (node, known_csts, callers); find_more_contexts_for_caller_subset (node, &known_contexts, callers); ipa_agg_replacement_value *aggvals @@ -5625,11 +5613,6 @@ decide_whether_version_node (struct cgraph_node *node) IPA_NODE_REF (clone)->is_all_contexts_clone = true; ret = true; } - else - { - known_csts.release (); - known_contexts.release (); - } return ret; } diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c index 86d01addb44..d8b95aca307 100644 --- a/gcc/ipa-fnsummary.c +++ b/gcc/ipa-fnsummary.c @@ -320,19 +320,18 @@ set_hint_predicate (predicate **p, predicate new_predicate) is always false in the second and also builtin_constant_p tests cannot use the fact that parameter is indeed a constant. - KNOWN_VALS is partial mapping of parameters of NODE to constant values. - KNOWN_AGGS is a vector of aggregate known offset/value set for each - parameter. Return clause of possible truths. When INLINE_P is true, assume - that we are inlining. + When INLINE_P is true, assume that we are inlining. AVAL contains known + information about argument values. The function does not modify its content + and so AVALs could also be of type ipa_call_arg_values but so far all + callers work with the auto version and so we avoid the conversion for + convenience. - ERROR_MARK means compile time invariant. */ + ERROR_MARK value of an argument means compile time invariant. */ static void evaluate_conditions_for_known_args (struct cgraph_node *node, bool inline_p, - vec known_vals, - vec known_value_ranges, - vec known_aggs, + ipa_auto_call_arg_values *avals, clause_t *ret_clause, clause_t *ret_nonspec_clause) { @@ -351,38 +350,33 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, /* We allow call stmt to have fewer arguments than the callee function (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.length () || !known_vals.length () - || (known_vals.length () == known_aggs.length ())); + m_known_aggs vector is either empty or has the same length as + m_known_vals). */ + gcc_checking_assert (!avals->m_known_aggs.length () + || !avals->m_known_vals.length () + || (avals->m_known_vals.length () + == avals->m_known_aggs.length ())); if (c->agg_contents) { - struct ipa_agg_value_set *agg; - if (c->code == predicate::changed && !c->by_ref - && c->operand_num < (int)known_vals.length () - && (known_vals[c->operand_num] == error_mark_node)) + && (avals->safe_sval_at(c->operand_num) == error_mark_node)) continue; - if (c->operand_num < (int)known_aggs.length ()) + if (ipa_agg_value_set *agg = avals->safe_aggval_at (c->operand_num)) { - agg = &known_aggs[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); + tree sval = avals->safe_sval_at (c->operand_num); + val = ipa_find_agg_cst_for_param (agg, sval, c->offset, + c->by_ref); } else val = NULL_TREE; } - else if (c->operand_num < (int) known_vals.length ()) + else { - val = known_vals[c->operand_num]; - if (val == error_mark_node && c->code != predicate::changed) + val = avals->safe_sval_at (c->operand_num); + if (val && val == error_mark_node && c->code != predicate::changed) val = NULL_TREE; } @@ -446,53 +440,54 @@ evaluate_conditions_for_known_args (struct cgraph_node *node, continue; } } - if (c->operand_num < (int) known_value_ranges.length () + if (c->operand_num < (int) avals->m_known_value_ranges.length () && !c->agg_contents - && !known_value_ranges[c->operand_num].undefined_p () - && !known_value_ranges[c->operand_num].varying_p () - && TYPE_SIZE (c->type) - == TYPE_SIZE (known_value_ranges[c->operand_num].type ()) && (!val || TREE_CODE (val) != INTEGER_CST)) { - value_range vr = known_value_ranges[c->operand_num]; - if (!useless_type_conversion_p (c->type, vr.type ())) + value_range vr = avals->m_known_value_ranges[c->operand_num]; + if (!vr.undefined_p () + && !vr.varying_p () + && (TYPE_SIZE (c->type) == TYPE_SIZE (vr.type ()))) { - value_range res; - range_fold_unary_expr (&res, NOP_EXPR, - c->type, &vr, vr.type ()); - vr = res; - } - tree type = c->type; - - for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++) - { - if (vr.varying_p () || vr.undefined_p ()) - break; - - value_range res; - if (!op->val[0]) - range_fold_unary_expr (&res, op->code, op->type, &vr, type); - else if (!op->val[1]) + if (!useless_type_conversion_p (c->type, vr.type ())) { - value_range op0 (op->val[0], op->val[0]); - range_fold_binary_expr (&res, op->code, op->type, - op->index ? &op0 : &vr, - op->index ? &vr : &op0); + value_range res; + range_fold_unary_expr (&res, NOP_EXPR, + c->type, &vr, vr.type ()); + vr = res; + } + tree type = c->type; + + for (j = 0; vec_safe_iterate (c->param_ops, j, &op); j++) + { + if (vr.varying_p () || vr.undefined_p ()) + break; + + value_range res; + if (!op->val[0]) + range_fold_unary_expr (&res, op->code, op->type, &vr, type); + else if (!op->val[1]) + { + value_range op0 (op->val[0], op->val[0]); + range_fold_binary_expr (&res, op->code, op->type, + op->index ? &op0 : &vr, + op->index ? &vr : &op0); + } + else + gcc_unreachable (); + type = op->type; + vr = res; + } + if (!vr.varying_p () && !vr.undefined_p ()) + { + value_range res; + value_range val_vr (c->val, c->val); + range_fold_binary_expr (&res, c->code, boolean_type_node, + &vr, + &val_vr); + if (res.zero_p ()) + continue; } - else - gcc_unreachable (); - type = op->type; - vr = res; - } - if (!vr.varying_p () && !vr.undefined_p ()) - { - value_range res; - value_range val_vr (c->val, c->val); - range_fold_binary_expr (&res, c->code, boolean_type_node, - &vr, - &val_vr); - if (res.zero_p ()) - continue; } } @@ -538,24 +533,20 @@ fre_will_run_p (struct cgraph_node *node) (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 constant 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. */ + Vectors in AVALS will be populated with useful known information about + argument values - information not known to have any uses will be omitted - + except for m_known_contexts which will only be calculated if + COMPUTE_CONTEXTS is true. */ void evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, clause_t *clause_ptr, clause_t *nonspec_clause_ptr, - vec *known_vals_ptr, - vec - *known_contexts_ptr, - vec *known_aggs_ptr) + ipa_auto_call_arg_values *avals, + bool compute_contexts) { struct cgraph_node *callee = e->callee->ultimate_alias_target (); class ipa_fn_summary *info = ipa_fn_summaries->get (callee); - auto_vec known_value_ranges; class ipa_edge_args *args; if (clause_ptr) @@ -563,7 +554,7 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, if (ipa_node_params_sum && !e->call_stmt_cannot_inline_p - && (info->conds || known_contexts_ptr) + && (info->conds || compute_contexts) && (args = IPA_EDGE_REF (e)) != NULL) { struct cgraph_node *caller; @@ -608,15 +599,15 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, if (cst) { gcc_checking_assert (TREE_CODE (cst) != TREE_BINFO); - if (!known_vals_ptr->length ()) - vec_safe_grow_cleared (known_vals_ptr, count, true); - (*known_vals_ptr)[i] = cst; + if (!avals->m_known_vals.length ()) + avals->m_known_vals.safe_grow_cleared (count, true); + avals->m_known_vals[i] = cst; } else if (inline_p && !es->param[i].change_prob) { - if (!known_vals_ptr->length ()) - vec_safe_grow_cleared (known_vals_ptr, count, true); - (*known_vals_ptr)[i] = error_mark_node; + if (!avals->m_known_vals.length ()) + avals->m_known_vals.safe_grow_cleared (count, true); + avals->m_known_vals[i] = error_mark_node; } /* If we failed to get simple constant, try value range. */ @@ -624,19 +615,20 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, && vrp_will_run_p (caller) && ipa_is_param_used_by_ipa_predicates (callee_pi, i)) { - value_range vr + 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 ()) + if (!avals->m_known_value_ranges.length ()) { - known_value_ranges.safe_grow (count, true); + avals->m_known_value_ranges.safe_grow (count, true); for (int i = 0; i < count; ++i) - new (&known_value_ranges[i]) value_range (); + new (&avals->m_known_value_ranges[i]) + value_range (); } - known_value_ranges[i] = vr; + avals->m_known_value_ranges[i] = vr; } } @@ -648,25 +640,25 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, caller, &jf->agg); if (agg.items.length ()) { - if (!known_aggs_ptr->length ()) - vec_safe_grow_cleared (known_aggs_ptr, count, true); - (*known_aggs_ptr)[i] = agg; + if (!avals->m_known_aggs.length ()) + avals->m_known_aggs.safe_grow_cleared (count, true); + avals->m_known_aggs[i] = agg; } } } /* For calls used in polymorphic calls we further determine polymorphic call context. */ - if (known_contexts_ptr + if (compute_contexts && 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, true); - (*known_contexts_ptr)[i] + if (!avals->m_known_contexts.length ()) + avals->m_known_contexts.safe_grow_cleared (count, true); + avals->m_known_contexts[i] = ipa_context_from_jfunc (caller_parms_info, e, i, jf); } } @@ -685,18 +677,14 @@ evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, cst = NULL; if (cst) { - if (!known_vals_ptr->length ()) - vec_safe_grow_cleared (known_vals_ptr, count, true); - (*known_vals_ptr)[i] = cst; + if (!avals->m_known_vals.length ()) + avals->m_known_vals.safe_grow_cleared (count, true); + avals->m_known_vals[i] = cst; } } } - evaluate_conditions_for_known_args (callee, inline_p, - *known_vals_ptr, - known_value_ranges, - *known_aggs_ptr, - clause_ptr, + evaluate_conditions_for_known_args (callee, inline_p, avals, clause_ptr, nonspec_clause_ptr); } @@ -781,7 +769,7 @@ ipa_fn_summary_t::duplicate (cgraph_node *src, vec *entry = info->size_time_table; /* Use SRC parm info since it may not be copied yet. */ class ipa_node_params *parms_info = IPA_NODE_REF (src); - vec known_vals = vNULL; + ipa_auto_call_arg_values avals; int count = ipa_get_param_count (parms_info); int i, j; clause_t possible_truths; @@ -792,7 +780,7 @@ ipa_fn_summary_t::duplicate (cgraph_node *src, struct cgraph_edge *edge, *next; info->size_time_table = 0; - known_vals.safe_grow_cleared (count, true); + avals.m_known_vals.safe_grow_cleared (count, true); for (i = 0; i < count; i++) { struct ipa_replace_map *r; @@ -801,20 +789,17 @@ ipa_fn_summary_t::duplicate (cgraph_node *src, { if (r->parm_num == i) { - known_vals[i] = r->new_tree; + avals.m_known_vals[i] = r->new_tree; break; } } } evaluate_conditions_for_known_args (dst, false, - known_vals, - vNULL, - vNULL, + &avals, &possible_truths, /* We are going to specialize, so ignore nonspec truths. */ NULL); - known_vals.release (); info->account_size_time (0, 0, true_pred, true_pred); @@ -3009,15 +2994,14 @@ compute_fn_summary_for_current (void) return 0; } -/* Estimate benefit devirtualizing indirect edge IE, provided KNOWN_VALS, - KNOWN_CONTEXTS and KNOWN_AGGS. */ +/* Estimate benefit devirtualizing indirect edge IE and return true if it can + be devirtualized and inlined, provided m_known_vals, m_known_contexts and + m_known_aggs in AVALS. Return false straight away if AVALS is NULL. */ static bool estimate_edge_devirt_benefit (struct cgraph_edge *ie, int *size, int *time, - vec known_vals, - vec known_contexts, - vec known_aggs) + ipa_call_arg_values *avals) { tree target; struct cgraph_node *callee; @@ -3025,13 +3009,13 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie, enum availability avail; bool speculative; - if (!known_vals.length () && !known_contexts.length ()) + if (!avals + || (!avals->m_known_vals.length() && !avals->m_known_contexts.length ())) return false; if (!opt_for_fn (ie->caller->decl, flag_indirect_inlining)) return false; - target = ipa_get_indirect_edge_target (ie, known_vals, known_contexts, - known_aggs, &speculative); + target = ipa_get_indirect_edge_target (ie, avals, &speculative); if (!target || speculative) return false; @@ -3055,17 +3039,13 @@ estimate_edge_devirt_benefit (struct cgraph_edge *ie, } /* Increase SIZE, MIN_SIZE (if non-NULL) and TIME for size and time needed to - handle edge E with probability PROB. - Set HINTS if edge may be devirtualized. - KNOWN_VALS, KNOWN_AGGS and KNOWN_CONTEXTS describe context of the call - site. */ + handle edge E with probability PROB. Set HINTS accordingly if edge may be + devirtualized. AVALS, if non-NULL, describes the context of the call site + as far as values of parameters are concerened. */ static inline void estimate_edge_size_and_time (struct cgraph_edge *e, int *size, int *min_size, - sreal *time, - vec known_vals, - vec known_contexts, - vec known_aggs, + sreal *time, ipa_call_arg_values *avals, ipa_hints *hints) { class ipa_call_summary *es = ipa_call_summaries->get (e); @@ -3074,8 +3054,7 @@ estimate_edge_size_and_time (struct cgraph_edge *e, int *size, int *min_size, int cur_size; if (!e->callee && hints && e->maybe_hot_p () - && estimate_edge_devirt_benefit (e, &call_size, &call_time, - known_vals, known_contexts, known_aggs)) + && estimate_edge_devirt_benefit (e, &call_size, &call_time, avals)) *hints |= INLINE_HINT_indirect_call; cur_size = call_size * ipa_fn_summary::size_scale; *size += cur_size; @@ -3087,9 +3066,9 @@ estimate_edge_size_and_time (struct cgraph_edge *e, int *size, int *min_size, /* Increase SIZE, MIN_SIZE and TIME for size and time needed to handle all - calls in NODE. POSSIBLE_TRUTHS, KNOWN_VALS, KNOWN_AGGS and KNOWN_CONTEXTS - describe context of the call site. - + calls in NODE. POSSIBLE_TRUTHS and AVALS describe the context of the call + site. + Helper for estimate_calls_size_and_time which does the same but (in most cases) faster. */ @@ -3098,9 +3077,7 @@ estimate_calls_size_and_time_1 (struct cgraph_node *node, int *size, int *min_size, sreal *time, ipa_hints *hints, clause_t possible_truths, - vec known_vals, - vec known_contexts, - vec known_aggs) + ipa_call_arg_values *avals) { struct cgraph_edge *e; for (e = node->callees; e; e = e->next_callee) @@ -3109,10 +3086,8 @@ estimate_calls_size_and_time_1 (struct cgraph_node *node, int *size, { gcc_checking_assert (!ipa_call_summaries->get (e)); estimate_calls_size_and_time_1 (e->callee, size, min_size, time, - hints, - possible_truths, - known_vals, known_contexts, - known_aggs); + hints, possible_truths, avals); + continue; } class ipa_call_summary *es = ipa_call_summaries->get (e); @@ -3130,9 +3105,7 @@ estimate_calls_size_and_time_1 (struct cgraph_node *node, int *size, so we do not need to compute probabilities. */ estimate_edge_size_and_time (e, size, es->predicate ? NULL : min_size, - time, - known_vals, known_contexts, - known_aggs, hints); + time, avals, hints); } } for (e = node->indirect_calls; e; e = e->next_callee) @@ -3142,9 +3115,7 @@ estimate_calls_size_and_time_1 (struct cgraph_node *node, int *size, || es->predicate->evaluate (possible_truths)) estimate_edge_size_and_time (e, size, es->predicate ? NULL : min_size, - time, - known_vals, known_contexts, known_aggs, - hints); + time, avals, hints); } } @@ -3166,8 +3137,7 @@ summarize_calls_size_and_time (struct cgraph_node *node, int size = 0; sreal time = 0; - estimate_edge_size_and_time (e, &size, NULL, &time, - vNULL, vNULL, vNULL, NULL); + estimate_edge_size_and_time (e, &size, NULL, &time, NULL, NULL); struct predicate pred = true; class ipa_call_summary *es = ipa_call_summaries->get (e); @@ -3181,8 +3151,7 @@ summarize_calls_size_and_time (struct cgraph_node *node, int size = 0; sreal time = 0; - estimate_edge_size_and_time (e, &size, NULL, &time, - vNULL, vNULL, vNULL, NULL); + estimate_edge_size_and_time (e, &size, NULL, &time, NULL, NULL); struct predicate pred = true; class ipa_call_summary *es = ipa_call_summaries->get (e); @@ -3193,17 +3162,15 @@ summarize_calls_size_and_time (struct cgraph_node *node, } /* Increase SIZE, MIN_SIZE and TIME for size and time needed to handle all - calls in NODE. POSSIBLE_TRUTHS, KNOWN_VALS, KNOWN_AGGS and KNOWN_CONTEXTS - describe context of the call site. */ + calls in NODE. POSSIBLE_TRUTHS and AVALS (the latter if non-NULL) describe + context of the call site. */ static void estimate_calls_size_and_time (struct cgraph_node *node, int *size, int *min_size, sreal *time, ipa_hints *hints, clause_t possible_truths, - vec known_vals, - vec known_contexts, - vec known_aggs) + ipa_call_arg_values *avals) { class ipa_fn_summary *sum = ipa_fn_summaries->get (node); bool use_table = true; @@ -3222,9 +3189,10 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size, use_table = false; /* If there is an indirect edge that may be optimized, we need to go the slow way. */ - else if ((known_vals.length () - || known_contexts.length () - || known_aggs.length ()) && hints) + else if (avals && hints + && (avals->m_known_vals.length () + || avals->m_known_contexts.length () + || avals->m_known_aggs.length ())) { class ipa_node_params *params_summary = IPA_NODE_REF (node); unsigned int nargs = params_summary @@ -3233,13 +3201,13 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size, for (unsigned int i = 0; i < nargs && use_table; i++) { if (ipa_is_param_used_by_indirect_call (params_summary, i) - && ((known_vals.length () > i && known_vals[i]) - || (known_aggs.length () > i - && known_aggs[i].items.length ()))) + && (avals->safe_sval_at (i) + || (avals->m_known_aggs.length () > i + && avals->m_known_aggs[i].items.length ()))) use_table = false; else if (ipa_is_param_used_by_polymorphic_call (params_summary, i) - && (known_contexts.length () > i - && !known_contexts[i].useless_p ())) + && (avals->m_known_contexts.length () > i + && !avals->m_known_contexts[i].useless_p ())) use_table = false; } } @@ -3282,8 +3250,7 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size, < ipa_fn_summary::max_size_time_table_size) { estimate_calls_size_and_time_1 (node, &old_size, NULL, &old_time, NULL, - possible_truths, known_vals, - known_contexts, known_aggs); + possible_truths, avals); gcc_assert (*size == old_size); if (time && (*time - old_time > 1 || *time - old_time < -1) && dump_file) @@ -3295,31 +3262,22 @@ estimate_calls_size_and_time (struct cgraph_node *node, int *size, /* Slow path by walking all edges. */ else estimate_calls_size_and_time_1 (node, size, min_size, time, hints, - possible_truths, known_vals, known_contexts, - known_aggs); + possible_truths, avals); } -/* Default constructor for ipa call context. - Memory allocation of known_vals, known_contexts - and known_aggs vectors is owned by the caller, but can - be release by ipa_call_context::release. - - inline_param_summary is owned by the caller. */ -ipa_call_context::ipa_call_context (cgraph_node *node, - clause_t possible_truths, +/* Main constructor for ipa call context. Memory allocation of ARG_VALUES + is owned by the caller. INLINE_PARAM_SUMMARY is also owned by the + caller. */ + +ipa_call_context::ipa_call_context (cgraph_node *node, clause_t possible_truths, clause_t nonspec_possible_truths, - vec known_vals, - vec - known_contexts, - vec known_aggs, vec - inline_param_summary) + inline_param_summary, + ipa_auto_call_arg_values *arg_values) : m_node (node), m_possible_truths (possible_truths), m_nonspec_possible_truths (nonspec_possible_truths), m_inline_param_summary (inline_param_summary), - m_known_vals (known_vals), - m_known_contexts (known_contexts), - m_known_aggs (known_aggs) + m_avals (arg_values) { } @@ -3350,47 +3308,50 @@ ipa_call_context::duplicate_from (const ipa_call_context &ctx) break; } } - m_known_vals = vNULL; - if (ctx.m_known_vals.exists ()) + m_avals.m_known_vals = vNULL; + if (ctx.m_avals.m_known_vals.exists ()) { - unsigned int n = MIN (ctx.m_known_vals.length (), nargs); + unsigned int n = MIN (ctx.m_avals.m_known_vals.length (), nargs); for (unsigned int i = 0; i < n; i++) if (ipa_is_param_used_by_indirect_call (params_summary, i) - && ctx.m_known_vals[i]) + && ctx.m_avals.m_known_vals[i]) { - m_known_vals = ctx.m_known_vals.copy (); + m_avals.m_known_vals = ctx.m_avals.m_known_vals.copy (); break; } } - m_known_contexts = vNULL; - if (ctx.m_known_contexts.exists ()) + m_avals.m_known_contexts = vNULL; + if (ctx.m_avals.m_known_contexts.exists ()) { - unsigned int n = MIN (ctx.m_known_contexts.length (), nargs); + unsigned int n = MIN (ctx.m_avals.m_known_contexts.length (), nargs); for (unsigned int i = 0; i < n; i++) if (ipa_is_param_used_by_polymorphic_call (params_summary, i) - && !ctx.m_known_contexts[i].useless_p ()) + && !ctx.m_avals.m_known_contexts[i].useless_p ()) { - m_known_contexts = ctx.m_known_contexts.copy (); + m_avals.m_known_contexts = ctx.m_avals.m_known_contexts.copy (); break; } } - m_known_aggs = vNULL; - if (ctx.m_known_aggs.exists ()) + m_avals.m_known_aggs = vNULL; + if (ctx.m_avals.m_known_aggs.exists ()) { - unsigned int n = MIN (ctx.m_known_aggs.length (), nargs); + unsigned int n = MIN (ctx.m_avals.m_known_aggs.length (), nargs); for (unsigned int i = 0; i < n; i++) if (ipa_is_param_used_by_indirect_call (params_summary, i) - && !ctx.m_known_aggs[i].is_empty ()) + && !ctx.m_avals.m_known_aggs[i].is_empty ()) { - m_known_aggs = ipa_copy_agg_values (ctx.m_known_aggs); + m_avals.m_known_aggs + = ipa_copy_agg_values (ctx.m_avals.m_known_aggs); break; } } + + m_avals.m_known_value_ranges = vNULL; } /* Release memory used by known_vals/contexts/aggs vectors. @@ -3404,11 +3365,11 @@ ipa_call_context::release (bool all) /* See if context is initialized at first place. */ if (!m_node) return; - ipa_release_agg_values (m_known_aggs, all); + ipa_release_agg_values (m_avals.m_known_aggs, all); if (all) { - m_known_vals.release (); - m_known_contexts.release (); + m_avals.m_known_vals.release (); + m_avals.m_known_contexts.release (); m_inline_param_summary.release (); } } @@ -3454,77 +3415,81 @@ ipa_call_context::equal_to (const ipa_call_context &ctx) return false; } } - if (m_known_vals.exists () || ctx.m_known_vals.exists ()) + if (m_avals.m_known_vals.exists () || ctx.m_avals.m_known_vals.exists ()) { for (unsigned int i = 0; i < nargs; i++) { if (!ipa_is_param_used_by_indirect_call (params_summary, i)) continue; - if (i >= m_known_vals.length () || !m_known_vals[i]) + if (i >= m_avals.m_known_vals.length () || !m_avals.m_known_vals[i]) { - if (i < ctx.m_known_vals.length () && ctx.m_known_vals[i]) + if (i < ctx.m_avals.m_known_vals.length () + && ctx.m_avals.m_known_vals[i]) return false; continue; } - if (i >= ctx.m_known_vals.length () || !ctx.m_known_vals[i]) + if (i >= ctx.m_avals.m_known_vals.length () + || !ctx.m_avals.m_known_vals[i]) { - if (i < m_known_vals.length () && m_known_vals[i]) + if (i < m_avals.m_known_vals.length () && m_avals.m_known_vals[i]) return false; continue; } - if (m_known_vals[i] != ctx.m_known_vals[i]) + if (m_avals.m_known_vals[i] != ctx.m_avals.m_known_vals[i]) return false; } } - if (m_known_contexts.exists () || ctx.m_known_contexts.exists ()) + if (m_avals.m_known_contexts.exists () + || ctx.m_avals.m_known_contexts.exists ()) { for (unsigned int i = 0; i < nargs; i++) { if (!ipa_is_param_used_by_polymorphic_call (params_summary, i)) continue; - if (i >= m_known_contexts.length () - || m_known_contexts[i].useless_p ()) + if (i >= m_avals.m_known_contexts.length () + || m_avals.m_known_contexts[i].useless_p ()) { - if (i < ctx.m_known_contexts.length () - && !ctx.m_known_contexts[i].useless_p ()) + if (i < ctx.m_avals.m_known_contexts.length () + && !ctx.m_avals.m_known_contexts[i].useless_p ()) return false; continue; } - if (i >= ctx.m_known_contexts.length () - || ctx.m_known_contexts[i].useless_p ()) + if (i >= ctx.m_avals.m_known_contexts.length () + || ctx.m_avals.m_known_contexts[i].useless_p ()) { - if (i < m_known_contexts.length () - && !m_known_contexts[i].useless_p ()) + if (i < m_avals.m_known_contexts.length () + && !m_avals.m_known_contexts[i].useless_p ()) return false; continue; } - if (!m_known_contexts[i].equal_to - (ctx.m_known_contexts[i])) + if (!m_avals.m_known_contexts[i].equal_to + (ctx.m_avals.m_known_contexts[i])) return false; } } - if (m_known_aggs.exists () || ctx.m_known_aggs.exists ()) + if (m_avals.m_known_aggs.exists () || ctx.m_avals.m_known_aggs.exists ()) { for (unsigned int i = 0; i < nargs; i++) { if (!ipa_is_param_used_by_indirect_call (params_summary, i)) continue; - if (i >= m_known_aggs.length () || m_known_aggs[i].is_empty ()) + if (i >= m_avals.m_known_aggs.length () + || m_avals.m_known_aggs[i].is_empty ()) { - if (i < ctx.m_known_aggs.length () - && !ctx.m_known_aggs[i].is_empty ()) + if (i < ctx.m_avals.m_known_aggs.length () + && !ctx.m_avals.m_known_aggs[i].is_empty ()) return false; continue; } - if (i >= ctx.m_known_aggs.length () - || ctx.m_known_aggs[i].is_empty ()) + if (i >= ctx.m_avals.m_known_aggs.length () + || ctx.m_avals.m_known_aggs[i].is_empty ()) { - if (i < m_known_aggs.length () - && !m_known_aggs[i].is_empty ()) + if (i < m_avals.m_known_aggs.length () + && !m_avals.m_known_aggs[i].is_empty ()) return false; continue; } - if (!m_known_aggs[i].equal_to (ctx.m_known_aggs[i])) + if (!m_avals.m_known_aggs[i].equal_to (ctx.m_avals.m_known_aggs[i])) return false; } } @@ -3574,7 +3539,7 @@ ipa_call_context::estimate_size_and_time (int *ret_size, estimate_calls_size_and_time (m_node, &size, &min_size, ret_time ? &time : NULL, ret_hints ? &hints : NULL, m_possible_truths, - m_known_vals, m_known_contexts, m_known_aggs); + &m_avals); sreal nonspecialized_time = time; @@ -3681,22 +3646,16 @@ ipa_call_context::estimate_size_and_time (int *ret_size, void estimate_ipcp_clone_size_and_time (struct cgraph_node *node, - vec known_vals, - vec - known_contexts, - vec known_aggs, + ipa_auto_call_arg_values *avals, int *ret_size, sreal *ret_time, sreal *ret_nonspec_time, ipa_hints *hints) { clause_t clause, nonspec_clause; - /* TODO: Also pass known value ranges. */ - evaluate_conditions_for_known_args (node, false, known_vals, vNULL, - known_aggs, &clause, &nonspec_clause); - ipa_call_context ctx (node, clause, nonspec_clause, - known_vals, known_contexts, - known_aggs, vNULL); + evaluate_conditions_for_known_args (node, false, avals, &clause, + &nonspec_clause); + ipa_call_context ctx (node, clause, nonspec_clause, vNULL, avals); ctx.estimate_size_and_time (ret_size, NULL, ret_time, ret_nonspec_time, hints); } @@ -3914,10 +3873,8 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge) if (callee_info->conds) { - auto_vec known_vals; - auto_vec known_aggs; - evaluate_properties_for_edge (edge, true, &clause, NULL, - &known_vals, NULL, &known_aggs); + ipa_auto_call_arg_values avals; + evaluate_properties_for_edge (edge, true, &clause, NULL, &avals, false); } if (ipa_node_params_sum && callee_info->conds) { @@ -4011,8 +3968,7 @@ ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge) int edge_size = 0; sreal edge_time = 0; - estimate_edge_size_and_time (edge, &edge_size, NULL, &edge_time, vNULL, - vNULL, vNULL, 0); + estimate_edge_size_and_time (edge, &edge_size, NULL, &edge_time, NULL, 0); /* Unaccount size and time of the optimized out call. */ info->account_size_time (-edge_size, -edge_time, es->predicate ? *es->predicate : true, @@ -4054,7 +4010,7 @@ ipa_update_overall_fn_summary (struct cgraph_node *node, bool reset) estimate_calls_size_and_time (node, &size_info->size, &info->min_size, &info->time, NULL, ~(clause_t) (1 << predicate::false_condition), - vNULL, vNULL, vNULL); + NULL); size_info->size = RDIV (size_info->size, ipa_fn_summary::size_scale); info->min_size = RDIV (info->min_size, ipa_fn_summary::size_scale); } diff --git a/gcc/ipa-fnsummary.h b/gcc/ipa-fnsummary.h index c6ddc9f3199..dfcde9f91b8 100644 --- a/gcc/ipa-fnsummary.h +++ b/gcc/ipa-fnsummary.h @@ -297,10 +297,8 @@ public: ipa_call_context (cgraph_node *node, clause_t possible_truths, clause_t nonspec_possible_truths, - vec known_vals, - vec known_contexts, - vec known_aggs, - vec m_inline_param_summary); + vec inline_param_summary, + ipa_auto_call_arg_values *arg_values); ipa_call_context () : m_node(NULL) { @@ -328,14 +326,9 @@ private: /* Inline summary maintains info about change probabilities. */ vec m_inline_param_summary; - /* The following is used only to resolve indirect calls. */ - - /* Vector describing known values of parameters. */ - vec m_known_vals; - /* Vector describing known polymorphic call contexts. */ - vec m_known_contexts; - /* Vector describing known aggregate values. */ - vec m_known_aggs; + /* Even after having calculated clauses, the information about argument + values is used to resolve indirect calls. */ + ipa_call_arg_values m_avals; }; extern fast_call_summary *ipa_call_summaries; @@ -349,9 +342,7 @@ void ipa_free_fn_summary (void); void ipa_free_size_summary (void); void inline_analyze_function (struct cgraph_node *node); void estimate_ipcp_clone_size_and_time (struct cgraph_node *, - vec, - vec, - vec, + ipa_auto_call_arg_values *, int *, sreal *, sreal *, ipa_hints *); void ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge); @@ -363,10 +354,8 @@ void evaluate_properties_for_edge (struct cgraph_edge *e, bool inline_p, clause_t *clause_ptr, clause_t *nonspec_clause_ptr, - vec *known_vals_ptr, - vec - *known_contexts_ptr, - vec *); + ipa_auto_call_arg_values *avals, + bool compute_contexts); void ipa_fnsummary_c_finalize (void); HOST_WIDE_INT ipa_get_stack_frame_offset (struct cgraph_node *node); diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c index 148efbc09ef..d2ae8196d09 100644 --- a/gcc/ipa-inline-analysis.c +++ b/gcc/ipa-inline-analysis.c @@ -184,20 +184,16 @@ do_estimate_edge_time (struct cgraph_edge *edge, sreal *ret_nonspec_time) ipa_hints hints; struct cgraph_node *callee; clause_t clause, nonspec_clause; - auto_vec known_vals; - auto_vec known_contexts; - auto_vec known_aggs; + ipa_auto_call_arg_values avals; class ipa_call_summary *es = ipa_call_summaries->get (edge); int min_size = -1; callee = edge->callee->ultimate_alias_target (); gcc_checking_assert (edge->inline_failed); - evaluate_properties_for_edge (edge, true, - &clause, &nonspec_clause, &known_vals, - &known_contexts, &known_aggs); - ipa_call_context ctx (callee, clause, nonspec_clause, known_vals, - known_contexts, known_aggs, es->param); + evaluate_properties_for_edge (edge, true, &clause, &nonspec_clause, + &avals, true); + ipa_call_context ctx (callee, clause, nonspec_clause, es->param, &avals); if (node_context_cache != NULL) { node_context_summary *e = node_context_cache->get_create (callee); @@ -255,7 +251,6 @@ do_estimate_edge_time (struct cgraph_edge *edge, sreal *ret_nonspec_time) : edge->caller->count.ipa ()))) hints |= INLINE_HINT_known_hot; - ctx.release (); gcc_checking_assert (size >= 0); gcc_checking_assert (time >= 0); @@ -307,9 +302,6 @@ do_estimate_edge_size (struct cgraph_edge *edge) int size; struct cgraph_node *callee; clause_t clause, nonspec_clause; - 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. */ @@ -325,14 +317,11 @@ do_estimate_edge_size (struct cgraph_edge *edge) /* Early inliner runs without caching, go ahead and do the dirty work. */ gcc_checking_assert (edge->inline_failed); - evaluate_properties_for_edge (edge, true, - &clause, &nonspec_clause, - &known_vals, &known_contexts, - &known_aggs); - ipa_call_context ctx (callee, clause, nonspec_clause, known_vals, - known_contexts, known_aggs, vNULL); + ipa_auto_call_arg_values avals; + evaluate_properties_for_edge (edge, true, &clause, &nonspec_clause, + &avals, true); + ipa_call_context ctx (callee, clause, nonspec_clause, vNULL, &avals); ctx.estimate_size_and_time (&size, NULL, NULL, NULL, NULL); - ctx.release (); return size; } @@ -346,9 +335,6 @@ do_estimate_edge_hints (struct cgraph_edge *edge) ipa_hints hints; struct cgraph_node *callee; clause_t clause, nonspec_clause; - 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. */ @@ -364,14 +350,11 @@ do_estimate_edge_hints (struct cgraph_edge *edge) /* Early inliner runs without caching, go ahead and do the dirty work. */ gcc_checking_assert (edge->inline_failed); - evaluate_properties_for_edge (edge, true, - &clause, &nonspec_clause, - &known_vals, &known_contexts, - &known_aggs); - ipa_call_context ctx (callee, clause, nonspec_clause, known_vals, - known_contexts, known_aggs, vNULL); + ipa_auto_call_arg_values avals; + evaluate_properties_for_edge (edge, true, &clause, &nonspec_clause, + &avals, true); + ipa_call_context ctx (callee, clause, nonspec_clause, vNULL, &avals); ctx.estimate_size_and_time (NULL, NULL, NULL, NULL, &hints); - ctx.release (); hints |= simple_edge_hints (edge); return hints; } diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index b28c78eeab4..230625a89bb 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -5795,4 +5795,14 @@ ipa_agg_value::equal_to (const ipa_agg_value &other) return offset == other.offset && operand_equal_p (value, other.value, 0); } + +/* Destructor also removing individual aggregate values. */ + +ipa_auto_call_arg_values::~ipa_auto_call_arg_values () +{ + ipa_release_agg_values (m_known_aggs, false); +} + + + #include "gt-ipa-prop.h" diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h index 23fcf905ef3..8b2edf6300c 100644 --- a/gcc/ipa-prop.h +++ b/gcc/ipa-prop.h @@ -433,6 +433,107 @@ ipa_get_jf_ancestor_type_preserved (struct ipa_jump_func *jfunc) return jfunc->value.ancestor.agg_preserved; } +/* Class for allocating a bundle of various potentially known properties about + actual arguments of a particular call on stack for the usual case and on + heap only if there are unusually many arguments. The data is deallocated + when the instance of this class goes out of scope or is otherwise + destructed. */ + +class ipa_auto_call_arg_values +{ +public: + ~ipa_auto_call_arg_values (); + + /* If m_known_vals (vector of known "scalar" values) is sufficiantly long, + return its element at INDEX, otherwise return NULL. */ + tree safe_sval_at (int index) + { + /* TODO: Assert non-negative index here and test. */ + if ((unsigned) index < m_known_vals.length ()) + return m_known_vals[index]; + return NULL; + } + + /* If m_known_aggs is sufficiantly long, return the pointer rto its element + at INDEX, otherwise return NULL. */ + ipa_agg_value_set *safe_aggval_at (int index) + { + /* TODO: Assert non-negative index here and test. */ + if ((unsigned) index < m_known_aggs.length ()) + return &m_known_aggs[index]; + return NULL; + } + + /* Vector describing known values of parameters. */ + auto_vec m_known_vals; + + /* Vector describing known polymorphic call contexts. */ + auto_vec m_known_contexts; + + /* Vector describing known aggregate values. */ + auto_vec m_known_aggs; + + /* Vector describing known value ranges of arguments. */ + auto_vec m_known_value_ranges; +}; + +/* Class bundling the various potentially known properties about actual + arguments of a particular call. This variant does not deallocate the + bundled data in any way. */ + +class ipa_call_arg_values +{ +public: + /* Default constructor, setting the vectors to empty ones. */ + ipa_call_arg_values () + {} + + /* Construct this general variant of the bundle from the variant which uses + auto_vecs to hold the vectors. This means that vectors of objects + constructed with this constructor should not be changed because if they + get reallocated, the member vectors and the underlying auto_vecs would get + out of sync. */ + ipa_call_arg_values (ipa_auto_call_arg_values *aavals) + : m_known_vals (aavals->m_known_vals), + m_known_contexts (aavals->m_known_contexts), + m_known_aggs (aavals->m_known_aggs), + m_known_value_ranges (aavals->m_known_value_ranges) + {} + + /* If m_known_vals (vector of known "scalar" values) is sufficiantly long, + return its element at INDEX, otherwise return NULL. */ + tree safe_sval_at (int index) + { + /* TODO: Assert non-negative index here and test. */ + if ((unsigned) index < m_known_vals.length ()) + return m_known_vals[index]; + return NULL; + } + + /* If m_known_aggs is sufficiantly long, return the pointer rto its element + at INDEX, otherwise return NULL. */ + ipa_agg_value_set *safe_aggval_at (int index) + { + /* TODO: Assert non-negative index here and test. */ + if ((unsigned) index < m_known_aggs.length ()) + return &m_known_aggs[index]; + return NULL; + } + + /* Vector describing known values of parameters. */ + vec m_known_vals = vNULL; + + /* Vector describing known polymorphic call contexts. */ + vec m_known_contexts = vNULL; + + /* Vector describing known aggregate values. */ + vec m_known_aggs = vNULL; + + /* Vector describing known value ranges of arguments. */ + vec m_known_value_ranges = vNULL; +}; + + /* Summary describing a single formal parameter. */ struct GTY(()) ipa_param_descriptor @@ -970,12 +1071,13 @@ void ipa_initialize_node_params (struct cgraph_node *node); bool ipa_propagate_indirect_call_infos (struct cgraph_edge *cs, vec *new_edges); -/* Indirect edge and binfo processing. */ +/* Indirect edge processing and target discovery. */ tree ipa_get_indirect_edge_target (struct cgraph_edge *ie, - vec, - vec, - vec, - bool *); + ipa_call_arg_values *avals, + bool *speculative); +tree ipa_get_indirect_edge_target (struct cgraph_edge *ie, + ipa_auto_call_arg_values *avals, + bool *speculative); struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree, bool speculative = false); tree ipa_impossible_devirt_target (struct cgraph_edge *, tree);