cgraphbuild.c: Include ipa-inline.h.

* cgraphbuild.c: Include ipa-inline.h.
	(reset_inline_failed): Use initialize_inline_failed.
	* cgraph.c: Include ipa-inline.h.
	(cgraph_create_node_1): Do not initialize estimated_growth.
	(initialize_inline_failed): More to ipa-inline-analysis.c
	(dump_cgraph_node): Do not dump inline flags.
	* cgraph.h (cgraph_local_info): Remove inlineable, versionable
	and disregard_inline_limits flags.
	(cgrpah_global_info): Remove estimated_stack_size, stack_frame_offset,
	time, size, estimated_growth.
	* ipa-cp.c (ipcp_versionable_function_p, ipcp_generate_summary): Update.
	* cgraphunit.c (cgraph_decide_is_function_needed): Use
	DECL_DISREGARD_INLINE_LIMITS.
	(cgraph_analyze_function): Do not initialize
	node->local.disregard_inline_limits.
	* lto-cgraph.c (lto_output_node, input_overwrite_node): Do not stream
	inlinable, versionable and disregard_inline_limits.
	* ipa-inline.c (cgraph_clone_inlined_nodes, cgraph_mark_inline_edge,
	cgraph_check_inline_limits, cgraph_default_inline_p, cgraph_edge_badness,
	update_caller_keys, update_callee_keys, add_new_edges_to_heap): Update.
	(cgraph_decide_inlining_of_small_function): Update; set CIF_FUNCTION_NOT_INLINABLE
	for uninlinable functions.
	(cgraph_decide_inlining, cgraph_edge_early_inlinable_p,
	cgraph_decide_inlining_incrementally): Update.
	* ipa-inline.h (inline_summary): Add inlinable, versionable, disregard_inline_limits,
	estimated_stack_size, stack_frame_offset, time, size and estimated_growth
	parameters.
	(estimate_edge_growth): Update.
	(initialize_inline_failed): Declare.
	* ipa-split.c: Include ipa-inline.h
	(execute_split_functions): Update.
	* ipa.c (cgraph_postorder): Use DECL_DISREGARD_INLINE_LIMITS.
	(cgraph_remove_unreachable_nodes): Do not clear inlinable flag.
	(record_cdtor_fn): Use DECL_DISREGARD_INLINE_LIMITS.
	* ipa-inline-analysis.c (inline_node_removal_hook): Update; set
	estimated_growth to INT_MIN.
	(inline_node_duplication_hook): Likewise.
	(dump_inline_summary): Dump new fields.
	(compute_inline_parameters): Update.
	(estimate_edge_time, estimate_time_after_inlining,
	estimate_size_after_inlining, estimate_growth, inline_read_summary,
	inline_write_summary):
	(initialize_inline_failed): Move here from cgraph.c.
	* tree-sra.c: Include ipa-inline.h.
	(ipa_sra_preliminary_function_checks): Update.
	* lto/lto.c (lto_balanced_map): Update.
	Update.
	* Makefile.in: (cgraph.o, cgraphbuild.o): Add dependency on
	ipa-inline.h

From-SVN: r172581
This commit is contained in:
Jan Hubicka 2011-04-16 11:13:08 +02:00 committed by Jan Hubicka
parent e81b856471
commit e7f2301855
16 changed files with 289 additions and 198 deletions

View File

@ -1,3 +1,53 @@
2011-04-16 Jan Hubicka <jh@suse.cz>
* cgraphbuild.c: Include ipa-inline.h.
(reset_inline_failed): Use initialize_inline_failed.
* cgraph.c: Include ipa-inline.h.
(cgraph_create_node_1): Do not initialize estimated_growth.
(initialize_inline_failed): More to ipa-inline-analysis.c
(dump_cgraph_node): Do not dump inline flags.
* cgraph.h (cgraph_local_info): Remove inlineable, versionable
and disregard_inline_limits flags.
(cgrpah_global_info): Remove estimated_stack_size, stack_frame_offset,
time, size, estimated_growth.
* ipa-cp.c (ipcp_versionable_function_p, ipcp_generate_summary): Update.
* cgraphunit.c (cgraph_decide_is_function_needed): Use
DECL_DISREGARD_INLINE_LIMITS.
(cgraph_analyze_function): Do not initialize
node->local.disregard_inline_limits.
* lto-cgraph.c (lto_output_node, input_overwrite_node): Do not stream
inlinable, versionable and disregard_inline_limits.
* ipa-inline.c (cgraph_clone_inlined_nodes, cgraph_mark_inline_edge,
cgraph_check_inline_limits, cgraph_default_inline_p, cgraph_edge_badness,
update_caller_keys, update_callee_keys, add_new_edges_to_heap): Update.
(cgraph_decide_inlining_of_small_function): Update; set CIF_FUNCTION_NOT_INLINABLE
for uninlinable functions.
(cgraph_decide_inlining, cgraph_edge_early_inlinable_p,
cgraph_decide_inlining_incrementally): Update.
* ipa-inline.h (inline_summary): Add inlinable, versionable, disregard_inline_limits,
estimated_stack_size, stack_frame_offset, time, size and estimated_growth
parameters.
(estimate_edge_growth): Update.
(initialize_inline_failed): Declare.
* ipa-split.c: Include ipa-inline.h
(execute_split_functions): Update.
* ipa.c (cgraph_postorder): Use DECL_DISREGARD_INLINE_LIMITS.
(cgraph_remove_unreachable_nodes): Do not clear inlinable flag.
(record_cdtor_fn): Use DECL_DISREGARD_INLINE_LIMITS.
* ipa-inline-analysis.c (inline_node_removal_hook): Update; set
estimated_growth to INT_MIN.
(inline_node_duplication_hook): Likewise.
(dump_inline_summary): Dump new fields.
(compute_inline_parameters): Update.
(estimate_edge_time, estimate_time_after_inlining,
estimate_size_after_inlining, estimate_growth, inline_read_summary,
inline_write_summary):
(initialize_inline_failed): Move here from cgraph.c.
* tree-sra.c: Include ipa-inline.h.
(ipa_sra_preliminary_function_checks): Update.
* Makefile.in: (cgraph.o, cgraphbuild.o): Add dependency on
ipa-inline.h
2011-04-16 Uros Bizjak <ubizjak@gmail.com> 2011-04-16 Uros Bizjak <ubizjak@gmail.com>
* config/i386/sse.md (V16): New mode iterator. * config/i386/sse.md (V16): New mode iterator.

View File

@ -2983,7 +2983,8 @@ cgraph.o : cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
langhooks.h toplev.h $(DIAGNOSTIC_CORE_H) $(FLAGS_H) $(GGC_H) $(TARGET_H) $(CGRAPH_H) \ langhooks.h toplev.h $(DIAGNOSTIC_CORE_H) $(FLAGS_H) $(GGC_H) $(TARGET_H) $(CGRAPH_H) \
gt-cgraph.h output.h intl.h $(BASIC_BLOCK_H) debug.h $(HASHTAB_H) \ gt-cgraph.h output.h intl.h $(BASIC_BLOCK_H) debug.h $(HASHTAB_H) \
$(TREE_INLINE_H) $(TREE_DUMP_H) $(TREE_FLOW_H) cif-code.def \ $(TREE_INLINE_H) $(TREE_DUMP_H) $(TREE_FLOW_H) cif-code.def \
value-prof.h $(EXCEPT_H) $(IPA_UTILS_H) $(DIAGNOSTIC_CORE_H) value-prof.h $(EXCEPT_H) $(IPA_UTILS_H) $(DIAGNOSTIC_CORE_H) \
ipa-inline.h
cgraphunit.o : cgraphunit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ cgraphunit.o : cgraphunit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) langhooks.h $(TREE_INLINE_H) toplev.h $(DIAGNOSTIC_CORE_H) $(FLAGS_H) $(GGC_H) \ $(TREE_H) langhooks.h $(TREE_INLINE_H) toplev.h $(DIAGNOSTIC_CORE_H) $(FLAGS_H) $(GGC_H) \
$(TARGET_H) $(CGRAPH_H) intl.h pointer-set.h $(FUNCTION_H) $(GIMPLE_H) \ $(TARGET_H) $(CGRAPH_H) intl.h pointer-set.h $(FUNCTION_H) $(GIMPLE_H) \
@ -2993,7 +2994,8 @@ cgraphunit.o : cgraphunit.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
tree-pretty-print.h gimple-pretty-print.h tree-pretty-print.h gimple-pretty-print.h
cgraphbuild.o : cgraphbuild.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ cgraphbuild.o : cgraphbuild.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) langhooks.h $(CGRAPH_H) intl.h pointer-set.h $(GIMPLE_H) \ $(TREE_H) langhooks.h $(CGRAPH_H) intl.h pointer-set.h $(GIMPLE_H) \
$(TREE_FLOW_H) $(TREE_PASS_H) $(IPA_UTILS_H) $(EXCEPT_H) $(TREE_FLOW_H) $(TREE_PASS_H) $(IPA_UTILS_H) $(EXCEPT_H) \
ipa-inline.h
varpool.o : varpool.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ varpool.o : varpool.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TREE_H) $(CGRAPH_H) langhooks.h $(DIAGNOSTIC_CORE_H) $(HASHTAB_H) \ $(TREE_H) $(CGRAPH_H) langhooks.h $(DIAGNOSTIC_CORE_H) $(HASHTAB_H) \
$(GGC_H) $(TIMEVAR_H) debug.h $(TARGET_H) output.h $(GIMPLE_H) \ $(GGC_H) $(TIMEVAR_H) debug.h $(TARGET_H) output.h $(GIMPLE_H) \

