void
cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate, bool update_original)
{
+ HOST_WIDE_INT peak;
if (duplicate)
{
/* We may eliminate the need for out-of-line copy to be output.
e->callee->global.inlined_to = e->caller->global.inlined_to;
else
e->callee->global.inlined_to = e->caller;
+ e->callee->global.stack_frame_offset
+ = e->caller->global.stack_frame_offset + e->caller->local.estimated_self_stack_size;
+ peak = e->callee->global.stack_frame_offset + e->callee->local.estimated_self_stack_size;
+ if (e->callee->global.inlined_to->global.estimated_stack_size < peak)
+ e->callee->global.inlined_to->global.estimated_stack_size = peak;
/* Recursively clone all bodies. */
for (e = e->callee->callees; e; e = e->next_callee)
}
/* Return false when inlining WHAT into TO is not good idea
- as it would cause too large growth of function bodies. */
+ as it would cause too large growth of function bodies.
+ When ONE_ONLY is true, assume that only one call site is going
+ to be inlined, otherwise figure out how many call sites in
+ TO calls WHAT and verify that all can be inlined.
+ */
static bool
cgraph_check_inline_limits (struct cgraph_node *to, struct cgraph_node *what,
- const char **reason)
+ const char **reason, bool one_only)
{
int times = 0;
struct cgraph_edge *e;
int newsize;
int limit;
+ HOST_WIDE_INT stack_size_limit, inlined_stack;
- for (e = to->callees; e; e = e->next_callee)
- if (e->callee == what)
- times++;
+ if (one_only)
+ times = 1;
+ else
+ for (e = to->callees; e; e = e->next_callee)
+ if (e->callee == what)
+ times++;
if (to->global.inlined_to)
to = to->global.inlined_to;
*reason = N_("--param large-function-growth limit reached");
return false;
}
+
+ stack_size_limit = to->local.estimated_self_stack_size;
+
+ stack_size_limit += stack_size_limit * PARAM_VALUE (PARAM_STACK_FRAME_GROWTH) / 100;
+
+ inlined_stack = (to->global.stack_frame_offset
+ + to->local.estimated_self_stack_size
+ + what->global.estimated_stack_size);
+ if (inlined_stack > stack_size_limit
+ && inlined_stack > PARAM_VALUE (PARAM_LARGE_STACK_FRAME))
+ {
+ if (reason)
+ *reason = N_("--param large-stack-frame-growth limit reached");
+ return false;
+ }
return true;
}
node->aux = 0;
}
-/* Leafify the cgraph node. We have to be careful in recursing
+/* Flatten the cgraph node. We have to be careful in recursing
as to not run endlessly in circles of the callgraph.
We do so by using a hashtab of cycle entering nodes as generated
by cgraph_find_cycles. */
{
struct cgraph_node *callee;
if (!cgraph_check_inline_limits (edge->caller, edge->callee,
- &edge->inline_failed))
+ &edge->inline_failed, true))
{
if (dump_file)
fprintf (dump_file, " Not inlining into %s:%s.\n",
int old_insns = 0;
int i;
- timevar_push (TV_INLINE_HEURISTICS);
max_count = 0;
for (node = cgraph_nodes; node; node = node->next)
if (node->analyzed && (node->needed || node->reachable))
htab_t cycles;
if (dump_file)
fprintf (dump_file,
- "Leafifying %s\n", cgraph_node_name (node));
+ "Flattening %s\n", cgraph_node_name (node));
cycles = htab_create (7, htab_hash_pointer, htab_eq_pointer, NULL);
cgraph_find_cycles (node, cycles);
cgraph_flatten_node (node, cycles);
&& node->local.inlinable && node->callers->inline_failed
&& !DECL_EXTERNAL (node->decl) && !DECL_COMDAT (node->decl))
{
- bool ok = true;
- struct cgraph_node *node1;
-
- /* Verify that we won't duplicate the caller. */
- for (node1 = node->callers->caller;
- node1->callers && !node1->callers->inline_failed
- && ok; node1 = node1->callers->caller)
- if (node1->callers->next_caller || node1->needed)
- ok = false;
- if (ok)
+ if (dump_file)
+ {
+ fprintf (dump_file,
+ "\nConsidering %s %i insns.\n",
+ cgraph_node_name (node), node->global.insns);
+ fprintf (dump_file,
+ " Called once from %s %i insns.\n",
+ cgraph_node_name (node->callers->caller),
+ node->callers->caller->global.insns);
+ }
+
+ old_insns = overall_insns;
+
+ if (cgraph_check_inline_limits (node->callers->caller, node,
+ NULL, false))
+ {
+ cgraph_mark_inline (node->callers);
+ if (dump_file)
+ fprintf (dump_file,
+ " Inlined into %s which now has %i insns"
+ " for a net change of %+i insns.\n",
+ cgraph_node_name (node->callers->caller),
+ node->callers->caller->global.insns,
+ overall_insns - old_insns);
+ }
+ else
{
if (dump_file)
- {
- fprintf (dump_file,
- "\nConsidering %s %i insns.\n",
- cgraph_node_name (node), node->global.insns);
- fprintf (dump_file,
- " Called once from %s %i insns.\n",
- cgraph_node_name (node->callers->caller),
- node->callers->caller->global.insns);
- }
-
- old_insns = overall_insns;
-
- if (cgraph_check_inline_limits (node->callers->caller, node,
- NULL))
- {
- cgraph_mark_inline (node->callers);
- if (dump_file)
- fprintf (dump_file,
- " Inlined into %s which now has %i insns"
- " for a net change of %+i insns.\n",
- cgraph_node_name (node->callers->caller),
- node->callers->caller->global.insns,
- overall_insns - old_insns);
- }
- else
- {
- if (dump_file)
- fprintf (dump_file,
- " Inline limit reached, not inlined.\n");
- }
+ fprintf (dump_file,
+ " Inline limit reached, not inlined.\n");
}
}
}
ncalls_inlined, nfunctions_inlined, initial_insns,
overall_insns);
free (order);
- timevar_pop (TV_INLINE_HEURISTICS);
return 0;
}
&& (!early
|| (cgraph_estimate_size_after_inlining (1, e->caller, e->callee)
<= e->caller->global.insns))
- && cgraph_check_inline_limits (node, e->callee, &e->inline_failed)
+ && cgraph_check_inline_limits (node, e->callee, &e->inline_failed,
+ false)
&& (DECL_SAVED_TREE (e->callee->decl) || e->callee->inline_decl))
{
if (cgraph_default_inline_p (e->callee, &failed_reason))
}
if (early && inlined)
{
+ timevar_push (TV_INTEGRATION);
push_cfun (DECL_STRUCT_FUNCTION (node->decl));
tree_register_cfg_hooks ();
current_function_decl = node->decl;
node->local.self_insns = node->global.insns;
current_function_decl = NULL;
pop_cfun ();
+ timevar_pop (TV_INTEGRATION);
}
return inlined;
}
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- TV_INTEGRATION, /* tv_id */
+ TV_INLINE_HEURISTICS, /* tv_id */
0, /* properties_required */
PROP_cfg, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_cgraph | TODO_dump_func, /* todo_flags_finish */
+ TODO_dump_cgraph | TODO_dump_func
+ | TODO_remove_functions, /* todo_flags_finish */
0 /* letter */
};
ggc_collect ();
}
}
- cgraph_remove_unreachable_nodes (true, dump_file);
#ifdef ENABLE_CHECKING
for (node = cgraph_nodes; node; node = node->next)
gcc_assert (!node->global.inlined_to);
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- TV_INTEGRATION, /* tv_id */
+ TV_INLINE_HEURISTICS, /* tv_id */
0, /* properties_required */
PROP_cfg, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_cgraph | TODO_dump_func, /* todo_flags_finish */
+ TODO_dump_cgraph | TODO_dump_func
+ | TODO_remove_functions, /* todo_flags_finish */
0 /* letter */
};