> 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 <mjam...@suse.cz>
>
> * 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.
OK,
Honza
> ---
> 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 4ef7d2570e9..6082f34d63f 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.28.0
>