View File

@ -98,6 +98,7 @@ The callgraph:
#include "rtl.h" #include "rtl.h"
#include "ipa-utils.h" #include "ipa-utils.h"
#include "lto-streamer.h" #include "lto-streamer.h"
#include "ipa-inline.h"
const char * const ld_plugin_symbol_resolution_names[]= const char * const ld_plugin_symbol_resolution_names[]=
{ {
@ -476,7 +477,6 @@ cgraph_create_node_1 (void)
if (cgraph_nodes) if (cgraph_nodes)
cgraph_nodes->previous = node; cgraph_nodes->previous = node;
node->previous = NULL; node->previous = NULL;
node->global.estimated_growth = INT_MIN;
node->frequency = NODE_FREQUENCY_NORMAL; node->frequency = NODE_FREQUENCY_NORMAL;
node->count_materialization_scale = REG_BR_PROB_BASE; node->count_materialization_scale = REG_BR_PROB_BASE;
ipa_empty_ref_list (&node->ref_list); ipa_empty_ref_list (&node->ref_list);
@ -970,28 +970,6 @@ cgraph_create_edge_including_clones (struct cgraph_node *orig,
} }
} }
/* Give initial reasons why inlining would fail on EDGE. This gets either
nullified or usually overwritten by more precise reasons later. */
static void
initialize_inline_failed (struct cgraph_edge *e)
{
struct cgraph_node *callee = e->callee;
if (e->indirect_unknown_callee)
e->inline_failed = CIF_INDIRECT_UNKNOWN_CALL;
else if (!callee->analyzed)
e->inline_failed = CIF_BODY_NOT_AVAILABLE;
else if (callee->local.redefined_extern_inline)
e->inline_failed = CIF_REDEFINED_EXTERN_INLINE;
else if (!callee->local.inlinable)
e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
else if (e->call_stmt && gimple_call_cannot_inline_p (e->call_stmt))
e->inline_failed = CIF_MISMATCHED_ARGUMENTS;
else
e->inline_failed = CIF_FUNCTION_NOT_CONSIDERED;
}
/* Allocate a cgraph_edge structure and fill it with data according to the /* Allocate a cgraph_edge structure and fill it with data according to the
parameters of which only CALLEE can be NULL (when creating an indirect call parameters of which only CALLEE can be NULL (when creating an indirect call
edge). */ edge). */
@ -1899,12 +1877,6 @@ dump_cgraph_node (FILE *f, struct cgraph_node *node)
ld_plugin_symbol_resolution_names[(int)node->resolution]); ld_plugin_symbol_resolution_names[(int)node->resolution]);
if (node->local.finalized) if (node->local.finalized)
fprintf (f, " finalized"); fprintf (f, " finalized");
if (node->local.disregard_inline_limits)
fprintf (f, " always_inline");
else if (node->local.inlinable)
fprintf (f, " inlinable");
else if (node->local.versionable)
fprintf (f, " versionable");
if (node->local.redefined_extern_inline) if (node->local.redefined_extern_inline)
fprintf (f, " redefined_extern_inline"); fprintf (f, " redefined_extern_inline");
if (TREE_ASM_WRITTEN (node->decl)) if (TREE_ASM_WRITTEN (node->decl))

View File

@ -88,20 +88,10 @@ struct GTY(()) cgraph_local_info {
/* Set once it has been finalized so we consider it to be output. */ /* Set once it has been finalized so we consider it to be output. */
unsigned finalized : 1; unsigned finalized : 1;
/* False when there something makes inlining impossible (such as va_arg). */
unsigned inlinable : 1;
/* False when there something makes versioning impossible.
Currently computed and used only by ipa-cp. */
unsigned versionable : 1;
/* False when function calling convention and signature can not be changed. /* False when function calling convention and signature can not be changed.
This is the case when __builtin_apply_args is used. */ This is the case when __builtin_apply_args is used. */
unsigned can_change_signature : 1; unsigned can_change_signature : 1;
/* True when function should be inlined independently on its size. */
unsigned disregard_inline_limits : 1;
/* True when the function has been originally extern inline, but it is /* True when the function has been originally extern inline, but it is
redefined now. */ redefined now. */
unsigned redefined_extern_inline : 1; unsigned redefined_extern_inline : 1;
@ -115,21 +105,9 @@ struct GTY(()) cgraph_local_info {
once compilation is finished. Available only with -funit-at-a-time. */ once compilation is finished. Available only with -funit-at-a-time. */
struct GTY(()) cgraph_global_info { struct GTY(()) cgraph_global_info {
/* Estimated stack frame consumption by the function. */
HOST_WIDE_INT estimated_stack_size;
/* Expected offset of the stack frame of inlined function. */
HOST_WIDE_INT stack_frame_offset;
/* For inline clones this points to the function they will be /* For inline clones this points to the function they will be
inlined into. */ inlined into. */
struct cgraph_node *inlined_to; struct cgraph_node *inlined_to;
/* Estimated size of the function after inlining. */
int time;
int size;
/* Estimated growth after inlining. INT_MIN if not computed. */
int estimated_growth;
}; };
/* Information about the function that is propagated by the RTL backend. /* Information about the function that is propagated by the RTL backend.

View File

@ -33,6 +33,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pass.h" #include "tree-pass.h"
#include "ipa-utils.h" #include "ipa-utils.h"
#include "except.h" #include "except.h"
#include "ipa-inline.h"
/* Context of record_reference. */ /* Context of record_reference. */
struct record_reference_ctx struct record_reference_ctx
@ -207,16 +208,7 @@ reset_inline_failed (struct cgraph_node *node)
for (e = node->callers; e; e = e->next_caller) for (e = node->callers; e; e = e->next_caller)
{ {
e->callee->global.inlined_to = NULL; e->callee->global.inlined_to = NULL;
if (!node->analyzed) initialize_inline_failed (e);
e->inline_failed = CIF_BODY_NOT_AVAILABLE;
else if (node->local.redefined_extern_inline)
e->inline_failed = CIF_REDEFINED_EXTERN_INLINE;
else if (!node->local.inlinable)
e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
else if (e->call_stmt_cannot_inline_p)
e->inline_failed = CIF_MISMATCHED_ARGUMENTS;
else
e->inline_failed = CIF_FUNCTION_NOT_CONSIDERED;
} }
} }

View File

