invoke.texi (max-early-inliner-iterations): New flag.
* 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. * testsuite/gcc.dg/tree-ssa/inline-3.c: New testcase From-SVN: r147587
This commit is contained in:
parent
d88e5c3725
commit
796bda2238
6 changed files with 133 additions and 66 deletions
|
@ -1,3 +1,12 @@
|
|||
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.
|
||||
|
|
|
@ -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
|
||||
|
|
143
gcc/ipa-inline.c
143
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);
|
||||
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 (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");
|
||||
}
|
||||
if (gimple_call_cannot_inline_p (e->call_stmt))
|
||||
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);
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
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.
|
||||
|
|
29
gcc/testsuite/gcc.dg/tree-ssa/inline-3.c
Normal file
29
gcc/testsuite/gcc.dg/tree-ssa/inline-3.c
Normal file
|
@ -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"} } */
|
Loading…
Add table
Reference in a new issue