* 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
+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>
* config/i386/sse.md (V16): New mode iterator.
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) \
$(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) \
$(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) \
tree-pretty-print.h gimple-pretty-print.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_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) \
$(TREE_H) $(CGRAPH_H) langhooks.h $(DIAGNOSTIC_CORE_H) $(HASHTAB_H) \
$(GGC_H) $(TIMEVAR_H) debug.h $(TARGET_H) output.h $(GIMPLE_H) \
#include "rtl.h"
#include "ipa-utils.h"
#include "lto-streamer.h"
+#include "ipa-inline.h"
const char * const ld_plugin_symbol_resolution_names[]=
{
if (cgraph_nodes)
cgraph_nodes->previous = node;
node->previous = NULL;
- node->global.estimated_growth = INT_MIN;
node->frequency = NODE_FREQUENCY_NORMAL;
node->count_materialization_scale = REG_BR_PROB_BASE;
ipa_empty_ref_list (&node->ref_list);
}
}
-/* 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
parameters of which only CALLEE can be NULL (when creating an indirect call
edge). */
ld_plugin_symbol_resolution_names[(int)node->resolution]);
if (node->local.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)
fprintf (f, " redefined_extern_inline");
if (TREE_ASM_WRITTEN (node->decl))
/* Set once it has been finalized so we consider it to be output. */
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.
This is the case when __builtin_apply_args is used. */
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
redefined now. */
unsigned redefined_extern_inline : 1;
once compilation is finished. Available only with -funit-at-a-time. */
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
inlined into. */
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.
#include "tree-pass.h"
#include "ipa-utils.h"
#include "except.h"
+#include "ipa-inline.h"
/* Context of record_reference. */
struct record_reference_ctx
for (e = node->callers; e; e = e->next_caller)
{
e->callee->global.inlined_to = NULL;
- if (!node->analyzed)
- 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;
+ initialize_inline_failed (e);
}
}
if (flag_keep_inline_functions
&& DECL_DECLARED_INLINE_P (decl)
&& !DECL_EXTERNAL (decl)
- && !lookup_attribute ("always_inline", DECL_ATTRIBUTES (decl)))
+ && !DECL_DISREGARD_INLINE_LIMITS (decl))
return true;
/* If we decided it was needed before, but at the time we didn't have
to change the behavior here. */
if (((TREE_PUBLIC (decl)
|| (!optimize
- && !node->local.disregard_inline_limits
+ && !DECL_DISREGARD_INLINE_LIMITS (decl)
&& !DECL_DECLARED_INLINE_P (decl)
&& !(DECL_CONTEXT (decl)
&& TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_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
function we lower it, which will require gimplified nested
functions, so we can end up here with an already gimplified
/* There are a number of generic reasons functions cannot be versioned. We
also cannot remove parameters if there are type attributes such as fnspec
present. */
- if (!node->local.versionable
+ if (!inline_summary (node)->versionable
|| TYPE_ATTRIBUTES (TREE_TYPE (node->decl)))
return false;
/* Unreachable nodes should have been eliminated before ipcp. */
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);
}
}
static void
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)
<= (unsigned)node->uid)
return;
- memset (inline_summary (node),
- 0, sizeof (inline_summary_t));
+ info = inline_summary (node);
+ info->estimated_growth = INT_MIN;
+ memset (info, 0, sizeof (inline_summary_t));
}
/* Hook that is called by cgraph.c when a node is duplicated. */
inline_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst,
ATTRIBUTE_UNUSED void *data)
{
+ struct inline_summary *info;
inline_summary_alloc ();
- memcpy (inline_summary (dst), inline_summary (src),
+ info = inline_summary (dst);
+ memcpy (info, inline_summary (src),
sizeof (struct inline_summary));
+ info->estimated_growth = INT_MIN;
}
static void
if (node->analyzed)
{
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);
- 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);
- 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",
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",
(int)s->estimated_self_stack_size);
fprintf (f, " global stack: %i\n\n",
- (int)node->global.estimated_stack_size);
+ (int)s->estimated_stack_size);
}
}
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.
0 - means not eliminated
1 - half of statements goes away
{
HOST_WIDE_INT self_stack_size;
struct cgraph_edge *e;
+ struct inline_summary *info;
gcc_assert (!node->global.inlined_to);
inline_summary_alloc ();
+ info = inline_summary (node);
+
/* Estimate the stack size for the function if we're optimizing. */
self_stack_size = optimize ? estimated_stack_frame_size (node) : 0;
- inline_summary (node)->estimated_self_stack_size = self_stack_size;
- node->global.estimated_stack_size = self_stack_size;
- node->global.stack_frame_offset = 0;
+ info->estimated_self_stack_size = self_stack_size;
+ info->estimated_stack_size = self_stack_size;
+ info->stack_frame_offset = 0;
/* Can this function be inlined at all? */
- node->local.inlinable = tree_inlinable_function_p (node->decl);
- if (!node->local.inlinable)
- node->local.disregard_inline_limits = 0;
+ info->inlinable = tree_inlinable_function_p (node->decl);
+ if (!info->inlinable)
+ info->disregard_inline_limits = 0;
/* Inlinable functions always can change signature. */
- if (node->local.inlinable)
+ if (info->inlinable)
node->local.can_change_signature = true;
else
{
estimate_function_body_sizes (node);
/* Inlining characteristics are maintained by the cgraph_mark_inline. */
- node->global.time = inline_summary (node)->self_time;
- node->global.size = inline_summary (node)->self_size;
+ info->time = info->self_time;
+ 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);
}
estimate_edge_time (struct cgraph_edge *edge)
{
int call_stmt_time;
+ struct inline_summary *info = inline_summary (edge->callee);
+
call_stmt_time = edge->call_stmt_time;
gcc_checking_assert (call_stmt_time);
- return (((gcov_type)edge->callee->global.time
- - inline_summary (edge->callee)->time_inlining_benefit
+ return (((gcov_type)info->time
+ - info->time_inlining_benefit
- call_stmt_time) * edge->frequency
+ CGRAPH_FREQ_BASE / 2) / CGRAPH_FREQ_BASE;
}
estimate_time_after_inlining (struct cgraph_node *node,
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)
time = 0;
if (time > MAX_TIME)
estimate_size_after_inlining (struct cgraph_node *node,
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);
return size;
}
int growth = 0;
struct cgraph_edge *e;
bool self_recursive = false;
+ struct inline_summary *info = inline_summary (node);
- if (node->global.estimated_growth != INT_MIN)
- return node->global.estimated_growth;
+ if (info->estimated_growth != INT_MIN)
+ return info->estimated_growth;
for (e = node->callers; e; e = e->next_caller)
{
some inlining. */
if (cgraph_will_be_removed_from_program_if_no_direct_calls (node)
&& !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
come from various template instantiations. Take this into account. */
else if (DECL_COMDAT (node->decl) && !self_recursive
&& 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;
- node->global.estimated_growth = growth;
+ info->estimated_growth = growth;
return growth;
}
struct cgraph_node *node;
struct inline_summary *info;
lto_cgraph_encoder_t encoder;
+ struct bitpack_d bp;
index = lto_input_uleb128 (ib);
encoder = file_data->cgraph_node_encoder;
node = lto_cgraph_encoder_deref (encoder, index);
info = inline_summary (node);
- node->global.estimated_stack_size
+ info->estimated_stack_size
= 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);
- 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);
- 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,
if (node->analyzed)
{
struct inline_summary *info = inline_summary (node);
+ struct bitpack_d bp;
+
lto_output_uleb128_stream (ob->main_stream,
lto_cgraph_encoder_encode (encoder, node));
lto_output_sleb128_stream (ob->main_stream,
info->self_time);
lto_output_sleb128_stream (ob->main_stream,
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);
bool update_original)
{
HOST_WIDE_INT peak;
+ struct inline_summary *caller_info, *callee_info;
if (duplicate)
{
gcc_assert (!e->callee->global.inlined_to);
if (e->callee->analyzed && !DECL_EXTERNAL (e->callee->decl))
{
- overall_size -= e->callee->global.size;
+ overall_size -= inline_summary (e->callee)->size;
nfunctions_inlined++;
}
duplicate = false;
}
}
+ callee_info = inline_summary (e->callee);
+ caller_info = inline_summary (e->caller);
+
if (e->caller->global.inlined_to)
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
- + inline_summary (e->caller)->estimated_self_stack_size;
- peak = e->callee->global.stack_frame_offset
- + inline_summary (e->callee)->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;
+ callee_info->stack_frame_offset
+ = caller_info->stack_frame_offset
+ + caller_info->estimated_self_stack_size;
+ peak = callee_info->stack_frame_offset
+ + callee_info->estimated_self_stack_size;
+ if (inline_summary (e->callee->global.inlined_to)->estimated_stack_size < peak)
+ inline_summary (e->callee->global.inlined_to)->estimated_stack_size = peak;
cgraph_propagate_frequency (e->callee);
/* Recursively clone all bodies. */
int old_size = 0, new_size = 0;
struct cgraph_node *to = NULL;
struct cgraph_edge *curr = e;
+ struct inline_summary *info;
/* Don't inline inlined edges. */
gcc_assert (e->inline_failed);
for (;e && !e->inline_failed; e = e->caller->callers)
{
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);
- to->global.size = new_size;
- to->global.time = estimate_time_after_inlining (to, curr);
+ info->size = new_size;
+ info->time = estimate_time_after_inlining (to, curr);
}
gcc_assert (curr->callee->global.inlined_to == to);
if (new_size > old_size)
int newsize;
int limit;
HOST_WIDE_INT stack_size_limit, inlined_stack;
+ struct inline_summary *info, *what_info;
if (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,
take the inlined function as base for limiting the growth. */
- if (inline_summary (to)->self_size > inline_summary(what)->self_size)
- limit = inline_summary (to)->self_size;
+ if (info->self_size > what_info->self_size)
+ limit = info->self_size;
else
- limit = inline_summary (what)->self_size;
+ limit = what_info->self_size;
limit += limit * PARAM_VALUE (PARAM_LARGE_FUNCTION_GROWTH) / 100;
/* Check the size after inlining against the function limits. But allow
the function to shrink if it went over the limits by forced inlining. */
newsize = estimate_size_after_inlining (to, e);
- if (newsize >= to->global.size
+ if (newsize >= info->size
&& newsize > PARAM_VALUE (PARAM_LARGE_FUNCTION_INSNS)
&& newsize > limit)
{
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;
- inlined_stack = (to->global.stack_frame_offset
- + inline_summary (to)->estimated_self_stack_size
- + what->global.estimated_stack_size);
+ inlined_stack = (info->stack_frame_offset
+ + info->estimated_self_stack_size
+ + what_info->estimated_stack_size);
if (inlined_stack > stack_size_limit
&& inlined_stack > PARAM_VALUE (PARAM_LARGE_STACK_FRAME))
{
cgraph_default_inline_p (struct cgraph_node *n, cgraph_inline_failed_t *reason)
{
tree decl = n->decl;
+ struct inline_summary *info = inline_summary (n);
- if (n->local.disregard_inline_limits)
+ if (info->disregard_inline_limits)
return true;
if (!flag_inline_small_functions && !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)
*reason = CIF_MAX_INLINE_INSNS_SINGLE_LIMIT;
}
else
{
- if (n->global.size >= MAX_INLINE_INSNS_AUTO)
+ if (info->size >= MAX_INLINE_INSNS_AUTO)
{
if (reason)
*reason = CIF_MAX_INLINE_INSNS_AUTO_LIMIT;
{
gcov_type badness;
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;
growth = estimate_edge_growth (edge);
cgraph_node_name (edge->callee));
fprintf (dump_file, " growth %i, time %i-%i, size %i-%i\n",
growth,
- edge->callee->global.time,
- inline_summary (edge->callee)->time_inlining_benefit
+ callee_info->time,
+ callee_info->time_inlining_benefit
+ edge->call_stmt_time,
- edge->callee->global.size,
- inline_summary (edge->callee)->size_inlining_benefit
+ callee_info->size,
+ callee_info->size_inlining_benefit
+ edge->call_stmt_size);
}
badness =
((int)
((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;
if (dump)
{
int growth_for_all;
badness = growth * 10000;
benefitperc =
- 100 * (inline_summary (edge->callee)->time_inlining_benefit
+ 100 * (callee_info->time_inlining_benefit
+ edge->call_stmt_time)
- / (edge->callee->global.time + 1) + 1;
+ / (callee_info->time + 1) + 1;
benefitperc = MIN (benefitperc, 100);
div *= benefitperc;
struct cgraph_edge *edge;
cgraph_inline_failed_t failed_reason;
- if (!node->local.inlinable
+ if (!inline_summary (node)->inlinable
|| cgraph_function_body_availability (node) <= AVAIL_OVERWRITABLE
|| node->global.inlined_to)
return;
if (!bitmap_set_bit (updated_nodes, node->uid))
return;
- node->global.estimated_growth = INT_MIN;
+ inline_summary (node)->estimated_growth = INT_MIN;
/* See if there is something to do. */
for (edge = node->callers; edge; edge = edge->next_caller)
bitmap updated_nodes)
{
struct cgraph_edge *e = node->callees;
- node->global.estimated_growth = INT_MIN;
+ inline_summary (node)->estimated_growth = INT_MIN;
if (!e)
return;
else
{
if (e->inline_failed
- && e->callee->local.inlinable
+ && inline_summary (e->callee)->inlinable
&& cgraph_function_body_availability (e->callee) >= AVAIL_AVAILABLE
&& !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 (!cgraph_default_inline_p (e->callee, &e->inline_failed))
update_caller_keys (heap, e->callee, updated_nodes);
bitmap updated_nodes)
{
struct cgraph_edge *e = node->callees;
- node->global.estimated_growth = INT_MIN;
+ inline_summary (node)->estimated_growth = INT_MIN;
if (!e)
return;
/* It does not make sense to recursively inline always-inline functions
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)))
return false;
if (dump_file)
fprintf (dump_file,
"\n Inlined %i times, body grown from size %i to %i, time %i to %i\n", n,
- master_clone->global.size, node->global.size,
- master_clone->global.time, node->global.time);
+ inline_summary (master_clone)->size, inline_summary (node)->size,
+ inline_summary (master_clone)->time, inline_summary (node)->time);
/* 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
struct cgraph_edge *edge = VEC_pop (cgraph_edge_p, new_edges);
gcc_assert (!edge->aux);
- if (edge->callee->local.inlinable
+ if (inline_summary (edge->callee)->inlinable
&& edge->inline_failed
&& cgraph_default_inline_p (edge->callee, &edge->inline_failed))
edge->aux = fibheap_insert (heap, cgraph_edge_badness (edge, false), edge);
/* Put all inline candidates into the heap. */
for (node = cgraph_nodes; node; node = node->next)
- {
- if (!node->local.inlinable || !node->callers)
- continue;
- if (dump_file)
- fprintf (dump_file, "Considering inline candidate %s.\n", cgraph_node_name (node));
+ if (node->analyzed)
+ {
+ struct inline_summary *info = inline_summary (node);
- node->global.estimated_growth = INT_MIN;
- if (!cgraph_default_inline_p (node, &failed_reason))
- {
- cgraph_set_inline_failed (node, failed_reason);
- continue;
- }
+ if (!info->inlinable || !node->callers)
+ {
+ struct cgraph_edge *e;
+ 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));
- for (edge = node->callers; edge; edge = edge->next_caller)
- if (edge->inline_failed)
+ info->estimated_growth = INT_MIN;
+ if (!cgraph_default_inline_p (node, &failed_reason))
{
- gcc_assert (!edge->aux);
- edge->aux = fibheap_insert (heap, cgraph_edge_badness (edge, false), edge);
+ 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);
min_size = overall_size;
fprintf (dump_file,
"\nConsidering %s with %i size\n",
cgraph_node_name (edge->callee),
- edge->callee->global.size);
+ inline_summary (edge->callee)->size);
fprintf (dump_file,
" to be inlined into %s in %s:%i\n"
" Estimated growth after inlined into all callees is %+i insns.\n"
if (where->global.inlined_to)
{
edge->inline_failed
- = (edge->callee->local.disregard_inline_limits
+ = (inline_summary (edge->callee)->disregard_inline_limits
? CIF_RECURSIVE_INLINING : CIF_UNSPECIFIED);
if (dump_file)
fprintf (dump_file, " inline_failed:Recursive inlining performed only for function itself.\n");
}
}
- if (edge->callee->local.disregard_inline_limits)
+ if (inline_summary (edge->callee)->disregard_inline_limits)
;
else if (!cgraph_maybe_hot_edge_p (edge))
not_good = CIF_UNLIKELY_CALL;
" Inlined into %s which now has time %i and size %i,"
"net change of %+i.\n",
cgraph_node_name (edge->caller),
- edge->caller->global.time,
- edge->caller->global.size,
+ inline_summary (edge->caller)->time,
+ inline_summary (edge->caller)->size,
overall_size - old_size);
}
if (min_size > overall_size)
fprintf (dump_file,
"\nSkipping %s with %i size\n",
cgraph_node_name (edge->callee),
- edge->callee->global.size);
+ inline_summary (edge->callee)->size);
fprintf (dump_file,
" called by %s in %s:%i\n"
" Estimated growth after inlined into all callees is %+i insns.\n"
if (dump_flags & TDF_DETAILS)
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;
}
if (node->analyzed)
{
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))
- initial_size += node->global.size;
+ initial_size += info->size;
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);
if (max_count < e->count)
max_count = e->count;
&& !node->callers->next_caller
&& !node->global.inlined_to
&& 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
&& node->callers->inline_failed
&& node->callers->caller != node
{
fprintf (dump_file,
"\nConsidering %s size %i.\n",
- cgraph_node_name (node), node->global.size);
+ cgraph_node_name (node), inline_summary (node)->size);
fprintf (dump_file,
" Called once from %s %i insns.\n",
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))
" Inlined into %s which now has %i size"
" for a net change of %+i size.\n",
cgraph_node_name (caller),
- caller->global.size,
+ inline_summary (caller)->size,
overall_size - old_size);
}
else
static bool
cgraph_edge_early_inlinable_p (struct cgraph_edge *e, FILE *file)
{
- if (!e->callee->local.inlinable)
+ if (!inline_summary (e->callee)->inlinable)
{
if (file)
fprintf (file, "Not inlining: Function not inlinable.\n");
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;
if (dump_file)
/* Never inline regular functions into always-inline functions
during incremental inlining. */
- if (node->local.disregard_inline_limits)
+ if (inline_summary (node)->disregard_inline_limits)
return false;
for (e = node->callees; e; e = e->next_callee)
{
int allowed_growth = 0;
- if (!e->callee->local.inlinable
+ if (!inline_summary (e->callee)->inlinable
|| !e->inline_failed
- || e->callee->local.disregard_inline_limits)
+ || inline_summary (e->callee)->disregard_inline_limits)
continue;
/* Do not consider functions not declared inline. */
struct inline_summary
{
+ /* Information about the function body itself. */
+
/* Estimated stack frame consumption by the function. */
HOST_WIDE_INT estimated_self_stack_size;
-
/* Size of the function body. */
int self_size;
/* How many instructions are likely going to disappear after inlining. */
int self_time;
/* How much time is going to be saved by inlining. */
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;
void inline_read_summary (void);
void inline_write_summary (cgraph_node_set, varpool_node_set);
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_size_after_inlining (struct cgraph_node *, struct cgraph_edge *);
int estimate_growth (struct cgraph_node *);
estimate_edge_growth (struct cgraph_edge *edge)
{
int call_stmt_size;
+ struct inline_summary *info = inline_summary (edge->callee);
call_stmt_size = edge->call_stmt_size;
gcc_checking_assert (call_stmt_size);
- return (edge->callee->global.size
- - inline_summary (edge->callee)->size_inlining_benefit
+ return (info->size
+ - info->size_inlining_benefit
- call_stmt_size);
}
-
#include "fibheap.h"
#include "params.h"
#include "gimple-pretty-print.h"
+#include "ipa-inline.h"
/* Per basic block info. */
}
/* This can be relaxed; function might become inlinable after splitting
away the uninlinable part. */
- if (!node->local.inlinable)
+ if (!inline_summary (node)->inlinable)
{
if (dump_file)
fprintf (dump_file, "Not splitting: not inlinable.\n");
return 0;
}
- if (node->local.disregard_inline_limits)
+ if (DECL_DISREGARD_INLINE_LIMITS (node->decl))
{
if (dump_file)
fprintf (dump_file, "Not splitting: disregarding inline limits.\n");
/* Break possible cycles involving always-inline
functions by ignoring edges from always-inline
functions to non-always-inline functions. */
- if (edge->caller->local.disregard_inline_limits
- && !edge->callee->local.disregard_inline_limits)
+ if (DECL_DISREGARD_INLINE_LIMITS (edge->caller->decl)
+ && !DECL_DISREGARD_INLINE_LIMITS (edge->callee->decl))
continue;
if (!edge->caller->aux)
{
cgraph_node_remove_callees (node);
ipa_remove_all_references (&node->ref_list);
node->analyzed = false;
- node->local.inlinable = false;
}
if (!node->aux)
{
if (!clone)
{
cgraph_release_function_body (node);
- node->local.inlinable = false;
if (node->prev_sibling_clone)
node->prev_sibling_clone->next_sibling_clone = node->next_sibling_clone;
else if (node->clone_of)
if (DECL_STATIC_DESTRUCTOR (node->decl))
VEC_safe_push (tree, heap, static_dtors, 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
bp_pack_value (&bp, node->local.local, 1);
bp_pack_value (&bp, node->local.externally_visible, 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.disregard_inline_limits, 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->needed, 1);
node->local.local = bp_unpack_value (bp, 1);
node->local.externally_visible = 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.disregard_inline_limits = 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->needed = bp_unpack_value (bp, 1);
+2011-04-16 Jan Hubicka <jh@suse.cz>
+
+ * lto.c (lto_balanced_map): Update.
+
2011-04-14 Jan Hubicka <jh@suse.cz>
* lto.c: Include ipa-inline.h
if (partition_cgraph_node_p (node))
{
order[n_nodes++] = node;
- total_size += node->global.size;
+ total_size += inline_summary (node)->size;
}
}
free (postorder);
{
if (!order[i]->aux)
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
all referenced variables unless they was already added into some
#include "dbgcnt.h"
#include "tree-inline.h"
#include "gimple-pretty-print.h"
+#include "ipa-inline.h"
/* Enumeration of all aggregate reductions we can do. */
enum sra_mode { SRA_MODE_EARLY_IPA, /* early call regularization */
}
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)
fprintf (dump_file, "Function too big to be made truly local.\n");