diff options
author | Jan Hubicka <jh@suse.cz> | 2011-04-14 15:26:44 +0200 |
---|---|---|
committer | Jan Hubicka <hubicka@gcc.gnu.org> | 2011-04-14 13:26:44 +0000 |
commit | 10a5dd5d3d4cc53613b8e44b78e99b7d61f85d77 (patch) | |
tree | eb6e4c913e14b3874133c0765b5a7b51b8c55868 /gcc/ipa-inline-analysis.c | |
parent | b602d918bc8a134e29e065c38776ecf1a382e932 (diff) | |
download | gcc-10a5dd5d3d4cc53613b8e44b78e99b7d61f85d77.zip gcc-10a5dd5d3d4cc53613b8e44b78e99b7d61f85d77.tar.gz gcc-10a5dd5d3d4cc53613b8e44b78e99b7d61f85d77.tar.bz2 |
cgraph.c (dump_cgraph_node): Do not dump inline summaries.
* cgraph.c (dump_cgraph_node): Do not dump inline summaries.
* cgraph.h (struct inline_summary): Move to ipa-inline.h
(cgraph_local_info): Remove inline_summary.
* ipa-cp.c: Include ipa-inline.h.
(ipcp_cloning_candidate_p, ipcp_estimate_growth,
ipcp_estimate_cloning_cost, ipcp_insert_stage): Use inline_summary
accesor.
* lto-cgraph.c (lto_output_node): Do not stream inline summary.
(input_overwrite_node): Do not set inline summary.
(input_node): Do not stream inline summary.
* ipa-inline.c (cgraph_decide_inlining): Dump inline summaries.
(cgraph_decide_inlining_incrementally): Do not try to estimate overall
growth; we do not have inline parameters computed for that anyway.
(cgraph_early_inlining): After inlining compute call_stmt_sizes.
* ipa-inline.h (struct inline_summary): Move here from ipa-inline.h
(inline_summary_t): New type and VECtor.
(debug_inline_summary, dump_inline_summaries): Declare.
(inline_summary): Use VOCtor.
(estimate_edge_growth): Kill hack computing call stmt size directly.
* lto-section-in.c (lto_section_name): Add inline section.
* ipa-inline-analysis.c: Include lto-streamer.h
(node_removal_hook_holder, node_duplication_hook_holder): New holders
(inline_node_removal_hook, inline_node_duplication_hook): New functions.
(inline_summary_vec): Define.
(inline_summary_alloc, dump_inline_summary, debug_inline_summary,
dump_inline_summaries): New functions.
(estimate_function_body_sizes): Properly compute size/time of outgoing calls.
(compute_inline_parameters): Alloc inline_summary; do not compute size/time
of incomming calls.
(estimate_edge_time): Avoid missing time summary hack.
(inline_read_summary): Read inline summary info.
(inline_write_summary): Write inline summary info.
(inline_free_summary): Free all hooks and inline summary vector.
* lto-streamer.h: Add LTO_section_inline_summary section.
* Makefile.in (ipa-cp.o, ipa-inline-analysis.o): Update dependencies.
* ipa.c (cgraph_remove_unreachable_nodes): Fix dump file formating.
* lto.c: Include ipa-inline.h
(add_cgraph_node_to_partition, undo_partition): Use inline_summary accessor.
(ipa_node_duplication_hook): Fix declaration.
* Make-lang.in (lto.o): Update dependencies.
From-SVN: r172430
Diffstat (limited to 'gcc/ipa-inline-analysis.c')
-rw-r--r-- | gcc/ipa-inline-analysis.c | 227 |
1 files changed, 204 insertions, 23 deletions
diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c index 8507c5e..47bd2a8 100644 --- a/gcc/ipa-inline-analysis.c +++ b/gcc/ipa-inline-analysis.c @@ -23,13 +23,13 @@ along with GCC; see the file COPYING3. If not see We estimate for each function - function body size - - function runtime + - average function execution time - inlining size benefit (that is how much of function body size and its call sequence is expected to disappear by inlining) - inlining time benefit - function frame size For each call - - call sequence size + - call statement size and time inlinie_summary datastructures store above information locally (i.e. parameters of the function itself) and globally (i.e. parameters of @@ -61,12 +61,99 @@ along with GCC; see the file COPYING3. If not see #include "ggc.h" #include "tree-flow.h" #include "ipa-prop.h" +#include "lto-streamer.h" #include "ipa-inline.h" #define MAX_TIME 1000000000 /* Holders of ipa cgraph hooks: */ static struct cgraph_node_hook_list *function_insertion_hook_holder; +static struct cgraph_node_hook_list *node_removal_hook_holder; +static struct cgraph_2node_hook_list *node_duplication_hook_holder; +static void inline_node_removal_hook (struct cgraph_node *, void *); +static void inline_node_duplication_hook (struct cgraph_node *, + struct cgraph_node *, void *); + +/* VECtor holding inline summaries. */ +VEC(inline_summary_t,heap) *inline_summary_vec; + +/* Allocate the inline summary vector or resize it to cover all cgraph nodes. */ + +static void +inline_summary_alloc (void) +{ + if (!node_removal_hook_holder) + node_removal_hook_holder = + cgraph_add_node_removal_hook (&inline_node_removal_hook, NULL); + if (!node_duplication_hook_holder) + node_duplication_hook_holder = + cgraph_add_node_duplication_hook (&inline_node_duplication_hook, NULL); + + if (VEC_length (inline_summary_t, inline_summary_vec) + <= (unsigned) cgraph_max_uid) + VEC_safe_grow_cleared (inline_summary_t, heap, + inline_summary_vec, cgraph_max_uid + 1); +} + +/* Hook that is called by cgraph.c when a node is removed. */ + +static void +inline_node_removal_hook (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED) +{ + if (VEC_length (inline_summary_t, inline_summary_vec) + <= (unsigned)node->uid) + return; + memset (inline_summary (node), + 0, sizeof (inline_summary_t)); +} + +/* Hook that is called by cgraph.c when a node is duplicated. */ + +static void +inline_node_duplication_hook (struct cgraph_node *src, struct cgraph_node *dst, + ATTRIBUTE_UNUSED void *data) +{ + inline_summary_alloc (); + memcpy (inline_summary (dst), inline_summary (src), + sizeof (struct inline_summary)); +} + +static void +dump_inline_summary (FILE *f, struct cgraph_node *node) +{ + if (node->analyzed) + { + struct inline_summary *s = inline_summary (node); + fprintf (f, "Inline summary for %s/%i\n", cgraph_node_name (node), + node->uid); + fprintf (f, " self time: %i, benefit: %i\n", + s->self_time, s->time_inlining_benefit); + fprintf (f, " global time: %i\n", node->global.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, " self stack: %i\n", + (int)s->estimated_self_stack_size); + fprintf (f, " global stack: %i\n\n", + (int)node->global.estimated_stack_size); + } +} + +void +debug_inline_summary (struct cgraph_node *node) +{ + dump_inline_summary (stderr, node); +} + +void +dump_inline_summaries (FILE *f) +{ + struct cgraph_node *node; + + for (node = cgraph_nodes; node; node = node->next) + if (node->analyzed) + dump_inline_summary (f, node); +} /* See if statement might disappear after inlining. 0 - means not eliminated @@ -179,16 +266,27 @@ estimate_function_body_sizes (struct cgraph_node *node) freq, this_size, this_time); print_gimple_stmt (dump_file, stmt, 0, 0); } + + if (is_gimple_call (stmt)) + { + struct cgraph_edge *edge = cgraph_edge (node, stmt); + edge->call_stmt_size = this_size; + edge->call_stmt_time = this_time; + } + this_time *= freq; time += this_time; size += this_size; + prob = eliminated_by_inlining_prob (stmt); if (prob == 1 && dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " 50%% will be eliminated by inlining\n"); if (prob == 2 && dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " will eliminated by inlining\n"); + size_inlining_benefit += this_size * prob; time_inlining_benefit += this_time * prob; + gcc_assert (time >= 0); gcc_assert (size >= 0); } @@ -222,6 +320,8 @@ compute_inline_parameters (struct cgraph_node *node) gcc_assert (!node->global.inlined_to); + inline_summary_alloc (); + /* 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; @@ -247,17 +347,7 @@ compute_inline_parameters (struct cgraph_node *node) node->local.can_change_signature = !e; } estimate_function_body_sizes (node); - /* Compute size of call statements. We have to do this for callers here, - those sizes need to be present for edges _to_ us as early as - we are finished with early opts. */ - for (e = node->callers; e; e = e->next_caller) - if (e->call_stmt) - { - e->call_stmt_size - = estimate_num_insns (e->call_stmt, &eni_size_weights); - e->call_stmt_time - = estimate_num_insns (e->call_stmt, &eni_time_weights); - } + /* 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; @@ -300,12 +390,8 @@ static inline int estimate_edge_time (struct cgraph_edge *edge) { int call_stmt_time; - /* ??? We throw away cgraph edges all the time so the information - we store in edges doesn't persist for early inlining. Ugh. */ - if (!edge->call_stmt) - call_stmt_time = edge->call_stmt_time; - else - call_stmt_time = estimate_num_insns (edge->call_stmt, &eni_time_weights); + 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 - call_stmt_time) * edge->frequency @@ -333,7 +419,7 @@ estimate_time_after_inlining (struct cgraph_node *node, int 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); gcc_assert (size >= 0); @@ -379,8 +465,10 @@ estimate_growth (struct cgraph_node *node) return growth; } + /* This function performs intraprocedural analysis in NODE that is required to inline indirect calls. */ + static void inline_indirect_intraprocedural_analysis (struct cgraph_node *node) { @@ -437,8 +525,6 @@ inline_generate_summary (void) for (node = cgraph_nodes; node; node = node->next) if (node->analyzed) inline_analyze_function (node); - - return; } @@ -449,6 +535,57 @@ inline_generate_summary (void) void inline_read_summary (void) { + struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data (); + struct lto_file_decl_data *file_data; + unsigned int j = 0; + + inline_summary_alloc (); + + while ((file_data = file_data_vec[j++])) + { + size_t len; + const char *data = lto_get_section_data (file_data, LTO_section_inline_summary, NULL, &len); + + struct lto_input_block *ib + = lto_create_simple_input_block (file_data, + LTO_section_inline_summary, + &data, &len); + if (ib) + { + unsigned int i; + unsigned int f_count = lto_input_uleb128 (ib); + + for (i = 0; i < f_count; i++) + { + unsigned int index; + struct cgraph_node *node; + struct inline_summary *info; + lto_cgraph_encoder_t encoder; + + 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_self_stack_size = lto_input_uleb128 (ib); + node->global.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_inlining_benefit = lto_input_uleb128 (ib); + node->global.estimated_growth = INT_MIN; + } + + lto_destroy_simple_input_block (file_data, + LTO_section_inline_summary, + ib, data, len); + } + else + /* Fatal error here. We do not want to support compiling ltrans units with + different version of compiler or different flags than the WPA unit, so + this should never happen. */ + fatal_error ("ipa inline summary is missing in input file"); + } if (flag_indirect_inlining) { ipa_register_cgraph_hooks (); @@ -468,14 +605,58 @@ void inline_write_summary (cgraph_node_set set, varpool_node_set vset ATTRIBUTE_UNUSED) { + struct cgraph_node *node; + struct lto_simple_output_block *ob + = lto_create_simple_output_block (LTO_section_inline_summary); + lto_cgraph_encoder_t encoder = ob->decl_state->cgraph_node_encoder; + unsigned int count = 0; + int i; + + for (i = 0; i < lto_cgraph_encoder_size (encoder); i++) + if (lto_cgraph_encoder_deref (encoder, i)->analyzed) + count++; + lto_output_uleb128_stream (ob->main_stream, count); + + for (i = 0; i < lto_cgraph_encoder_size (encoder); i++) + { + node = lto_cgraph_encoder_deref (encoder, i); + if (node->analyzed) + { + struct inline_summary *info = inline_summary (node); + lto_output_uleb128_stream (ob->main_stream, + lto_cgraph_encoder_encode (encoder, node)); + lto_output_sleb128_stream (ob->main_stream, + info->estimated_self_stack_size); + lto_output_sleb128_stream (ob->main_stream, + info->self_size); + lto_output_sleb128_stream (ob->main_stream, + info->size_inlining_benefit); + lto_output_sleb128_stream (ob->main_stream, + info->self_time); + lto_output_sleb128_stream (ob->main_stream, + info->time_inlining_benefit); + } + } + lto_destroy_simple_output_block (ob); + if (flag_indirect_inlining && !flag_ipa_cp) ipa_prop_write_jump_functions (set); } + /* Release inline summary. */ void inline_free_summary (void) { - cgraph_remove_function_insertion_hook (function_insertion_hook_holder); + if (function_insertion_hook_holder) + cgraph_remove_function_insertion_hook (function_insertion_hook_holder); + function_insertion_hook_holder = NULL; + if (node_removal_hook_holder) + cgraph_remove_node_removal_hook (node_removal_hook_holder); + node_removal_hook_holder = NULL; + if (node_duplication_hook_holder) + cgraph_remove_node_duplication_hook (node_duplication_hook_holder); + node_duplication_hook_holder = NULL; + VEC_free (inline_summary_t, heap, inline_summary_vec); } |