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;
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
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
|| (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)
{
"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))
{
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;
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;
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)
if (time > nonspecialized_time)
time = nonspecialized_time;
- if (ret_hints)
+ if (est_hints)
{
if (info->loop_iterations
&& !info->loop_iterations->evaluate (m_possible_truths))
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;
}
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
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
: 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 ()
{
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);
&& !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
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
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;
}
ipa_hints
do_estimate_edge_hints (struct cgraph_edge *edge)
{
- ipa_hints hints;
struct cgraph_node *callee;
clause_t clause, nonspec_clause;
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;
}
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;
}