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:
parent
7d2cb2755a
commit
1e7fdc02cb
4 changed files with 105 additions and 83 deletions
45
gcc/ipa-cp.c
45
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))
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue