if (dump_file)
{
fprintf (dump_file, " not inlinable: %s/%i -> %s/%i, %s\n",
- cgraph_node_name (e->caller), e->caller->uid,
- cgraph_node_name (e->callee), e->callee->uid,
+ xstrdup (cgraph_node_name (e->caller)), e->caller->uid,
+ xstrdup (cgraph_node_name (e->callee)), e->callee->uid,
cgraph_inline_failed_string (e->inline_failed));
}
}
e->inline_failed = CIF_EH_PERSONALITY;
inlinable = false;
}
+ /* TM pure functions should not be inlined into non-TM_pure
+ functions. */
+ else if (is_tm_pure (callee->decl)
+ && !is_tm_pure (e->caller->decl))
+ {
+ e->inline_failed = CIF_UNSPECIFIED;
+ inlinable = false;
+ }
/* Don't inline if the callee can throw non-call exceptions but the
caller cannot.
FIXME: this is obviously wrong for LTO where STRUCT_FUNCTION is missing.
}
}
- /* Be sure that the cannot_inline_p flag is up to date. */
- gcc_checking_assert (!e->call_stmt
- || (gimple_call_cannot_inline_p (e->call_stmt)
- == e->call_stmt_cannot_inline_p)
- /* In -flto-partition=none mode we really keep things out of
- sync because call_stmt_cannot_inline_p is set at cgraph
- merging when function bodies are not there yet. */
- || (in_lto_p && !gimple_call_cannot_inline_p (e->call_stmt)));
if (!inlinable && report)
report_inline_failed_reason (e);
return inlinable;
if (dump_file)
fprintf (dump_file, " will not early inline: %s/%i->%s/%i, "
"call is cold and code would grow by %i\n",
- cgraph_node_name (e->caller), e->caller->uid,
- cgraph_node_name (callee), callee->uid,
+ xstrdup (cgraph_node_name (e->caller)), e->caller->uid,
+ xstrdup (cgraph_node_name (callee)), callee->uid,
growth);
want_inline = false;
}
if (dump_file)
fprintf (dump_file, " will not early inline: %s/%i->%s/%i, "
"callee is not leaf and code would grow by %i\n",
- cgraph_node_name (e->caller), e->caller->uid,
- cgraph_node_name (callee), callee->uid,
+ xstrdup (cgraph_node_name (e->caller)), e->caller->uid,
+ xstrdup (cgraph_node_name (callee)), callee->uid,
growth);
want_inline = false;
}
if (dump_file)
fprintf (dump_file, " will not early inline: %s/%i->%s/%i, "
"growth %i exceeds --param early-inlining-insns\n",
- cgraph_node_name (e->caller), e->caller->uid,
- cgraph_node_name (callee), callee->uid,
+ xstrdup (cgraph_node_name (e->caller)), e->caller->uid,
+ xstrdup (cgraph_node_name (callee)), callee->uid,
growth);
want_inline = false;
}
e->inline_failed = CIF_MAX_INLINE_INSNS_SINGLE_LIMIT;
want_inline = false;
}
- else if (!DECL_DECLARED_INLINE_P (callee->decl)
- && !flag_inline_functions)
- {
- e->inline_failed = CIF_NOT_DECLARED_INLINED;
- want_inline = false;
- }
- else if (!DECL_DECLARED_INLINE_P (callee->decl)
- && growth >= MAX_INLINE_INSNS_AUTO)
- {
- e->inline_failed = CIF_MAX_INLINE_INSNS_AUTO_LIMIT;
- want_inline = false;
- }
- /* If call is cold, do not inline when function body would grow.
- Still inline when the overall unit size will shrink because the offline
- copy of function being eliminated.
+ /* Before giving up based on fact that caller size will grow, allow
+ functions that are called few times and eliminating the offline
+ copy will lead to overall code size reduction.
+ Not all of these will be handled by subsequent inlining of functions
+ called once: in particular weak functions are not handled or funcitons
+ that inline to multiple calls but a lot of bodies is optimized out.
+ Finally we want to inline earlier to allow inlining of callbacks.
This is slightly wrong on aggressive side: it is entirely possible
that function is called many times with a context where inlining
first, this situation is not a problem at all: after inlining all
"good" calls, we will realize that keeping the function around is
better. */
- else if (!cgraph_maybe_hot_edge_p (e)
- && (DECL_EXTERNAL (callee->decl)
-
- /* Unlike for functions called once, we play unsafe with
- COMDATs. We can allow that since we know functions
- in consideration are small (and thus risk is small) and
- moreover grow estimates already accounts that COMDAT
- functions may or may not disappear when eliminated from
- current unit. With good probability making aggressive
- choice in all units is going to make overall program
- smaller.
-
- Consequently we ask cgraph_can_remove_if_no_direct_calls_p
- instead of
- cgraph_will_be_removed_from_program_if_no_direct_calls */
-
- || !cgraph_can_remove_if_no_direct_calls_p (callee)
- || estimate_growth (callee) > 0))
+ else if (growth <= MAX_INLINE_INSNS_SINGLE
+ /* Unlike for functions called once, we play unsafe with
+ COMDATs. We can allow that since we know functions
+ in consideration are small (and thus risk is small) and
+ moreover grow estimates already accounts that COMDAT
+ functions may or may not disappear when eliminated from
+ current unit. With good probability making aggressive
+ choice in all units is going to make overall program
+ smaller.
+
+ Consequently we ask cgraph_can_remove_if_no_direct_calls_p
+ instead of
+ cgraph_will_be_removed_from_program_if_no_direct_calls */
+ && !DECL_EXTERNAL (callee->decl)
+ && cgraph_can_remove_if_no_direct_calls_p (callee)
+ && estimate_growth (callee) <= 0)
+ ;
+ else if (!DECL_DECLARED_INLINE_P (callee->decl)
+ && !flag_inline_functions)
+ {
+ e->inline_failed = CIF_NOT_DECLARED_INLINED;
+ want_inline = false;
+ }
+ else if (!DECL_DECLARED_INLINE_P (callee->decl)
+ && growth >= MAX_INLINE_INSNS_AUTO)
+ {
+ e->inline_failed = CIF_MAX_INLINE_INSNS_AUTO_LIMIT;
+ want_inline = false;
+ }
+ /* If call is cold, do not inline when function body would grow. */
+ else if (!cgraph_maybe_hot_edge_p (e))
{
e->inline_failed = CIF_UNLIKELY_CALL;
want_inline = false;
if (dump)
{
fprintf (dump_file, " Badness calculation for %s -> %s\n",
- cgraph_node_name (edge->caller),
- cgraph_node_name (callee));
+ xstrdup (cgraph_node_name (edge->caller)),
+ xstrdup (cgraph_node_name (callee)));
fprintf (dump_file, " size growth %i, time growth %i\n",
growth,
time_growth);
else if (flag_guess_branch_prob)
{
int div = edge->frequency * (1<<10) / CGRAPH_FREQ_MAX;
- int growth_for_all;
div = MAX (div, 1);
gcc_checking_assert (edge->frequency <= CGRAPH_FREQ_MAX);
/* Result must be integer in range 0...INT_MAX.
Set the base of fixed point calculation so we don't lose much of
precision for small bandesses (those are interesting) yet we don't
- overflow for growths that are still in interesting range. */
- badness = ((gcov_type)growth) * (1<<18);
+ overflow for growths that are still in interesting range.
+
+ Fixed point arithmetic with point at 8th bit. */
+ badness = ((gcov_type)growth) * (1<<(19+8));
badness = (badness + div / 2) / div;
/* Overall growth of inlining all calls of function matters: we want to
We might mix the valud into the fraction by taking into account
relative growth of the unit, but for now just add the number
into resulting fraction. */
- growth_for_all = estimate_growth (callee);
- badness += growth_for_all;
- if (badness > INT_MAX - 1)
- badness = INT_MAX - 1;
+ if (badness > INT_MAX / 2)
+ {
+ badness = INT_MAX / 2;
+ if (dump)
+ fprintf (dump_file, "Badness overflow\n");
+ }
if (dump)
{
fprintf (dump_file,
- " %i: guessed profile. frequency %f, overall growth %i,"
+ " %i: guessed profile. frequency %f,"
" benefit %f%%, divisor %i\n",
- (int) badness, (double)edge->frequency / CGRAPH_FREQ_BASE, growth_for_all,
+ (int) badness, (double)edge->frequency / CGRAPH_FREQ_BASE,
relative_time_benefit (callee_info, edge, time_growth) * 100 / 256.0, div);
}
}
else
{
int nest = MIN (inline_edge_summary (edge)->loop_depth, 8);
- badness = estimate_growth (callee) * 256;
+ badness = growth * 256;
/* Decrease badness if call is nested. */
if (badness > 0)
{
fprintf (dump_file,
" decreasing badness %s/%i -> %s/%i, %i to %i\n",
- cgraph_node_name (edge->caller), edge->caller->uid,
- cgraph_node_name (edge->callee), edge->callee->uid,
+ xstrdup (cgraph_node_name (edge->caller)),
+ edge->caller->uid,
+ xstrdup (cgraph_node_name (edge->callee)),
+ edge->callee->uid,
(int)n->key,
badness);
}
{
fprintf (dump_file,
" enqueuing call %s/%i -> %s/%i, badness %i\n",
- cgraph_node_name (edge->caller), edge->caller->uid,
- cgraph_node_name (edge->callee), edge->callee->uid,
+ xstrdup (cgraph_node_name (edge->caller)),
+ edge->caller->uid,
+ xstrdup (cgraph_node_name (edge->callee)),
+ edge->callee->uid,
badness);
}
edge->aux = fibheap_insert (heap, badness, edge);
struct cgraph_node *where, *callee;
int badness = fibheap_min_key (heap);
int current_badness;
+ int cached_badness;
int growth;
edge = (struct cgraph_edge *) fibheap_extract_min (heap);
if (!edge->inline_failed)
continue;
- /* Be sure that caches are maintained consistent. */
-#ifdef ENABLE_CHECKING
+ /* Be sure that caches are maintained consistent.
+ We can not make this ENABLE_CHECKING only because it cause differnt
+ updates of the fibheap queue. */
+ cached_badness = edge_badness (edge, false);
reset_edge_growth_cache (edge);
reset_node_growth_cache (edge->callee);
-#endif
/* When updating the edge costs, we only decrease badness in the keys.
Increases of badness are handled lazilly; when we see key with out
of date value on it, we re-insert it now. */
current_badness = edge_badness (edge, false);
+ gcc_assert (cached_badness == current_badness);
gcc_assert (current_badness >= badness);
if (current_badness != badness)
{
/* We inlined last offline copy to the body. This might lead
to callees of function having fewer call sites and thus they
- may need updating. */
- if (callee->global.inlined_to)
+ may need updating.
+
+ FIXME: the callee size could also shrink because more information
+ is propagated from caller. We don't track when this happen and
+ thus we need to recompute everything all the time. Once this is
+ solved, "|| 1" should go away. */
+ if (callee->global.inlined_to || 1)
update_all_callee_keys (heap, callee, updated_nodes);
else
update_callee_keys (heap, edge->callee, updated_nodes);
if (dump_file)
fprintf (dump_file,
"Not inlining %s into %s to avoid cycle.\n",
- cgraph_node_name (callee),
- cgraph_node_name (e->caller));
+ xstrdup (cgraph_node_name (callee)),
+ xstrdup (cgraph_node_name (e->caller)));
e->inline_failed = CIF_RECURSIVE_INLINING;
continue;
}
recursing through the original node if the node was cloned. */
if (dump_file)
fprintf (dump_file, " Inlining %s into %s.\n",
- cgraph_node_name (callee),
- cgraph_node_name (e->caller));
+ xstrdup (cgraph_node_name (callee)),
+ xstrdup (cgraph_node_name (e->caller)));
orig_callee = callee;
inline_call (e, true, NULL, NULL);
if (e->callee != orig_callee)
{
fprintf (dump_file,
"\nInlining %s size %i.\n",
- cgraph_node_name (node), inline_summary (node)->size);
+ cgraph_node_name (node),
+ inline_summary (node)->size);
fprintf (dump_file,
" Called once from %s %i insns.\n",
cgraph_node_name (node->callers->caller),
if (dump_file)
fprintf (dump_file, " Inlining %s into %s (always_inline).\n",
- cgraph_node_name (e->callee),
- cgraph_node_name (e->caller));
+ xstrdup (cgraph_node_name (e->callee)),
+ xstrdup (cgraph_node_name (e->caller)));
inline_call (e, true, NULL, NULL);
inlined = true;
}
if (dump_file)
fprintf (dump_file, " Inlining %s into %s.\n",
- cgraph_node_name (callee),
- cgraph_node_name (e->caller));
+ xstrdup (cgraph_node_name (callee)),
+ xstrdup (cgraph_node_name (e->caller)));
inline_call (e, true, NULL, NULL);
inlined = true;
}
= estimate_num_insns (edge->call_stmt, &eni_size_weights);
es->call_stmt_time
= estimate_num_insns (edge->call_stmt, &eni_time_weights);
+ if (edge->callee->decl
+ && !gimple_check_call_matching_types (edge->call_stmt,
+ edge->callee->decl))
+ edge->call_stmt_cannot_inline_p = true;
}
timevar_pop (TV_INTEGRATION);
iterations++;