/* Inlining decision heuristics.
- Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2007 Free Software Foundation, Inc.
Contributed by Jan Hubicka
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA. */
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
/* Inlining decision heuristics
if (n->inline_decl)
decl = n->inline_decl;
- if (!DECL_INLINE (decl))
+ if (!flag_inline_small_functions && !DECL_DECLARED_INLINE_P (decl))
{
if (reason)
- *reason = N_("function not inlinable");
+ *reason = N_("function not inline candidate");
return false;
}
int depth = 0;
int n = 0;
- if (optimize_size)
+ if (optimize_size
+ || (!flag_inline_functions && !DECL_DECLARED_INLINE_P (node->decl)))
return false;
if (DECL_DECLARED_INLINE_P (node->decl))
struct cgraph_node *where;
int growth =
cgraph_estimate_size_after_inlining (1, edge->caller, edge->callee);
+ const char *not_good = NULL;
growth -= edge->caller->global.insns;
}
}
- if ((!cgraph_maybe_hot_edge_p (edge) || optimize_size) && growth > 0)
+ if (!cgraph_maybe_hot_edge_p (edge))
+ not_good = N_("call is unlikely and code size would grow");
+ if (!flag_inline_functions
+ && !DECL_DECLARED_INLINE_P (edge->callee->decl))
+ not_good = N_("function not declared inline and code size would grow");
+ if (optimize_size)
+ not_good = N_("optimizing for size and code size would grow");
+ if (not_good && growth > 0 && cgraph_estimate_growth (edge->callee) > 0)
{
if (!cgraph_recursive_inlining_p (edge->caller, edge->callee,
&edge->inline_failed))
{
- edge->inline_failed =
- N_("call is unlikely");
+ edge->inline_failed = not_good;
if (dump_file)
fprintf (dump_file, " inline_failed:%s.\n", edge->inline_failed);
}
/* When the function body would grow and inlining the function won't
eliminate the need for offline copy of the function, don't inline.
*/
- if (mode == INLINE_SIZE
+ if ((mode == INLINE_SIZE
+ || (!flag_inline_functions
+ && !DECL_DECLARED_INLINE_P (e->callee->decl)))
&& (cgraph_estimate_size_after_inlining (1, e->caller, e->callee)
> e->caller->global.insns)
&& cgraph_estimate_growth (e->callee) > 0)
return flag_inline_trees;
}
-struct tree_opt_pass pass_ipa_inline =
-{
- "inline", /* name */
- cgraph_gate_inlining, /* gate */
- cgraph_decide_inlining, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_INLINE_HEURISTICS, /* tv_id */
- 0, /* properties_required */
- PROP_cfg, /* properties_provided */
- 0, /* properties_destroyed */
- TODO_remove_functions, /* todo_flags_finish */
- TODO_dump_cgraph | TODO_dump_func
- | TODO_remove_functions, /* todo_flags_finish */
- 0 /* letter */
-};
-
/* Because inlining might remove no-longer reachable nodes, we need to
keep the array visible to garbage collector to avoid reading collected
out nodes. */
return flag_inline_trees && flag_early_inlining;
}
-struct tree_opt_pass pass_early_inline =
+struct gimple_opt_pass pass_early_inline =
{
+ {
+ GIMPLE_PASS,
"einline", /* name */
cgraph_gate_early_inlining, /* gate */
cgraph_early_inlining, /* execute */
PROP_cfg, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_func, /* todo_flags_finish */
- 0 /* letter */
+ TODO_dump_func /* todo_flags_finish */
+ }
};
/* When inlining shall be performed. */
/* IPA pass wrapper for early inlining pass. We need to run early inlining
before tree profiling so we have stand alone IPA pass for doing so. */
-struct tree_opt_pass pass_ipa_early_inline =
+struct simple_ipa_opt_pass pass_ipa_early_inline =
{
+ {
+ SIMPLE_IPA_PASS,
"einline_ipa", /* name */
cgraph_gate_ipa_early_inlining, /* gate */
NULL, /* execute */
PROP_cfg, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_dump_cgraph, /* todo_flags_finish */
- 0 /* letter */
+ TODO_dump_cgraph /* todo_flags_finish */
+ }
};
/* Compute parameters of functions used by inliner. */
node->local.inlinable = tree_inlinable_function_p (current_function_decl);
node->local.self_insns = estimate_num_insns (current_function_decl,
&eni_inlining_weights);
- if (node->local.inlinable)
+ if (node->local.inlinable && !node->local.disregard_inline_limits)
node->local.disregard_inline_limits
- = lang_hooks.tree_inlining.disregard_inline_limits (current_function_decl);
+ = DECL_DISREGARD_INLINE_LIMITS (current_function_decl);
if (flag_really_no_inline && !node->local.disregard_inline_limits)
node->local.inlinable = 0;
/* Inlining characteristics are maintained by the cgraph_mark_inline. */
return flag_inline_trees;
}
-struct tree_opt_pass pass_inline_parameters =
+struct gimple_opt_pass pass_inline_parameters =
{
+ {
+ GIMPLE_PASS,
NULL, /* name */
gate_inline_passes, /* gate */
compute_inline_parameters, /* execute */
PROP_cfg, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- 0, /* todo_flags_finish */
- 0 /* letter */
+ 0 /* todo_flags_finish */
+ }
};
-/* Apply inline plan to the function. */
+/* Note function body size. */
+static void
+inline_generate_summary (struct cgraph_node *node ATTRIBUTE_UNUSED)
+{
+ compute_inline_parameters ();
+ return;
+}
+
+/* Apply inline plan to function. */
static unsigned int
-apply_inline (void)
+inline_transform (struct cgraph_node *node)
{
unsigned int todo = 0;
struct cgraph_edge *e;
- struct cgraph_node *node = cgraph_node (current_function_decl);
-
- /* Even when not optimizing, ensure that always_inline functions get inlined.
- */
- if (!optimize)
- cgraph_decide_inlining_incrementally (node, INLINE_SPEED, 0);
/* We might need the body of this function so that we can expand
it inline somewhere else. */
todo = optimize_inline_calls (current_function_decl);
timevar_pop (TV_INTEGRATION);
}
+ return todo | execute_fixup_cfg ();
+}
+
+struct ipa_opt_pass pass_ipa_inline =
+{
+ {
+ IPA_PASS,
+ "inline", /* name */
+ cgraph_gate_inlining, /* gate */
+ cgraph_decide_inlining, /* execute */
+ NULL, /* sub */
+ NULL, /* next */
+ 0, /* static_pass_number */
+ TV_INLINE_HEURISTICS, /* tv_id */
+ 0, /* properties_required */
+ PROP_cfg, /* properties_provided */
+ 0, /* properties_destroyed */
+ TODO_remove_functions, /* todo_flags_finish */
+ TODO_dump_cgraph | TODO_dump_func
+ | TODO_remove_functions /* todo_flags_finish */
+ },
+ inline_generate_summary, /* function_generate_summary */
+ NULL, /* variable_generate_summary */
+ NULL, /* function_write_summary */
+ NULL, /* variable_write_summary */
+ NULL, /* function_read_summary */
+ NULL, /* variable_read_summary */
+ 0, /* TODOs */
+ inline_transform, /* function_transform */
+ NULL, /* variable_transform */
+};
+
+
+/* When inlining shall be performed. */
+static bool
+cgraph_gate_O0_always_inline (void)
+{
+ return !flag_unit_at_a_time || !flag_inline_trees;
+}
+
+static unsigned int
+cgraph_O0_always_inline (void)
+{
+ struct cgraph_node *node = cgraph_node (current_function_decl);
+ unsigned int todo = 0;
+ bool inlined;
+
+ if (sorrycount || errorcount)
+ return 0;
+ inlined = cgraph_decide_inlining_incrementally (node, INLINE_SPEED, 0);
+ /* We might need the body of this function so that we can expand
+ it inline somewhere else. */
+ if (cgraph_preserve_function_body_p (current_function_decl))
+ save_inline_function_body (node);
+ if (inlined || warn_inline)
+ {
+ timevar_push (TV_INTEGRATION);
+ todo = optimize_inline_calls (current_function_decl);
+ timevar_pop (TV_INTEGRATION);
+ }
/* In non-unit-at-a-time we must mark all referenced functions as needed. */
if (!flag_unit_at_a_time)
{
return todo | execute_fixup_cfg ();
}
-struct tree_opt_pass pass_apply_inline =
+struct gimple_opt_pass pass_O0_always_inline =
{
- "apply_inline", /* name */
- NULL, /* gate */
- apply_inline, /* execute */
+ {
+ GIMPLE_PASS,
+ "always_inline", /* name */
+ cgraph_gate_O0_always_inline, /* gate */
+ cgraph_O0_always_inline, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func | TODO_verify_flow
- | TODO_verify_stmts, /* todo_flags_finish */
- 0 /* letter */
+ | TODO_verify_stmts /* todo_flags_finish */
+ }
};
#include "gt-ipa-inline.h"