@ -172,7 +172,7 @@ cgraph_decide_is_function_needed (struct cgraph_node *node, tree decl)
if (flag_keep_inline_functions if (flag_keep_inline_functions
&& DECL_DECLARED_INLINE_P (decl) && DECL_DECLARED_INLINE_P (decl)
&& !DECL_EXTERNAL (decl) && !DECL_EXTERNAL (decl)
&& !lookup_attribute ("always_inline", DECL_ATTRIBUTES (decl))) && !DECL_DISREGARD_INLINE_LIMITS (decl))
return true; return true;
/* If we decided it was needed before, but at the time we didn't have /* If we decided it was needed before, but at the time we didn't have
@ -191,7 +191,7 @@ cgraph_decide_is_function_needed (struct cgraph_node *node, tree decl)
to change the behavior here. */ to change the behavior here. */
if (((TREE_PUBLIC (decl) if (((TREE_PUBLIC (decl)
|| (!optimize || (!optimize
&& !node->local.disregard_inline_limits && !DECL_DISREGARD_INLINE_LIMITS (decl)
&& !DECL_DECLARED_INLINE_P (decl) && !DECL_DECLARED_INLINE_P (decl)
&& !(DECL_CONTEXT (decl) && !(DECL_CONTEXT (decl)
&& TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL))) && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)))
@ -783,11 +783,6 @@ cgraph_analyze_function (struct cgraph_node *node)
assign_assembler_name_if_neeeded (node->decl); assign_assembler_name_if_neeeded (node->decl);
/* disregard_inline_limits affects topological order of the early optimization,
so we need to compute it ahead of rest of inline parameters. */
node->local.disregard_inline_limits
= DECL_DISREGARD_INLINE_LIMITS (node->decl);
/* Make sure to gimplify bodies only once. During analyzing a /* Make sure to gimplify bodies only once. During analyzing a
function we lower it, which will require gimplified nested function we lower it, which will require gimplified nested
functions, so we can end up here with an already gimplified functions, so we can end up here with an already gimplified

View File

@ -424,7 +424,7 @@ ipcp_versionable_function_p (struct cgraph_node *node)
/* There are a number of generic reasons functions cannot be versioned. We /* There are a number of generic reasons functions cannot be versioned. We
also cannot remove parameters if there are type attributes such as fnspec also cannot remove parameters if there are type attributes such as fnspec
present. */ present. */
if (!node->local.versionable if (!inline_summary (node)->versionable
|| TYPE_ATTRIBUTES (TREE_TYPE (node->decl))) || TYPE_ATTRIBUTES (TREE_TYPE (node->decl)))
return false; return false;
@ -1577,7 +1577,7 @@ ipcp_generate_summary (void)
/* Unreachable nodes should have been eliminated before ipcp. */ /* Unreachable nodes should have been eliminated before ipcp. */
gcc_assert (node->needed || node->reachable); gcc_assert (node->needed || node->reachable);
node->local.versionable = tree_versionable_function_p (node->decl); inline_summary (node)->versionable = tree_versionable_function_p (node->decl);
ipa_analyze_node (node); ipa_analyze_node (node);
} }
} }

View File

