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  <mjambor@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.
This commit is contained in:
Martin Jambor 2020-10-02 18:41:34 +02:00
parent 7d2cb2755a
commit 1e7fdc02cb
4 changed files with 105 additions and 83 deletions

View file

@ -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))
{

View file

@ -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

View file

@ -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);

View file

@ -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;
}