From 1e7fdc02cba43e646fb2389e3c79e7c4e5ff772e Mon Sep 17 00:00:00 2001 From: Martin Jambor Date: Fri, 2 Oct 2020 18:41:34 +0200 Subject: [PATCH] ipa: Bundle estimates of ipa_call_context::estimate_size_and_time A subsequent patch adds another two estimates that the code in ipa_call_context::estimate_size_and_time computes, and the fact that the function has a special output parameter for each thing it computes would make it have just too many. Therefore, this patch collapses all those ouptut parameters into one output structure. gcc/ChangeLog: 2020-09-02 Martin Jambor * ipa-inline-analysis.c (do_estimate_edge_time): Adjusted to use ipa_call_estimates. (do_estimate_edge_size): Likewise. (do_estimate_edge_hints): Likewise. * ipa-fnsummary.h (struct ipa_call_estimates): New type. (ipa_call_context::estimate_size_and_time): Adjusted declaration. (estimate_ipcp_clone_size_and_time): Likewise. * ipa-cp.c (hint_time_bonus): Changed the type of the second argument to ipa_call_estimates. (perform_estimation_of_a_value): Adjusted to use ipa_call_estimates. (estimate_local_effects): Likewise. * ipa-fnsummary.c (ipa_call_context::estimate_size_and_time): Adjusted to return estimates in a single ipa_call_estimates parameter. (estimate_ipcp_clone_size_and_time): Likewise. --- gcc/ipa-cp.c | 45 ++++++++++++++--------------- gcc/ipa-fnsummary.c | 60 +++++++++++++++++++-------------------- gcc/ipa-fnsummary.h | 36 +++++++++++++++++------ gcc/ipa-inline-analysis.c | 47 +++++++++++++++++------------- 4 files changed, 105 insertions(+), 83 deletions(-) diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index 292dd7e5bdf..77c84a6ed5d 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -3196,12 +3196,13 @@ devirtualization_time_bonus (struct cgraph_node *node, return res; } -/* Return time bonus incurred because of HINTS. */ +/* Return time bonus incurred because of hints stored in ESTIMATES. */ static int -hint_time_bonus (cgraph_node *node, ipa_hints hints) +hint_time_bonus (cgraph_node *node, const ipa_call_estimates &estimates) { int result = 0; + ipa_hints hints = estimates.hints; if (hints & (INLINE_HINT_loop_iterations | INLINE_HINT_loop_stride)) result += opt_for_fn (node->decl, param_ipa_cp_loop_hint_bonus); return result; @@ -3397,15 +3398,13 @@ perform_estimation_of_a_value (cgraph_node *node, int removable_params_cost, int est_move_cost, ipcp_value_base *val) { - int size, time_benefit; - sreal time, base_time; - ipa_hints hints; + int time_benefit; + ipa_call_estimates estimates; - estimate_ipcp_clone_size_and_time (node, avals, &size, &time, - &base_time, &hints); - base_time -= time; - if (base_time > 65535) - base_time = 65535; + estimate_ipcp_clone_size_and_time (node, avals, &estimates); + sreal time_delta = estimates.nonspecialized_time - estimates.time; + if (time_delta > 65535) + time_delta = 65535; /* Extern inline functions have no cloning local time benefits because they will be inlined anyway. The only reason to clone them is if it enables @@ -3413,11 +3412,12 @@ perform_estimation_of_a_value (cgraph_node *node, if (DECL_EXTERNAL (node->decl) && DECL_DECLARED_INLINE_P (node->decl)) time_benefit = 0; else - time_benefit = base_time.to_int () + time_benefit = time_delta.to_int () + devirtualization_time_bonus (node, avals) - + hint_time_bonus (node, hints) + + hint_time_bonus (node, estimates) + removable_params_cost + est_move_cost; + int size = estimates.size; gcc_checking_assert (size >=0); /* The inliner-heuristics based estimates may think that in certain contexts some functions do not have any size at all but we want @@ -3472,23 +3472,21 @@ estimate_local_effects (struct cgraph_node *node) || (removable_params_cost && node->can_change_signature)) { struct caller_statistics stats; - ipa_hints hints; - sreal time, base_time; - int size; + ipa_call_estimates estimates; init_caller_stats (&stats); node->call_for_symbol_thunks_and_aliases (gather_caller_stats, &stats, false); - estimate_ipcp_clone_size_and_time (node, &avals, &size, &time, - &base_time, &hints); - time -= devirt_bonus; - time -= hint_time_bonus (node, hints); - time -= removable_params_cost; - size -= stats.n_calls * removable_params_cost; + estimate_ipcp_clone_size_and_time (node, &avals, &estimates); + sreal time = estimates.nonspecialized_time - estimates.time; + time += devirt_bonus; + time += hint_time_bonus (node, estimates); + time += removable_params_cost; + int size = estimates.size - stats.n_calls * removable_params_cost; if (dump_file) fprintf (dump_file, " - context independent values, size: %i, " - "time_benefit: %f\n", size, (base_time - time).to_double ()); + "time_benefit: %f\n", size, (time).to_double ()); if (size <= 0 || node->local) { @@ -3499,8 +3497,7 @@ estimate_local_effects (struct cgraph_node *node) "known contexts, code not going to grow.\n"); } else if (good_cloning_opportunity_p (node, - MIN ((base_time - time).to_int (), - 65536), + MIN ((time).to_int (), 65536), stats.freq_sum, stats.count_sum, size)) { diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c index fe236963fd8..f89f1583b6b 100644 --- a/gcc/ipa-fnsummary.c +++ b/gcc/ipa-fnsummary.c @@ -3536,18 +3536,14 @@ ipa_call_context::equal_to (const ipa_call_context &ctx) return true; } -/* Estimate size and time needed to execute call in the given context. - Additionally determine hints determined by the context. Finally compute - minimal size needed for the call that is independent on the call context and - can be used for fast estimates. Return the values in RET_SIZE, - RET_MIN_SIZE, RET_TIME and RET_HINTS. */ +/* Fill in the selected fields in ESTIMATES with value estimated for call in + this context. Always compute size and min_size. Only compute time and + nonspecialized_time if EST_TIMES is true. Only compute hints if EST_HINTS + is true. */ void -ipa_call_context::estimate_size_and_time (int *ret_size, - int *ret_min_size, - sreal *ret_time, - sreal *ret_nonspecialized_time, - ipa_hints *ret_hints) +ipa_call_context::estimate_size_and_time (ipa_call_estimates *estimates, + bool est_times, bool est_hints) { class ipa_fn_summary *info = ipa_fn_summaries->get (m_node); size_time_entry *e; @@ -3577,8 +3573,8 @@ ipa_call_context::estimate_size_and_time (int *ret_size, if (m_node->callees || m_node->indirect_calls) estimate_calls_size_and_time (m_node, &size, &min_size, - ret_time ? &time : NULL, - ret_hints ? &hints : NULL, m_possible_truths, + est_times ? &time : NULL, + est_hints ? &hints : NULL, m_possible_truths, &m_avals); sreal nonspecialized_time = time; @@ -3605,7 +3601,7 @@ ipa_call_context::estimate_size_and_time (int *ret_size, known to be constant in a specialized setting. */ if (nonconst) size += e->size; - if (!ret_time) + if (!est_times) continue; nonspecialized_time += e->time; if (!nonconst) @@ -3645,7 +3641,7 @@ ipa_call_context::estimate_size_and_time (int *ret_size, if (time > nonspecialized_time) time = nonspecialized_time; - if (ret_hints) + if (est_hints) { if (info->loop_iterations && !info->loop_iterations->evaluate (m_possible_truths)) @@ -3663,18 +3659,23 @@ ipa_call_context::estimate_size_and_time (int *ret_size, min_size = RDIV (min_size, ipa_fn_summary::size_scale); if (dump_file && (dump_flags & TDF_DETAILS)) - fprintf (dump_file, "\n size:%i time:%f nonspec time:%f\n", (int) size, - time.to_double (), nonspecialized_time.to_double ()); - if (ret_time) - *ret_time = time; - if (ret_nonspecialized_time) - *ret_nonspecialized_time = nonspecialized_time; - if (ret_size) - *ret_size = size; - if (ret_min_size) - *ret_min_size = min_size; - if (ret_hints) - *ret_hints = hints; + { + if (est_times) + fprintf (dump_file, "\n size:%i time:%f nonspec time:%f\n", + (int) size, time.to_double (), + nonspecialized_time.to_double ()); + else + fprintf (dump_file, "\n size:%i (time not estimated)\n", (int) size); + } + if (est_times) + { + estimates->time = time; + estimates->nonspecialized_time = nonspecialized_time; + } + estimates->size = size; + estimates->min_size = min_size; + if (est_hints) + estimates->hints = hints; return; } @@ -3687,17 +3688,14 @@ ipa_call_context::estimate_size_and_time (int *ret_size, void estimate_ipcp_clone_size_and_time (struct cgraph_node *node, ipa_auto_call_arg_values *avals, - int *ret_size, sreal *ret_time, - sreal *ret_nonspec_time, - ipa_hints *hints) + ipa_call_estimates *estimates) { clause_t clause, nonspec_clause; 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); + ctx.estimate_size_and_time (estimates); } /* Return stack frame offset where frame of NODE is supposed to start inside diff --git a/gcc/ipa-fnsummary.h b/gcc/ipa-fnsummary.h index 020a6f0425d..ccb6b432f0b 100644 --- a/gcc/ipa-fnsummary.h +++ b/gcc/ipa-fnsummary.h @@ -287,6 +287,29 @@ public: ipa_call_summary *dst_data); }; +/* Estimated execution times, code sizes and other information about the + code executing a call described by ipa_call_context. */ + +struct ipa_call_estimates +{ + /* Estimated size needed to execute call in the given context. */ + int size; + + /* Minimal size needed for the call that is + independent on the call context + and can be used for fast estimates. */ + int min_size; + + /* Estimated time needed to execute call in the given context. */ + sreal time; + + /* Estimated time needed to execute the function when not ignoring + computations known to be constant in this context. */ + sreal nonspecialized_time; + + /* Further discovered reasons why to inline or specialize the give calls. */ + ipa_hints hints; +}; + class ipa_cached_call_context; /* This object describe a context of call. That is a summary of known @@ -305,10 +328,8 @@ public: : m_node(NULL) { } - void estimate_size_and_time (int *ret_size, int *ret_min_size, - sreal *ret_time, - sreal *ret_nonspecialized_time, - ipa_hints *ret_hints); + void estimate_size_and_time (ipa_call_estimates *estimates, + bool est_times = true, bool est_hints = true); bool equal_to (const ipa_call_context &); bool exists_p () { @@ -353,10 +374,9 @@ void ipa_dump_hints (FILE *f, ipa_hints); 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 *, - ipa_auto_call_arg_values *, - int *, sreal *, sreal *, - ipa_hints *); +void estimate_ipcp_clone_size_and_time (struct cgraph_node *node, + ipa_auto_call_arg_values *avals, + ipa_call_estimates *estimates); void ipa_merge_fn_summary_after_inlining (struct cgraph_edge *edge); void ipa_update_overall_fn_summary (struct cgraph_node *node, bool reset = true); void compute_fn_summary (struct cgraph_node *, bool); diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c index b7af77f7b9b..acbf82e84d9 100644 --- a/gcc/ipa-inline-analysis.c +++ b/gcc/ipa-inline-analysis.c @@ -208,16 +208,12 @@ do_estimate_edge_time (struct cgraph_edge *edge, sreal *ret_nonspec_time) && !opt_for_fn (callee->decl, flag_profile_partial_training) && !callee->count.ipa_p ()) { - sreal chk_time, chk_nonspec_time; - int chk_size, chk_min_size; - - ipa_hints chk_hints; - ctx.estimate_size_and_time (&chk_size, &chk_min_size, - &chk_time, &chk_nonspec_time, - &chk_hints); - gcc_assert (chk_size == size && chk_time == time - && chk_nonspec_time == nonspec_time - && chk_hints == hints); + ipa_call_estimates chk_estimates; + ctx.estimate_size_and_time (&chk_estimates); + gcc_assert (chk_estimates.size == size + && chk_estimates.time == time + && chk_estimates.nonspecialized_time == nonspec_time + && chk_estimates.hints == hints); } } else @@ -227,18 +223,28 @@ do_estimate_edge_time (struct cgraph_edge *edge, sreal *ret_nonspec_time) else node_context_cache_clear++; e->entry.ctx.release (); - ctx.estimate_size_and_time (&size, &min_size, - &time, &nonspec_time, &hints); + ipa_call_estimates estimates; + ctx.estimate_size_and_time (&estimates); + size = estimates.size; e->entry.size = size; + time = estimates.time; e->entry.time = time; + nonspec_time = estimates.nonspecialized_time; e->entry.nonspec_time = nonspec_time; + hints = estimates.hints; e->entry.hints = hints; e->entry.ctx.duplicate_from (ctx); } } else - ctx.estimate_size_and_time (&size, &min_size, - &time, &nonspec_time, &hints); + { + ipa_call_estimates estimates; + ctx.estimate_size_and_time (&estimates); + size = estimates.size; + time = estimates.time; + nonspec_time = estimates.nonspecialized_time; + hints = estimates.hints; + } /* When we have profile feedback, we can quite safely identify hot edges and for those we disable size limits. Don't do that when @@ -321,8 +327,9 @@ do_estimate_edge_size (struct cgraph_edge *edge) 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); - return size; + ipa_call_estimates estimates; + ctx.estimate_size_and_time (&estimates, false, false); + return estimates.size; } @@ -332,7 +339,6 @@ do_estimate_edge_size (struct cgraph_edge *edge) ipa_hints do_estimate_edge_hints (struct cgraph_edge *edge) { - ipa_hints hints; struct cgraph_node *callee; clause_t clause, nonspec_clause; @@ -341,7 +347,7 @@ do_estimate_edge_hints (struct cgraph_edge *edge) if (edge_growth_cache != NULL) { do_estimate_edge_time (edge); - hints = edge_growth_cache->get (edge)->hints; + ipa_hints hints = edge_growth_cache->get (edge)->hints; gcc_checking_assert (hints); return hints - 1; } @@ -354,8 +360,9 @@ do_estimate_edge_hints (struct cgraph_edge *edge) 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); - hints |= simple_edge_hints (edge); + ipa_call_estimates estimates; + ctx.estimate_size_and_time (&estimates, false, true); + ipa_hints hints = estimates.hints | simple_edge_hints (edge); return hints; } -- 2.30.2