aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/doc/invoke.texi6
-rw-r--r--gcc/ipa-inline.c143
-rw-r--r--gcc/params.def8
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/inline-3.c29
6 files changed, 133 insertions, 66 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e45090d..fa3be0d 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,14 @@
2009-05-15 Jan Hubicka <jh@suse.cz>
+ * doc/invoke.texi (max-early-inliner-iterations): New flag.
+ * ipa-inline.c (enum inlining_mode): New INLINE_SIZE_NORECURSIVE.
+ (try_inline): Fix return value.
+ (cgraph_decide_inlining_incrementally): Honor new value.
+ (cgraph_early_inlining): Handle indirect inlining.
+ * params.def (PARAM_EARLY_INLINER_MAX_ITERATIONS): New.
+
+2009-05-15 Jan Hubicka <jh@suse.cz>
+
* cgraph.h (struct cgraph_node): Add finalized_by_frotnend flag.
* cgraphunit.c (cgraph_finalize_function): Set it.
(cgraph_expand_function): Use it.
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index d22d1da..89d9b69 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -7485,6 +7485,12 @@ whose probability exceeds given threshold (in percents). The default value is
Specify growth that early inliner can make. In effect it increases amount of
inlining for code having large abstraction penalty. The default value is 12.
+@item max-early-inliner-iterations
+@itemx max-early-inliner-iterations
+Limit of iterations of early inliner. This basically bounds number of nested
+indirect calls early inliner can resolve. Deeper chains are still handled by
+late inlining.
+
@item min-vect-loop-bound
The minimum number of iterations under which a loop will not get vectorized
when @option{-ftree-vectorize} is used. The number of iterations after
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 99640bf..c8cb498 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -152,6 +152,7 @@ along with GCC; see the file COPYING3. If not see
enum inlining_mode {
INLINE_NONE = 0,
INLINE_ALWAYS_INLINE,
+ INLINE_SIZE_NORECURSIVE,
INLINE_SIZE,
INLINE_ALL
};
@@ -1269,6 +1270,7 @@ try_inline (struct cgraph_edge *e, enum inlining_mode mode, int depth)
struct cgraph_node *callee = e->callee;
enum inlining_mode callee_mode = (enum inlining_mode) (size_t) callee->aux;
bool always_inline = e->callee->local.disregard_inline_limits;
+ bool inlined = false;
/* We've hit cycle? */
if (callee_mode)
@@ -1323,9 +1325,10 @@ try_inline (struct cgraph_edge *e, enum inlining_mode mode, int depth)
if (mode == INLINE_ALL || always_inline)
cgraph_decide_inlining_incrementally (e->callee, mode, depth + 1);
+ inlined = true;
}
callee->aux = (void *)(size_t) callee_mode;
- return true;
+ return inlined;
}
/* Decide on the inlining. We do so in the topological order to avoid
@@ -1348,7 +1351,7 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node,
old_mode = (enum inlining_mode) (size_t)node->aux;
- if (mode != INLINE_ALWAYS_INLINE
+ if (mode != INLINE_ALWAYS_INLINE && mode != INLINE_SIZE_NORECURSIVE
&& lookup_attribute ("flatten", DECL_ATTRIBUTES (node->decl)) != NULL)
{
if (dump_file)
@@ -1362,69 +1365,70 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node,
node->aux = (void *)(size_t) mode;
/* First of all look for always inline functions. */
- for (e = node->callees; e; e = e->next_callee)
- {
- if (!e->callee->local.disregard_inline_limits
- && (mode != INLINE_ALL || !e->callee->local.inlinable))
- continue;
- if (gimple_call_cannot_inline_p (e->call_stmt))
- continue;
- /* When the edge is already inlined, we just need to recurse into
- it in order to fully flatten the leaves. */
- if (!e->inline_failed && mode == INLINE_ALL)
- {
- inlined |= try_inline (e, mode, depth);
- continue;
- }
- if (dump_file)
- {
- indent_to (dump_file, depth);
- fprintf (dump_file,
- "Considering to always inline inline candidate %s.\n",
- cgraph_node_name (e->callee));
- }
- if (cgraph_recursive_inlining_p (node, e->callee, &e->inline_failed))
- {
- if (dump_file)
- {
- indent_to (dump_file, depth);
- fprintf (dump_file, "Not inlining: recursive call.\n");
- }
- continue;
- }
- if (!tree_can_inline_p (node->decl, e->callee->decl))
- {
- gimple_call_set_cannot_inline (e->call_stmt, true);
- if (dump_file)
- {
- indent_to (dump_file, depth);
- fprintf (dump_file,
- "Not inlining: Target specific option mismatch.\n");
- }
- continue;
- }
- if (gimple_in_ssa_p (DECL_STRUCT_FUNCTION (node->decl))
- != gimple_in_ssa_p (DECL_STRUCT_FUNCTION (e->callee->decl)))
- {
- if (dump_file)
- {
- indent_to (dump_file, depth);
- fprintf (dump_file, "Not inlining: SSA form does not match.\n");
- }
+ if (mode != INLINE_SIZE_NORECURSIVE)
+ for (e = node->callees; e; e = e->next_callee)
+ {
+ if (!e->callee->local.disregard_inline_limits
+ && (mode != INLINE_ALL || !e->callee->local.inlinable))
continue;
- }
- if (!e->callee->analyzed && !e->callee->inline_decl)
- {
- if (dump_file)
- {
- indent_to (dump_file, depth);
- fprintf (dump_file,
- "Not inlining: Function body no longer available.\n");
- }
+ if (gimple_call_cannot_inline_p (e->call_stmt))
continue;
- }
- inlined |= try_inline (e, mode, depth);
- }
+ /* When the edge is already inlined, we just need to recurse into
+ it in order to fully flatten the leaves. */
+ if (!e->inline_failed && mode == INLINE_ALL)
+ {
+ inlined |= try_inline (e, mode, depth);
+ continue;
+ }
+ if (dump_file)
+ {
+ indent_to (dump_file, depth);
+ fprintf (dump_file,
+ "Considering to always inline inline candidate %s.\n",
+ cgraph_node_name (e->callee));
+ }
+ if (cgraph_recursive_inlining_p (node, e->callee, &e->inline_failed))
+ {
+ if (dump_file)
+ {
+ indent_to (dump_file, depth);
+ fprintf (dump_file, "Not inlining: recursive call.\n");
+ }
+ continue;
+ }
+ if (!tree_can_inline_p (node->decl, e->callee->decl))
+ {
+ gimple_call_set_cannot_inline (e->call_stmt, true);
+ if (dump_file)
+ {
+ indent_to (dump_file, depth);
+ fprintf (dump_file,
+ "Not inlining: Target specific option mismatch.\n");
+ }
+ continue;
+ }
+ if (gimple_in_ssa_p (DECL_STRUCT_FUNCTION (node->decl))
+ != gimple_in_ssa_p (DECL_STRUCT_FUNCTION (e->callee->decl)))
+ {
+ if (dump_file)
+ {
+ indent_to (dump_file, depth);
+ fprintf (dump_file, "Not inlining: SSA form does not match.\n");
+ }
+ continue;
+ }
+ if (!e->callee->analyzed && !e->callee->inline_decl)
+ {
+ if (dump_file)
+ {
+ indent_to (dump_file, depth);
+ fprintf (dump_file,
+ "Not inlining: Function body no longer available.\n");
+ }
+ continue;
+ }
+ inlined |= try_inline (e, mode, depth);
+ }
/* Now do the automatic inlining. */
if (mode != INLINE_ALL && mode != INLINE_ALWAYS_INLINE)
@@ -1459,7 +1463,7 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node,
/* 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 || mode == INLINE_SIZE_NORECURSIVE)
|| (!flag_inline_functions
&& !DECL_DECLARED_INLINE_P (e->callee->decl)))
&& (cgraph_estimate_size_after_inlining (1, e->caller, e->callee)
@@ -1531,15 +1535,22 @@ cgraph_early_inlining (void)
{
struct cgraph_node *node = cgraph_node (current_function_decl);
unsigned int todo = 0;
+ int iterations = 0;
if (sorrycount || errorcount)
return 0;
- if (cgraph_decide_inlining_incrementally (node, INLINE_SIZE, 0))
+ while (cgraph_decide_inlining_incrementally (node,
+ iterations
+ ? INLINE_SIZE_NORECURSIVE : INLINE_SIZE, 0)
+ && iterations < PARAM_VALUE (PARAM_EARLY_INLINER_MAX_ITERATIONS))
{
timevar_push (TV_INTEGRATION);
- todo = optimize_inline_calls (current_function_decl);
+ todo |= optimize_inline_calls (current_function_decl);
+ iterations++;
timevar_pop (TV_INTEGRATION);
}
+ if (dump_file)
+ fprintf (dump_file, "Iterations: %i\n", iterations);
cfun->always_inline_functions_inlined = true;
return todo;
}
diff --git a/gcc/params.def b/gcc/params.def
index 684de5e..9b5db87 100644
--- a/gcc/params.def
+++ b/gcc/params.def
@@ -139,6 +139,14 @@ DEFPARAM (PARAM_MIN_INLINE_RECURSIVE_PROBABILITY,
"Inline recursively only when the probability of call being executed exceeds the parameter",
10, 0, 0)
+/* Limit of iterations of early inliner. This basically bounds number of
+ nested indirect calls early inliner can resolve. Deeper chains are still
+ handled by late inlining. */
+DEFPARAM (PARAM_EARLY_INLINER_MAX_ITERATIONS,
+ "max-early-inliner-iterations",
+ "The maximum number of nested indirect inlining performed by early inliner",
+ 10, 0, 0)
+
/* Limit the number of expansions created by the variable expansion
optimization to avoid register pressure. */
DEFPARAM (PARAM_MAX_VARIABLE_EXPANSIONS,
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c46f139..f1ff5d5 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,9 @@
2009-05-15 Jan Hubicka <jh@suse.cz>
+ * testsuite/gcc.dg/tree-ssa/inline-3.c: New testcase
+
+2009-05-15 Jan Hubicka <jh@suse.cz>
+
* gcc.target/i386/align-main-1.c (check): Mark noinline.
* gcc.target/i386/align-main-2.c (check): Mark noinline.
* gcc.dg/ipa/ipa-4.c: Disable early inlining.
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/inline-3.c b/gcc/testsuite/gcc.dg/tree-ssa/inline-3.c
new file mode 100644
index 0000000..5132aa3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/inline-3.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-einline2" } */
+extern void inlined ();
+void inline_me_too (void);
+void inline_through_me (void (*ptr)(void));
+void
+inline_me (void)
+{
+ inlined();
+}
+
+void main(void)
+{
+ inline_through_me (inline_me);
+ inline_through_me (inline_me_too);
+}
+void
+inline_through_me (void (*ptr)(void))
+{
+ ptr();
+}
+
+void
+inline_me_too (void)
+{
+ inlined();
+}
+/* { dg-final { scan-tree-dump-times "Inlining inline_me " 1 "einline2"} } */
+/* { dg-final { scan-tree-dump-times "Inlining inline_me_too " 1 "einline2"} } */