@ -100,11 +100,13 @@ inline_summary_alloc (void)
static void static void
inline_node_removal_hook (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) inline_node_removal_hook (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
{ {
struct inline_summary *info;
if (VEC_length (inline_summary_t, inline_summary_vec) if (VEC_length (inline_summary_t, inline_summary_vec)
<= (unsigned)node->uid) <= (unsigned)node->uid)
return; return;
memset (inline_summary (node), info = inline_summary (node);
0, sizeof (inline_summary_t)); info->estimated_growth = INT_MIN;
memset (info, 0, sizeof (inline_summary_t));
} }
/* Hook that is called by cgraph.c when a node is duplicated. */ /* Hook that is called by cgraph.c when a node is duplicated. */
@ -113,9 +115,12 @@ static void
inline_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst, inline_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst,
ATTRIBUTE_UNUSED void *data) ATTRIBUTE_UNUSED void *data)
{ {
struct inline_summary *info;
inline_summary_alloc (); inline_summary_alloc ();
memcpy (inline_summary (dst), inline_summary (src), info = inline_summary (dst);
memcpy (info, inline_summary (src),
sizeof (struct inline_summary)); sizeof (struct inline_summary));
info->estimated_growth = INT_MIN;
} }
static void static void
@ -124,18 +129,24 @@ dump_inline_summary (FILE *f, struct cgraph_node *node)
if (node->analyzed) if (node->analyzed)
{ {
struct inline_summary *s = inline_summary (node); struct inline_summary *s = inline_summary (node);
fprintf (f, "Inline summary for %s/%i\n", cgraph_node_name (node), fprintf (f, "Inline summary for %s/%i", cgraph_node_name (node),
node->uid); node->uid);
fprintf (f, " self time: %i, benefit: %i\n", if (s->disregard_inline_limits)
fprintf (f, " always_inline");
if (s->inlinable)
fprintf (f, " inlinable");
if (s->versionable)
fprintf (f, " versionable");
fprintf (f, "\n self time: %i, benefit: %i\n",
s->self_time, s->time_inlining_benefit); s->self_time, s->time_inlining_benefit);
fprintf (f, " global time: %i\n", node->global.time); fprintf (f, " global time: %i\n", s->time);
fprintf (f, " self size: %i, benefit: %i\n", fprintf (f, " self size: %i, benefit: %i\n",
s->self_size, s->size_inlining_benefit); s->self_size, s->size_inlining_benefit);
fprintf (f, " global size: %i", node->global.size); fprintf (f, " global size: %i", s->size);
fprintf (f, " self stack: %i\n", fprintf (f, " self stack: %i\n",
(int)s->estimated_self_stack_size); (int)s->estimated_self_stack_size);
fprintf (f, " global stack: %i\n\n", fprintf (f, " global stack: %i\n\n",
(int)node->global.estimated_stack_size); (int)s->estimated_stack_size);
} }
} }
@ -155,6 +166,26 @@ dump_inline_summaries (FILE *f)
dump_inline_summary (f, node); dump_inline_summary (f, node);
} }
/* Give initial reasons why inlining would fail on EDGE. This gets either
nullified or usually overwritten by more precise reasons later. */
void
initialize_inline_failed (struct cgraph_edge *e)
{
struct cgraph_node *callee = e->callee;
if (e->indirect_unknown_callee)
e->inline_failed = CIF_INDIRECT_UNKNOWN_CALL;
else if (!callee->analyzed)
e->inline_failed = CIF_BODY_NOT_AVAILABLE;
else if (callee->local.redefined_extern_inline)
e->inline_failed = CIF_REDEFINED_EXTERN_INLINE;
else if (e->call_stmt && gimple_call_cannot_inline_p (e->call_stmt))
e->inline_failed = CIF_MISMATCHED_ARGUMENTS;
else
e->inline_failed = CIF_FUNCTION_NOT_CONSIDERED;
}
/* See if statement might disappear after inlining. /* See if statement might disappear after inlining.
0 - means not eliminated 0 - means not eliminated
1 - half of statements goes away 1 - half of statements goes away
@ -317,24 +348,27 @@ compute_inline_parameters (struct cgraph_node *node)
{ {
HOST_WIDE_INT self_stack_size; HOST_WIDE_INT self_stack_size;
struct cgraph_edge *e; struct cgraph_edge *e;
struct inline_summary *info;
gcc_assert (!node->global.inlined_to); gcc_assert (!node->global.inlined_to);
inline_summary_alloc (); inline_summary_alloc ();
info = inline_summary (node);
/* Estimate the stack size for the function if we're optimizing. */ /* Estimate the stack size for the function if we're optimizing. */
self_stack_size = optimize ? estimated_stack_frame_size (node) : 0; self_stack_size = optimize ? estimated_stack_frame_size (node) : 0;
inline_summary (node)->estimated_self_stack_size = self_stack_size; info->estimated_self_stack_size = self_stack_size;
node->global.estimated_stack_size = self_stack_size; info->estimated_stack_size = self_stack_size;
node->global.stack_frame_offset = 0; info->stack_frame_offset = 0;
/* Can this function be inlined at all? */ /* Can this function be inlined at all? */
node->local.inlinable = tree_inlinable_function_p (node->decl); info->inlinable = tree_inlinable_function_p (node->decl);
if (!node->local.inlinable) if (!info->inlinable)
node->local.disregard_inline_limits = 0; info->disregard_inline_limits = 0;
/* Inlinable functions always can change signature. */ /* Inlinable functions always can change signature. */
if (node->local.inlinable) if (info->inlinable)
node->local.can_change_signature = true; node->local.can_change_signature = true;
else else
{ {
@ -349,8 +383,13 @@ compute_inline_parameters (struct cgraph_node *node)
estimate_function_body_sizes (node); estimate_function_body_sizes (node);
/* Inlining characteristics are maintained by the cgraph_mark_inline. */ /* Inlining characteristics are maintained by the cgraph_mark_inline. */
node->global.time = inline_summary (node)->self_time; info->time = info->self_time;
node->global.size = inline_summary (node)->self_size; info->size = info->self_size;
info->estimated_growth = INT_MIN;
info->stack_frame_offset = 0;
info->estimated_stack_size = info->estimated_self_stack_size;
info->disregard_inline_limits
= DECL_DISREGARD_INLINE_LIMITS (node->decl);
} }
@ -390,10 +429,12 @@ static inline int
estimate_edge_time (struct cgraph_edge *edge) estimate_edge_time (struct cgraph_edge *edge)
{ {
int call_stmt_time; int call_stmt_time;
struct inline_summary *info = inline_summary (edge->callee);
call_stmt_time = edge->call_stmt_time; call_stmt_time = edge->call_stmt_time;
gcc_checking_assert (call_stmt_time); gcc_checking_assert (call_stmt_time);
return (((gcov_type)edge->callee->global.time return (((gcov_type)info->time
- inline_summary (edge->callee)->time_inlining_benefit - info->time_inlining_benefit
- call_stmt_time) * edge->frequency - call_stmt_time) * edge->frequency
+ CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE; + CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE;
} }
@ -405,7 +446,7 @@ int
estimate_time_after_inlining (struct cgraph_node *node, estimate_time_after_inlining (struct cgraph_node *node,
struct cgraph_edge *edge) struct cgraph_edge *edge)
{ {
gcov_type time = node->global.time + estimate_edge_time (edge); gcov_type time = inline_summary (node)->time + estimate_edge_time (edge);
if (time < 0) if (time < 0)
time = 0; time = 0;
if (time > MAX_TIME) if (time > MAX_TIME)
@ -421,7 +462,7 @@ int
estimate_size_after_inlining (struct cgraph_node *node, estimate_size_after_inlining (struct cgraph_node *node,
struct cgraph_edge *edge) struct cgraph_edge *edge)
{ {
int size = node->global.size + estimate_edge_growth (edge); int size = inline_summary (node)->size + estimate_edge_growth (edge);
gcc_assert (size >= 0); gcc_assert (size >= 0);
return size; return size;
} }
@ -435,9 +476,10 @@ estimate_growth (struct cgraph_node *node)
int growth = 0; int growth = 0;
struct cgraph_edge *e; struct cgraph_edge *e;
bool self_recursive = false; bool self_recursive = false;
struct inline_summary *info = inline_summary (node);
if (node->global.estimated_growth != INT_MIN) if (info->estimated_growth != INT_MIN)
return node->global.estimated_growth; return info->estimated_growth;
for (e = node->callers; e; e = e->next_caller) for (e = node->callers; e; e = e->next_caller)
{ {
@ -453,15 +495,15 @@ estimate_growth (struct cgraph_node *node)
some inlining. */ some inlining. */
if (cgraph_will_be_removed_from_program_if_no_direct_calls (node) if (cgraph_will_be_removed_from_program_if_no_direct_calls (node)
&& !DECL_EXTERNAL (node->decl) && !self_recursive) && !DECL_EXTERNAL (node->decl) && !self_recursive)
growth -= node->global.size; growth -= info->size;
/* COMDAT functions are very often not shared across multiple units since they /* COMDAT functions are very often not shared across multiple units since they
come from various template instantiations. Take this into account. */ come from various template instantiations. Take this into account. */
else if (DECL_COMDAT (node->decl) && !self_recursive else if (DECL_COMDAT (node->decl) && !self_recursive
&& cgraph_can_remove_if_no_direct_calls_p (node)) && cgraph_can_remove_if_no_direct_calls_p (node))
growth -= (node->global.size growth -= (info->size
* (100 - PARAM_VALUE (PARAM_COMDAT_SHARING_PROBABILITY)) + 50) / 100; * (100 - PARAM_VALUE (PARAM_COMDAT_SHARING_PROBABILITY)) + 50) / 100;
node->global.estimated_growth = growth; info->estimated_growth = growth;
return growth; return growth;
} }
@ -561,19 +603,25 @@ inline_read_summary (void)
struct cgraph_node *node; struct cgraph_node *node;
struct inline_summary *info; struct inline_summary *info;
lto_cgraph_encoder_t encoder; lto_cgraph_encoder_t encoder;
struct bitpack_d bp;
index = lto_input_uleb128 (ib); index = lto_input_uleb128 (ib);
encoder = file_data->cgraph_node_encoder; encoder = file_data->cgraph_node_encoder;
node = lto_cgraph_encoder_deref (encoder, index); node = lto_cgraph_encoder_deref (encoder, index);
info = inline_summary (node); info = inline_summary (node);
node->global.estimated_stack_size info->estimated_stack_size
= info->estimated_self_stack_size = lto_input_uleb128 (ib); = info->estimated_self_stack_size = lto_input_uleb128 (ib);
node->global.time = info->self_time = lto_input_uleb128 (ib); info->time = info->self_time = lto_input_uleb128 (ib);
info->time_inlining_benefit = lto_input_uleb128 (ib); info->time_inlining_benefit = lto_input_uleb128 (ib);
node->global.size = info->self_size = lto_input_uleb128 (ib); info->size = info->self_size = lto_input_uleb128 (ib);
info->size_inlining_benefit = lto_input_uleb128 (ib); info->size_inlining_benefit = lto_input_uleb128 (ib);
node->global.estimated_growth = INT_MIN; info->estimated_growth = INT_MIN;
bp = lto_input_bitpack (ib);
info->inlinable = bp_unpack_value (&bp, 1);
info->versionable = bp_unpack_value (&bp, 1);
info->disregard_inline_limits = bp_unpack_value (&bp, 1);
} }
lto_destroy_simple_input_block (file_data, lto_destroy_simple_input_block (file_data,
@ -623,6 +671,8 @@ inline_write_summary (cgraph_node_set set,
if (node->analyzed) if (node->analyzed)
{ {
struct inline_summary *info = inline_summary (node); struct inline_summary *info = inline_summary (node);
struct bitpack_d bp;
lto_output_uleb128_stream (ob->main_stream, lto_output_uleb128_stream (ob->main_stream,
lto_cgraph_encoder_encode (encoder, node)); lto_cgraph_encoder_encode (encoder, node));
lto_output_sleb128_stream (ob->main_stream, lto_output_sleb128_stream (ob->main_stream,
@ -635,6 +685,11 @@ inline_write_summary (cgraph_node_set set,
info->self_time); info->self_time);
lto_output_sleb128_stream (ob->main_stream, lto_output_sleb128_stream (ob->main_stream,
info->time_inlining_benefit); info->time_inlining_benefit);
bp = bitpack_create (ob->main_stream);
bp_pack_value (&bp, info->inlinable, 1);
bp_pack_value (&bp, info->versionable, 1);
bp_pack_value (&bp, info->disregard_inline_limits, 1);
lto_output_bitpack (&bp);
} }
} }
lto_destroy_simple_output_block (ob); lto_destroy_simple_output_block (ob);

View File

@ -156,6 +156,7 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
bool update_original) bool update_original)
{ {
HOST_WIDE_INT peak; HOST_WIDE_INT peak;
struct inline_summary *caller_info, *callee_info;
if (duplicate) if (duplicate)
{ {
@ -184,7 +185,7 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
gcc_assert (!e->callee->global.inlined_to); gcc_assert (!e->callee->global.inlined_to);
if (e->callee->analyzed && !DECL_EXTERNAL (e->callee->decl)) if (e->callee->analyzed && !DECL_EXTERNAL (e->callee->decl))
{ {
overall_size -= e->callee->global.size; overall_size -= inline_summary (e->callee)->size;
nfunctions_inlined++; nfunctions_inlined++;
} }
duplicate = false; duplicate = false;
@ -201,17 +202,20 @@ cgraph_clone_inlined_nodes (struct cgraph_edge *e, bool duplicate,
} }
} }
callee_info = inline_summary (e->callee);
caller_info = inline_summary (e->caller);
if (e->caller->global.inlined_to) if (e->caller->global.inlined_to)
e->callee->global.inlined_to = e->caller->global.inlined_to; e->callee->global.inlined_to = e->caller->global.inlined_to;
else else
e->callee->global.inlined_to = e->caller; e->callee->global.inlined_to = e->caller;
e->callee->global.stack_frame_offset callee_info->stack_frame_offset
= e->caller->global.stack_frame_offset = caller_info->stack_frame_offset
+ inline_summary (e->caller)->estimated_self_stack_size; + caller_info->estimated_self_stack_size;
peak = e->callee->global.stack_frame_offset peak = callee_info->stack_frame_offset
+ inline_summary (e->callee)->estimated_self_stack_size; + callee_info->estimated_self_stack_size;
if (e->callee->global.inlined_to->global.estimated_stack_size < peak) if (inline_summary (e->callee->global.inlined_to)->estimated_stack_size < peak)
e->callee->global.inlined_to->global.estimated_stack_size = peak; inline_summary (e->callee->global.inlined_to)->estimated_stack_size = peak;
cgraph_propagate_frequency (e->callee); cgraph_propagate_frequency (e->callee);
/* Recursively clone all bodies. */ /* Recursively clone all bodies. */
@ -233,6 +237,7 @@ cgraph_mark_inline_edge (struct cgraph_edge *e, bool update_original,
int old_size = 0, new_size = 0; int old_size = 0, new_size = 0;
struct cgraph_node *to = NULL; struct cgraph_node *to = NULL;
struct cgraph_edge *curr = e; struct cgraph_edge *curr = e;
struct inline_summary *info;
/* Don't inline inlined edges. */ /* Don't inline inlined edges. */
gcc_assert (e->inline_failed); gcc_assert (e->inline_failed);
@ -248,10 +253,11 @@ cgraph_mark_inline_edge (struct cgraph_edge *e, bool update_original,
for (;e && !e->inline_failed; e = e->caller->callers) for (;e && !e->inline_failed; e = e->caller->callers)
{ {
to = e->caller; to = e->caller;
old_size = e->caller->global.size; info = inline_summary (to);
old_size = info->size;
new_size = estimate_size_after_inlining (to, curr); new_size = estimate_size_after_inlining (to, curr);
to->global.size = new_size; info->size = new_size;
to->global.time = estimate_time_after_inlining (to, curr); info->time = estimate_time_after_inlining (to, curr);
} }
gcc_assert (curr->callee->global.inlined_to == to); gcc_assert (curr->callee->global.inlined_to == to);
if (new_size > old_size) if (new_size > old_size)
@ -280,23 +286,27 @@ cgraph_check_inline_limits (struct cgraph_edge *e,
int newsize; int newsize;
int limit; int limit;
HOST_WIDE_INT stack_size_limit, inlined_stack; HOST_WIDE_INT stack_size_limit, inlined_stack;
struct inline_summary *info, *what_info;
if (to->global.inlined_to) if (to->global.inlined_to)
to = to->global.inlined_to; to = to->global.inlined_to;
info = inline_summary (to);
what_info = inline_summary (what);
/* When inlining large function body called once into small function, /* When inlining large function body called once into small function,
take the inlined function as base for limiting the growth. */ take the inlined function as base for limiting the growth. */
if (inline_summary (to)->self_size > inline_summary(what)->self_size) if (info->self_size > what_info->self_size)
limit = inline_summary (to)->self_size; limit = info->self_size;
else else
limit = inline_summary (what)->self_size; limit = what_info->self_size;
limit += limit * PARAM_VALUE (PARAM_LARGE_FUNCTION_GROWTH) / 100; limit += limit * PARAM_VALUE (PARAM_LARGE_FUNCTION_GROWTH) / 100;
/* Check the size after inlining against the function limits. But allow /* Check the size after inlining against the function limits. But allow
the function to shrink if it went over the limits by forced inlining. */ the function to shrink if it went over the limits by forced inlining. */
newsize = estimate_size_after_inlining (to, e); newsize = estimate_size_after_inlining (to, e);
if (newsize >= to->global.size if (newsize >= info->size
&& newsize > PARAM_VALUE (PARAM_LARGE_FUNCTION_INSNS) && newsize > PARAM_VALUE (PARAM_LARGE_FUNCTION_INSNS)
&& newsize > limit) && newsize > limit)
{ {
@ -305,13 +315,13 @@ cgraph_check_inline_limits (struct cgraph_edge *e,
return false; return false;
} }
stack_size_limit = inline_summary (to)->estimated_self_stack_size; stack_size_limit = info->estimated_self_stack_size;
stack_size_limit += stack_size_limit * PARAM_VALUE (PARAM_STACK_FRAME_GROWTH) / 100; stack_size_limit += stack_size_limit * PARAM_VALUE (PARAM_STACK_FRAME_GROWTH) / 100;
inlined_stack = (to->global.stack_frame_offset inlined_stack = (info->stack_frame_offset
+ inline_summary (to)->estimated_self_stack_size + info->estimated_self_stack_size
+ what->global.estimated_stack_size); + what_info->estimated_stack_size);
if (inlined_stack > stack_size_limit if (inlined_stack > stack_size_limit
&& inlined_stack > PARAM_VALUE (PARAM_LARGE_STACK_FRAME)) && inlined_stack > PARAM_VALUE (PARAM_LARGE_STACK_FRAME))
{ {
@ -328,8 +338,9 @@ static bool
cgraph_default_inline_p (struct cgraph_node *n, cgraph_inline_failed_t *reason) cgraph_default_inline_p (struct cgraph_node *n, cgraph_inline_failed_t *reason)
{ {
tree decl = n->decl; tree decl = n->decl;
struct inline_summary *info = inline_summary (n);
if (n->local.disregard_inline_limits) if (info->disregard_inline_limits)
return true; return true;
if (!flag_inline_small_functions && !DECL_DECLARED_INLINE_P (decl)) if (!flag_inline_small_functions && !DECL_DECLARED_INLINE_P (decl))
@ -354,7 +365,7 @@ cgraph_default_inline_p (struct cgraph_node *n, cgraph_inline_failed_t *reason)
if (DECL_DECLARED_INLINE_P (decl)) if (DECL_DECLARED_INLINE_P (decl))
{ {
if (n->global.size >= MAX_INLINE_INSNS_SINGLE) if (info->size >= MAX_INLINE_INSNS_SINGLE)
{ {
if (reason) if (reason)
*reason = CIF_MAX_INLINE_INSNS_SINGLE_LIMIT; *reason = CIF_MAX_INLINE_INSNS_SINGLE_LIMIT;
@ -363,7 +374,7 @@ cgraph_default_inline_p (struct cgraph_node *n, cgraph_inline_failed_t *reason)
} }
else else
{ {
if (n->global.size >= MAX_INLINE_INSNS_AUTO) if (info->size >= MAX_INLINE_INSNS_AUTO)
{ {
if (reason) if (reason)
*reason = CIF_MAX_INLINE_INSNS_AUTO_LIMIT; *reason = CIF_MAX_INLINE_INSNS_AUTO_LIMIT;
@ -385,8 +396,9 @@ cgraph_edge_badness (struct cgraph_edge *edge, bool dump)
{ {
gcov_type badness; gcov_type badness;
int growth; int growth;
struct inline_summary *callee_info = inline_summary (edge->callee);
if (edge->callee->local.disregard_inline_limits) if (callee_info->disregard_inline_limits)
return INT_MIN; return INT_MIN;
growth = estimate_edge_growth (edge); growth = estimate_edge_growth (edge);
@ -398,11 +410,11 @@ cgraph_edge_badness (struct cgraph_edge *edge, bool dump)
cgraph_node_name (edge->callee)); cgraph_node_name (edge->callee));
fprintf (dump_file, " growth %i, time %i-%i, size %i-%i\n", fprintf (dump_file, " growth %i, time %i-%i, size %i-%i\n",
growth, growth,
edge->callee->global.time, callee_info->time,
inline_summary (edge->callee)->time_inlining_benefit callee_info->time_inlining_benefit
+ edge->call_stmt_time, + edge->call_stmt_time,
edge->callee->global.size, callee_info->size,
inline_summary (edge->callee)->size_inlining_benefit callee_info->size_inlining_benefit
+ edge->call_stmt_size); + edge->call_stmt_size);
} }
@ -422,7 +434,7 @@ cgraph_edge_badness (struct cgraph_edge *edge, bool dump)
badness = badness =
((int) ((int)
((double) edge->count * INT_MIN / max_count / (max_benefit + 1)) * ((double) edge->count * INT_MIN / max_count / (max_benefit + 1)) *
(inline_summary (edge->callee)->time_inlining_benefit (callee_info->time_inlining_benefit
+ edge->call_stmt_time + 1)) / growth; + edge->call_stmt_time + 1)) / growth;
if (dump) if (dump)
{ {
@ -453,9 +465,9 @@ cgraph_edge_badness (struct cgraph_edge *edge, bool dump)
int growth_for_all; int growth_for_all;
badness = growth * 10000; badness = growth * 10000;
benefitperc = benefitperc =
100 * (inline_summary (edge->callee)->time_inlining_benefit 100 * (callee_info->time_inlining_benefit
+ edge->call_stmt_time) + edge->call_stmt_time)
/ (edge->callee->global.time + 1) + 1; / (callee_info->time + 1) + 1;
benefitperc = MIN (benefitperc, 100); benefitperc = MIN (benefitperc, 100);
div *= benefitperc; div *= benefitperc;
@ -543,13 +555,13 @@ update_caller_keys (fibheap_t heap, struct cgraph_node *node,
struct cgraph_edge *edge; struct cgraph_edge *edge;
cgraph_inline_failed_t failed_reason; cgraph_inline_failed_t failed_reason;
if (!node->local.inlinable if (!inline_summary (node)->inlinable
|| cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE || cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE
|| node->global.inlined_to) || node->global.inlined_to)
return; return;
if (!bitmap_set_bit (updated_nodes, node->uid)) if (!bitmap_set_bit (updated_nodes, node->uid))
return; return;
node->global.estimated_growth = INT_MIN; inline_summary (node)->estimated_growth = INT_MIN;
/* See if there is something to do. */ /* See if there is something to do. */
for (edge = node->callers; edge; edge = edge->next_caller) for (edge = node->callers; edge; edge = edge->next_caller)
@ -586,7 +598,7 @@ update_callee_keys (fibheap_t heap, struct cgraph_node *node,
bitmap updated_nodes) bitmap updated_nodes)
{ {
struct cgraph_edge *e = node->callees; struct cgraph_edge *e = node->callees;
node->global.estimated_growth = INT_MIN; inline_summary (node)->estimated_growth = INT_MIN;
if (!e) if (!e)
return; return;
@ -596,11 +608,11 @@ update_callee_keys (fibheap_t heap, struct cgraph_node *node,
else else
{ {
if (e->inline_failed if (e->inline_failed
&& e->callee->local.inlinable && inline_summary (e->callee)->inlinable
&& cgraph_function_body_availability (e->callee) >= AVAIL_AVAILABLE && cgraph_function_body_availability (e->callee) >= AVAIL_AVAILABLE
&& !bitmap_bit_p (updated_nodes, e->callee->uid)) && !bitmap_bit_p (updated_nodes, e->callee->uid))
{ {
node->global.estimated_growth = INT_MIN; inline_summary (node)->estimated_growth = INT_MIN;
/* If function becomes uninlinable, we need to remove it from the heap. */ /* If function becomes uninlinable, we need to remove it from the heap. */
if (!cgraph_default_inline_p (e->callee, &e->inline_failed)) if (!cgraph_default_inline_p (e->callee, &e->inline_failed))
update_caller_keys (heap, e->callee, updated_nodes); update_caller_keys (heap, e->callee, updated_nodes);
@ -632,7 +644,7 @@ update_all_callee_keys (fibheap_t heap, struct cgraph_node *node,
bitmap updated_nodes) bitmap updated_nodes)
{ {
struct cgraph_edge *e = node->callees; struct cgraph_edge *e = node->callees;
node->global.estimated_growth = INT_MIN; inline_summary (node)->estimated_growth = INT_MIN;
if (!e) if (!e)
return; return;
@ -709,7 +721,7 @@ cgraph_decide_recursive_inlining (struct cgraph_edge *edge,
/* It does not make sense to recursively inline always-inline functions /* It does not make sense to recursively inline always-inline functions
as we are going to sorry() on the remaining calls anyway. */ as we are going to sorry() on the remaining calls anyway. */
if (node->local.disregard_inline_limits if (inline_summary (node)->disregard_inline_limits
&& lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl))) && lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl)))
return false; return false;
@ -811,8 +823,8 @@ cgraph_decide_recursive_inlining (struct cgraph_edge *edge,
if (dump_file) if (dump_file)
fprintf (dump_file, fprintf (dump_file,
"\n Inlined %i times, body grown from size %i to %i, time %i to %i\n", n, "\n Inlined %i times, body grown from size %i to %i, time %i to %i\n", n,
master_clone->global.size, node->global.size, inline_summary (master_clone)->size, inline_summary (node)->size,
master_clone->global.time, node->global.time); inline_summary (master_clone)->time, inline_summary (node)->time);
/* Remove master clone we used for inlining. We rely that clones inlined /* Remove master clone we used for inlining. We rely that clones inlined
into master clone gets queued just before master clone so we don't into master clone gets queued just before master clone so we don't
@ -870,7 +882,7 @@ add_new_edges_to_heap (fibheap_t heap, VEC (cgraph_edge_p, heap) *new_edges)
struct cgraph_edge *edge = VEC_pop (cgraph_edge_p, new_edges); struct cgraph_edge *edge = VEC_pop (cgraph_edge_p, new_edges);
gcc_assert (!edge->aux); gcc_assert (!edge->aux);
if (edge->callee->local.inlinable if (inline_summary (edge->callee)->inlinable
&& edge->inline_failed && edge->inline_failed
&& cgraph_default_inline_p (edge->callee, &edge->inline_failed)) && cgraph_default_inline_p (edge->callee, &edge->inline_failed))
edge->aux = fibheap_insert (heap, cgraph_edge_badness (edge, false), edge); edge->aux = fibheap_insert (heap, cgraph_edge_badness (edge, false), edge);
@ -905,26 +917,37 @@ cgraph_decide_inlining_of_small_functions (void)
/* Put all inline candidates into the heap. */ /* Put all inline candidates into the heap. */
for (node = cgraph_nodes; node; node = node->next) for (node = cgraph_nodes; node; node = node->next)
{ if (node->analyzed)
if (!node->local.inlinable || !node->callers) {
continue; struct inline_summary *info = inline_summary (node);
if (dump_file)
fprintf (dump_file, "Considering inline candidate %s.\n", cgraph_node_name (node));
node->global.estimated_growth = INT_MIN; if (!info->inlinable || !node->callers)
if (!cgraph_default_inline_p (node, &failed_reason))
{
cgraph_set_inline_failed (node, failed_reason);
continue;
}
for (edge = node->callers; edge; edge = edge->next_caller)
if (edge->inline_failed)
{ {
gcc_assert (!edge->aux); struct cgraph_edge *e;
edge->aux = fibheap_insert (heap, cgraph_edge_badness (edge, false), edge); for (e = node->callers; e; e = e->next_caller)
{
gcc_assert (e->inline_failed);
e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
}
continue;
} }
} if (dump_file)
fprintf (dump_file, "Considering inline candidate %s.\n", cgraph_node_name (node));
info->estimated_growth = INT_MIN;
if (!cgraph_default_inline_p (node, &failed_reason))
{
cgraph_set_inline_failed (node, failed_reason);
continue;
}
for (edge = node->callers; edge; edge = edge->next_caller)
if (edge->inline_failed)
{
gcc_assert (!edge->aux);
edge->aux = fibheap_insert (heap, cgraph_edge_badness (edge, false), edge);
}
}
max_size = compute_max_insns (overall_size); max_size = compute_max_insns (overall_size);
min_size = overall_size; min_size = overall_size;
@ -963,7 +986,7 @@ cgraph_decide_inlining_of_small_functions (void)
fprintf (dump_file, fprintf (dump_file,
"\nConsidering %s with %i size\n", "\nConsidering %s with %i size\n",
cgraph_node_name (edge->callee), cgraph_node_name (edge->callee),
edge->callee->global.size); inline_summary (edge->callee)->size);
fprintf (dump_file, fprintf (dump_file,
" to be inlined into %s in %s:%i\n" " to be inlined into %s in %s:%i\n"
" Estimated growth after inlined into all callees is %+i insns.\n" " Estimated growth after inlined into all callees is %+i insns.\n"
@ -1007,7 +1030,7 @@ cgraph_decide_inlining_of_small_functions (void)
if (where->global.inlined_to) if (where->global.inlined_to)
{ {
edge->inline_failed edge->inline_failed
= (edge->callee->local.disregard_inline_limits = (inline_summary (edge->callee)->disregard_inline_limits
? CIF_RECURSIVE_INLINING : CIF_UNSPECIFIED); ? CIF_RECURSIVE_INLINING : CIF_UNSPECIFIED);
if (dump_file) if (dump_file)
fprintf (dump_file, " inline_failed:Recursive inlining performed only for function itself.\n"); fprintf (dump_file, " inline_failed:Recursive inlining performed only for function itself.\n");
@ -1015,7 +1038,7 @@ cgraph_decide_inlining_of_small_functions (void)
} }
} }
if (edge->callee->local.disregard_inline_limits) if (inline_summary (edge->callee)->disregard_inline_limits)
; ;
else if (!cgraph_maybe_hot_edge_p (edge)) else if (!cgraph_maybe_hot_edge_p (edge))
not_good = CIF_UNLIKELY_CALL; not_good = CIF_UNLIKELY_CALL;
@ -1112,8 +1135,8 @@ cgraph_decide_inlining_of_small_functions (void)
" Inlined into %s which now has time %i and size %i," " Inlined into %s which now has time %i and size %i,"
"net change of %+i.\n", "net change of %+i.\n",
cgraph_node_name (edge->caller), cgraph_node_name (edge->caller),
edge->caller->global.time, inline_summary (edge->caller)->time,
edge->caller->global.size, inline_summary (edge->caller)->size,
overall_size - old_size); overall_size - old_size);
} }
if (min_size > overall_size) if (min_size > overall_size)
@ -1142,7 +1165,7 @@ cgraph_decide_inlining_of_small_functions (void)
fprintf (dump_file, fprintf (dump_file,
"\nSkipping %s with %i size\n", "\nSkipping %s with %i size\n",
cgraph_node_name (edge->callee), cgraph_node_name (edge->callee),
edge->callee->global.size); inline_summary (edge->callee)->size);
fprintf (dump_file, fprintf (dump_file,
" called by %s in %s:%i\n" " called by %s in %s:%i\n"
" Estimated growth after inlined into all callees is %+i insns.\n" " Estimated growth after inlined into all callees is %+i insns.\n"
@ -1159,7 +1182,7 @@ cgraph_decide_inlining_of_small_functions (void)
if (dump_flags & TDF_DETAILS) if (dump_flags & TDF_DETAILS)
cgraph_edge_badness (edge, true); cgraph_edge_badness (edge, true);
} }
if (!edge->callee->local.disregard_inline_limits && edge->inline_failed) if (!inline_summary (edge->callee)->disregard_inline_limits && edge->inline_failed)
edge->inline_failed = CIF_INLINE_UNIT_GROWTH_LIMIT; edge->inline_failed = CIF_INLINE_UNIT_GROWTH_LIMIT;
} }
@ -1287,13 +1310,14 @@ cgraph_decide_inlining (void)
if (node->analyzed) if (node->analyzed)
{ {
struct cgraph_edge *e; struct cgraph_edge *e;
struct inline_summary *info = inline_summary (node);
gcc_assert (inline_summary (node)->self_size == node->global.size); gcc_assert (info->self_size == info->size);
if (!DECL_EXTERNAL (node->decl)) if (!DECL_EXTERNAL (node->decl))
initial_size += node->global.size; initial_size += info->size;
for (e = node->callees; e; e = e->next_callee) for (e = node->callees; e; e = e->next_callee)
{ {
int benefit = (inline_summary (node)->time_inlining_benefit int benefit = (info->time_inlining_benefit
+ e->call_stmt_time); + e->call_stmt_time);
if (max_count < e->count) if (max_count < e->count)
max_count = e->count; max_count = e->count;
@ -1362,7 +1386,7 @@ cgraph_decide_inlining (void)
&& !node->callers->next_caller && !node->callers->next_caller
&& !node->global.inlined_to && !node->global.inlined_to
&& cgraph_will_be_removed_from_program_if_no_direct_calls (node) && cgraph_will_be_removed_from_program_if_no_direct_calls (node)
&& node->local.inlinable && inline_summary (node)->inlinable
&& cgraph_function_body_availability (node) >= AVAIL_AVAILABLE && cgraph_function_body_availability (node) >= AVAIL_AVAILABLE
&& node->callers->inline_failed && node->callers->inline_failed
&& node->callers->caller != node && node->callers->caller != node
@ -1377,11 +1401,11 @@ cgraph_decide_inlining (void)
{ {
fprintf (dump_file, fprintf (dump_file,
"\nConsidering %s size %i.\n", "\nConsidering %s size %i.\n",
cgraph_node_name (node), node->global.size); cgraph_node_name (node), inline_summary (node)->size);
fprintf (dump_file, fprintf (dump_file,
" Called once from %s %i insns.\n", " Called once from %s %i insns.\n",
cgraph_node_name (node->callers->caller), cgraph_node_name (node->callers->caller),
node->callers->caller->global.size); inline_summary (node->callers->caller)->size);
} }
if (cgraph_check_inline_limits (node->callers, &reason)) if (cgraph_check_inline_limits (node->callers, &reason))
@ -1393,7 +1417,7 @@ cgraph_decide_inlining (void)
" Inlined into %s which now has %i size" " Inlined into %s which now has %i size"
" for a net change of %+i size.\n", " for a net change of %+i size.\n",
cgraph_node_name (caller), cgraph_node_name (caller),
caller->global.size, inline_summary (caller)->size,
overall_size - old_size); overall_size - old_size);
} }
else else
@ -1442,7 +1466,7 @@ leaf_node_p (struct cgraph_node *n)
static bool static bool
cgraph_edge_early_inlinable_p (struct cgraph_edge *e, FILE *file) cgraph_edge_early_inlinable_p (struct cgraph_edge *e, FILE *file)
{ {
if (!e->callee->local.inlinable) if (!inline_summary (e->callee)->inlinable)
{ {
if (file) if (file)
fprintf (file, "Not inlining: Function not inlinable.\n"); fprintf (file, "Not inlining: Function not inlinable.\n");
@ -1482,7 +1506,7 @@ cgraph_perform_always_inlining (struct cgraph_node *node)
for (e = node->callees; e; e = e->next_callee) for (e = node->callees; e; e = e->next_callee)
{ {
if (!e->callee->local.disregard_inline_limits) if (!inline_summary (e->callee)->disregard_inline_limits)
continue; continue;
if (dump_file) if (dump_file)
@ -1524,16 +1548,16 @@ cgraph_decide_inlining_incrementally (struct cgraph_node *node)
/* Never inline regular functions into always-inline functions /* Never inline regular functions into always-inline functions
during incremental inlining. */ during incremental inlining. */
if (node->local.disregard_inline_limits) if (inline_summary (node)->disregard_inline_limits)
return false; return false;
for (e = node->callees; e; e = e->next_callee) for (e = node->callees; e; e = e->next_callee)
{ {
int allowed_growth = 0; int allowed_growth = 0;
if (!e->callee->local.inlinable if (!inline_summary (e->callee)->inlinable
|| !e->inline_failed || !e->inline_failed
|| e->callee->local.disregard_inline_limits) || inline_summary (e->callee)->disregard_inline_limits)
continue; continue;
/* Do not consider functions not declared inline. */ /* Do not consider functions not declared inline. */

View File

@ -23,9 +23,10 @@ along with GCC; see the file COPYING3. If not see
struct inline_summary struct inline_summary
{ {
/* Information about the function body itself. */
/* Estimated stack frame consumption by the function. */ /* Estimated stack frame consumption by the function. */
HOST_WIDE_INT estimated_self_stack_size; HOST_WIDE_INT estimated_self_stack_size;
/* Size of the function body. */ /* Size of the function body. */
int self_size; int self_size;
/* How many instructions are likely going to disappear after inlining. */ /* How many instructions are likely going to disappear after inlining. */
@ -34,6 +35,29 @@ struct inline_summary
int self_time; int self_time;
/* How much time is going to be saved by inlining. */ /* How much time is going to be saved by inlining. */
int time_inlining_benefit; int time_inlining_benefit;
/* False when there something makes inlining impossible (such as va_arg). */
unsigned inlinable : 1;
/* False when there something makes versioning impossible.
Currently computed and used only by ipa-cp. */
unsigned versionable : 1;
/* True when function should be inlined independently on its size. */
unsigned disregard_inline_limits : 1;
/* Information about function that will result after applying all the
inline decisions present in the callgraph. Generally kept up to
date only for functions that are not inline clones. */
/* Estimated stack frame consumption by the function. */
HOST_WIDE_INT estimated_stack_size;
/* Expected offset of the stack frame of inlined function. */
HOST_WIDE_INT stack_frame_offset;
/* Estimated size of the function after inlining. */
int time;
int size;
/* Cached estimated growth after inlining.
INT_MIN if not computed. */
int estimated_growth;
}; };
typedef struct inline_summary inline_summary_t; typedef struct inline_summary inline_summary_t;
@ -47,6 +71,7 @@ void inline_generate_summary (void);
void inline_read_summary (void); void inline_read_summary (void);
void inline_write_summary (cgraph_node_set, varpool_node_set); void inline_write_summary (cgraph_node_set, varpool_node_set);
void inline_free_summary (void); void inline_free_summary (void);
void initialize_inline_failed (struct cgraph_edge *);
int estimate_time_after_inlining (struct cgraph_node *, struct cgraph_edge *); int estimate_time_after_inlining (struct cgraph_node *, struct cgraph_edge *);
int estimate_size_after_inlining (struct cgraph_node *, struct cgraph_edge *); int estimate_size_after_inlining (struct cgraph_node *, struct cgraph_edge *);
int estimate_growth (struct cgraph_node *); int estimate_growth (struct cgraph_node *);
@ -63,10 +88,10 @@ static inline int
estimate_edge_growth (struct cgraph_edge *edge) estimate_edge_growth (struct cgraph_edge *edge)
{ {
int call_stmt_size; int call_stmt_size;
struct inline_summary *info = inline_summary (edge->callee);
call_stmt_size = edge->call_stmt_size; call_stmt_size = edge->call_stmt_size;
gcc_checking_assert (call_stmt_size); gcc_checking_assert (call_stmt_size);
return (edge->callee->global.size return (info->size
- inline_summary (edge->callee)->size_inlining_benefit - info->size_inlining_benefit
- call_stmt_size); - call_stmt_size);
} }

View File

@ -92,6 +92,7 @@ along with GCC; see the file COPYING3. If not see
#include "fibheap.h" #include "fibheap.h"
#include "params.h" #include "params.h"
#include "gimple-pretty-print.h" #include "gimple-pretty-print.h"
#include "ipa-inline.h"
/* Per basic block info. */ /* Per basic block info. */
@ -1281,13 +1282,13 @@ execute_split_functions (void)
} }
/* This can be relaxed; function might become inlinable after splitting /* This can be relaxed; function might become inlinable after splitting
away the uninlinable part. */ away the uninlinable part. */
if (!node->local.inlinable) if (!inline_summary (node)->inlinable)
{ {
if (dump_file) if (dump_file)
fprintf (dump_file, "Not splitting: not inlinable.\n"); fprintf (dump_file, "Not splitting: not inlinable.\n");
return 0; return 0;
} }
if (node->local.disregard_inline_limits) if (DECL_DISREGARD_INLINE_LIMITS (node->decl))
{ {
if (dump_file) if (dump_file)
fprintf (dump_file, "Not splitting: disregarding inline limits.\n"); fprintf (dump_file, "Not splitting: disregarding inline limits.\n");

View File

@ -78,8 +78,8 @@ cgraph_postorder (struct cgraph_node **order)
/* Break possible cycles involving always-inline /* Break possible cycles involving always-inline
functions by ignoring edges from always-inline functions by ignoring edges from always-inline
functions to non-always-inline functions. */ functions to non-always-inline functions. */
if (edge->caller->local.disregard_inline_limits if (DECL_DISREGARD_INLINE_LIMITS (edge->caller->decl)
&& !edge->callee->local.disregard_inline_limits) && !DECL_DISREGARD_INLINE_LIMITS (edge->callee->decl))
continue; continue;
if (!edge->caller->aux) if (!edge->caller->aux)
{ {
@ -380,7 +380,6 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
cgraph_node_remove_callees (node); cgraph_node_remove_callees (node);
ipa_remove_all_references (&node->ref_list); ipa_remove_all_references (&node->ref_list);
node->analyzed = false; node->analyzed = false;
node->local.inlinable = false;
} }
if (!node->aux) if (!node->aux)
{ {
@ -421,7 +420,6 @@ cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
if (!clone) if (!clone)
{ {
cgraph_release_function_body (node); cgraph_release_function_body (node);
node->local.inlinable = false;
if (node->prev_sibling_clone) if (node->prev_sibling_clone)
node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone; node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone;
else if (node->clone_of) else if (node->clone_of)
@ -1629,7 +1627,7 @@ record_cdtor_fn (struct cgraph_node *node)
if (DECL_STATIC_DESTRUCTOR (node->decl)) if (DECL_STATIC_DESTRUCTOR (node->decl))
VEC_safe_push (tree, heap, static_dtors, node->decl); VEC_safe_push (tree, heap, static_dtors, node->decl);
node = cgraph_get_node (node->decl); node = cgraph_get_node (node->decl);
node->local.disregard_inline_limits = 1; DECL_DISREGARD_INLINE_LIMITS (node->decl) = 1;
} }
/* Define global constructors/destructor functions for the CDTORS, of /* Define global constructors/destructor functions for the CDTORS, of

View File

@ -489,10 +489,7 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node,
bp_pack_value (&bp, node->local.local, 1); bp_pack_value (&bp, node->local.local, 1);
bp_pack_value (&bp, node->local.externally_visible, 1); bp_pack_value (&bp, node->local.externally_visible, 1);
bp_pack_value (&bp, node->local.finalized, 1); bp_pack_value (&bp, node->local.finalized, 1);
bp_pack_value (&bp, node->local.inlinable, 1);
bp_pack_value (&bp, node->local.versionable, 1);
bp_pack_value (&bp, node->local.can_change_signature, 1); bp_pack_value (&bp, node->local.can_change_signature, 1);
bp_pack_value (&bp, node->local.disregard_inline_limits, 1);
bp_pack_value (&bp, node->local.redefined_extern_inline, 1); bp_pack_value (&bp, node->local.redefined_extern_inline, 1);
bp_pack_value (&bp, node->local.vtable_method, 1); bp_pack_value (&bp, node->local.vtable_method, 1);
bp_pack_value (&bp, node->needed, 1); bp_pack_value (&bp, node->needed, 1);
@ -928,10 +925,7 @@ input_overwrite_node (struct lto_file_decl_data *file_data,
node->local.local = bp_unpack_value (bp, 1); node->local.local = bp_unpack_value (bp, 1);
node->local.externally_visible = bp_unpack_value (bp, 1); node->local.externally_visible = bp_unpack_value (bp, 1);
node->local.finalized = bp_unpack_value (bp, 1); node->local.finalized = bp_unpack_value (bp, 1);
node->local.inlinable = bp_unpack_value (bp, 1);
node->local.versionable = bp_unpack_value (bp, 1);
node->local.can_change_signature = bp_unpack_value (bp, 1); node->local.can_change_signature = bp_unpack_value (bp, 1);
node->local.disregard_inline_limits = bp_unpack_value (bp, 1);
node->local.redefined_extern_inline = bp_unpack_value (bp, 1); node->local.redefined_extern_inline = bp_unpack_value (bp, 1);
node->local.vtable_method = bp_unpack_value (bp, 1); node->local.vtable_method = bp_unpack_value (bp, 1);
node->needed = bp_unpack_value (bp, 1); node->needed = bp_unpack_value (bp, 1);

View File

@ -1,3 +1,7 @@
2011-04-16 Jan Hubicka <jh@suse.cz>
* lto.c (lto_balanced_map): Update.
2011-04-14 Jan Hubicka <jh@suse.cz> 2011-04-14 Jan Hubicka <jh@suse.cz>
* lto.c: Include ipa-inline.h * lto.c: Include ipa-inline.h

View File

@ -1030,7 +1030,7 @@ lto_balanced_map (void)
if (partition_cgraph_node_p (node)) if (partition_cgraph_node_p (node))
{ {
order[n_nodes++] = node; order[n_nodes++] = node;
total_size += node->global.size; total_size += inline_summary (node)->size;
} }
} }
free (postorder); free (postorder);
@ -1049,7 +1049,7 @@ lto_balanced_map (void)
{ {
if (!order[i]->aux) if (!order[i]->aux)
add_cgraph_node_to_partition (partition, order[i]); add_cgraph_node_to_partition (partition, order[i]);
total_size -= order[i]->global.size; total_size -= inline_summary (order[i])->size;
/* Once we added a new node to the partition, we also want to add /* Once we added a new node to the partition, we also want to add
all referenced variables unless they was already added into some all referenced variables unless they was already added into some

View File

@ -91,6 +91,7 @@ along with GCC; see the file COPYING3. If not see
#include "dbgcnt.h" #include "dbgcnt.h"
#include "tree-inline.h" #include "tree-inline.h"
#include "gimple-pretty-print.h" #include "gimple-pretty-print.h"
#include "ipa-inline.h"
/* Enumeration of all aggregate reductions we can do. */ /* Enumeration of all aggregate reductions we can do. */
enum sra_mode { SRA_MODE_EARLY_IPA, /* early call regularization */ enum sra_mode { SRA_MODE_EARLY_IPA, /* early call regularization */
@ -4469,7 +4470,7 @@ ipa_sra_preliminary_function_checks (struct cgraph_node *node)
} }
if ((DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl)) if ((DECL_COMDAT (node->decl) || DECL_EXTERNAL (node->decl))
&& node->global.size >= MAX_INLINE_INSNS_AUTO) && inline_summary(node)->size >= MAX_INLINE_INSNS_AUTO)
{ {
if (dump_file) if (dump_file)
fprintf (dump_file, "Function too big to be made truly local.\n"); fprintf (dump_file, "Function too big to be made truly local.\n");