X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Flto-cgraph.c;h=e3deb9c8b06b1b8b2dc696ae09b0c04c5c3d3672;hp=14916473640c7a99bdbeb83871850e103300f774;hb=9a5fddda997a4f6bfe006628d28b792b445ee6d0;hpb=90f477a9d799a42f20bdcf872c8e0527133d0033 diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c index 14916473640..e3deb9c8b06 100644 --- a/gcc/lto-cgraph.c +++ b/gcc/lto-cgraph.c @@ -45,6 +45,7 @@ along with GCC; see the file COPYING3. If not see #include "output.h" #include "pointer-set.h" #include "lto-streamer.h" +#include "gcov-io.h" /* Create a new cgraph encoder. */ @@ -79,7 +80,7 @@ lto_cgraph_encoder_encode (lto_cgraph_encoder_t encoder, { int ref; void **slot; - + slot = pointer_map_contains (encoder->map, node); if (!slot) { @@ -115,7 +116,7 @@ lto_cgraph_encoder_deref (lto_cgraph_encoder_t encoder, int ref) if (ref == LCC_NOT_FOUND) return NULL; - return VEC_index (cgraph_node_ptr, encoder->nodes, ref); + return VEC_index (cgraph_node_ptr, encoder->nodes, ref); } @@ -141,11 +142,11 @@ lto_output_edge (struct lto_simple_output_block *ob, struct cgraph_edge *edge, lto_output_uleb128_stream (ob->main_stream, LTO_cgraph_edge); ref = lto_cgraph_encoder_lookup (encoder, edge->caller); - gcc_assert (ref != LCC_NOT_FOUND); + gcc_assert (ref != LCC_NOT_FOUND); lto_output_sleb128_stream (ob->main_stream, ref); ref = lto_cgraph_encoder_lookup (encoder, edge->callee); - gcc_assert (ref != LCC_NOT_FOUND); + gcc_assert (ref != LCC_NOT_FOUND); lto_output_sleb128_stream (ob->main_stream, ref); lto_output_sleb128_stream (ob->main_stream, edge->count); @@ -196,15 +197,15 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, case AVAIL_LOCAL: tag = LTO_cgraph_avail_node; break; - + case AVAIL_OVERWRITABLE: tag = LTO_cgraph_overwritable_node; break; - + default: gcc_unreachable (); } - + if (boundary_p) tag = LTO_cgraph_unavail_node; @@ -220,13 +221,15 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, Boundary nodes: There are nodes that are not part of SET but are called from within SET. We artificially make them look like - externally visible nodes with no function body. + externally visible nodes with no function body. Cherry-picked nodes: These are nodes we pulled from other translation units into SET during IPA-inlining. We make them as local static nodes to prevent clashes with other local statics. */ if (boundary_p) { + /* Inline clones can not be part of boundary. */ + gcc_assert (!node->global.inlined_to); local = 0; externally_visible = 1; inlinable = 0; @@ -270,15 +273,15 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, if (tag != LTO_cgraph_unavail_node) { - lto_output_sleb128_stream (ob->main_stream, + lto_output_sleb128_stream (ob->main_stream, node->local.inline_summary.estimated_self_stack_size); - lto_output_sleb128_stream (ob->main_stream, + lto_output_sleb128_stream (ob->main_stream, node->local.inline_summary.self_size); - lto_output_sleb128_stream (ob->main_stream, + lto_output_sleb128_stream (ob->main_stream, node->local.inline_summary.size_inlining_benefit); - lto_output_sleb128_stream (ob->main_stream, + lto_output_sleb128_stream (ob->main_stream, node->local.inline_summary.self_time); - lto_output_sleb128_stream (ob->main_stream, + lto_output_sleb128_stream (ob->main_stream, node->local.inline_summary.time_inlining_benefit); } @@ -303,6 +306,69 @@ lto_output_node (struct lto_simple_output_block *ob, struct cgraph_node *node, lto_output_sleb128_stream (ob->main_stream, node->global.estimated_growth); lto_output_uleb128_stream (ob->main_stream, node->global.inlined); + if (node->same_comdat_group) + { + ref = lto_cgraph_encoder_lookup (encoder, node->same_comdat_group); + gcc_assert (ref != LCC_NOT_FOUND); + } + else + ref = LCC_NOT_FOUND; + lto_output_sleb128_stream (ob->main_stream, ref); + + if (node->same_body) + { + struct cgraph_node *alias; + unsigned long alias_count = 1; + for (alias = node->same_body; alias->next; alias = alias->next) + alias_count++; + lto_output_uleb128_stream (ob->main_stream, alias_count); + do + { + lto_output_fn_decl_index (ob->decl_state, ob->main_stream, + alias->decl); + if (alias->thunk.thunk_p) + { + lto_output_uleb128_stream + (ob->main_stream, + 1 + (alias->thunk.this_adjusting != 0) * 2 + + (alias->thunk.virtual_offset_p != 0) * 4); + lto_output_uleb128_stream (ob->main_stream, + alias->thunk.fixed_offset); + lto_output_uleb128_stream (ob->main_stream, + alias->thunk.virtual_value); + lto_output_fn_decl_index (ob->decl_state, ob->main_stream, + alias->thunk.alias); + } + else + { + lto_output_uleb128_stream (ob->main_stream, 0); + lto_output_fn_decl_index (ob->decl_state, ob->main_stream, + alias->thunk.alias); + } + alias = alias->previous; + } + while (alias); + } + else + lto_output_uleb128_stream (ob->main_stream, 0); +} + +/* Stream out profile_summary to OB. */ + +static void +output_profile_summary (struct lto_simple_output_block *ob) +{ + if (profile_info) + { + /* We do not output num, it is not terribly useful. */ + gcc_assert (profile_info->runs); + lto_output_uleb128_stream (ob->main_stream, profile_info->runs); + lto_output_sleb128_stream (ob->main_stream, profile_info->sum_all); + lto_output_sleb128_stream (ob->main_stream, profile_info->run_max); + lto_output_sleb128_stream (ob->main_stream, profile_info->sum_max); + } + else + lto_output_uleb128_stream (ob->main_stream, 0); } @@ -322,6 +388,8 @@ output_cgraph (cgraph_node_set set) ob = lto_create_simple_output_block (LTO_section_cgraph); + output_profile_summary (ob); + /* An encoder for cgraph nodes should have been created by ipa_write_summaries_1. */ gcc_assert (ob->decl_state->cgraph_node_encoder); @@ -352,8 +420,30 @@ output_cgraph (cgraph_node_set set) /* We should have moved all the inlines. */ gcc_assert (!callee->global.inlined_to); lto_cgraph_encoder_encode (encoder, callee); + /* Also with each included function include all other functions + in the same comdat group. */ + if (callee->same_comdat_group) + { + struct cgraph_node *next; + for (next = callee->same_comdat_group; + next != callee; + next = next->same_comdat_group) + if (!cgraph_node_in_set_p (next, set)) + lto_cgraph_encoder_encode (encoder, next); + } } } + /* Also with each included function include all other functions + in the same comdat group. */ + if (node->same_comdat_group) + { + struct cgraph_node *next; + for (next = node->same_comdat_group; + next != node; + next = next->same_comdat_group) + if (!cgraph_node_in_set_p (next, set)) + lto_cgraph_encoder_encode (encoder, next); + } } /* Write out the nodes. */ @@ -370,8 +460,16 @@ output_cgraph (cgraph_node_set set) for (csi = csi_start (set); !csi_end_p (csi); csi_next (&csi)) { node = csi_node (csi); - for (edge = node->callees; edge; edge = edge->next_callee) - lto_output_edge (ob, edge, encoder); + if (node->callees) + { + /* Output edges in backward direction, so the reconstructed callgraph + match and it is easy to associate call sites in the IPA pass summaries. */ + edge = node->callees; + while (edge->next_callee) + edge = edge->next_callee; + for (; edge; edge = edge->prev_callee) + lto_output_edge (ob, edge, encoder); + } } lto_output_uleb128_stream (ob->main_stream, 0); @@ -440,9 +538,9 @@ input_overwrite_node (struct lto_file_decl_data *file_data, } -/* Read a node from input_block IB. TAG is the node's tag just read. +/* Read a node from input_block IB. TAG is the node's tag just read. Return the node read or overwriten. */ - + static struct cgraph_node * input_node (struct lto_file_decl_data *file_data, struct lto_input_block *ib, @@ -456,7 +554,7 @@ input_node (struct lto_file_decl_data *file_data, bool clone_p; int estimated_stack_size = 0; int stack_frame_offset = 0; - int ref = LCC_NOT_FOUND; + int ref = LCC_NOT_FOUND, ref2 = LCC_NOT_FOUND; int estimated_growth = 0; int time = 0; int size = 0; @@ -464,6 +562,7 @@ input_node (struct lto_file_decl_data *file_data, int self_size = 0; int time_inlining_benefit = 0; int size_inlining_benefit = 0; + unsigned long same_body_count = 0; bool inlined = false; clone_p = (lto_input_uleb128 (ib) != 0); @@ -480,7 +579,7 @@ input_node (struct lto_file_decl_data *file_data, node->count = lto_input_sleb128 (ib); bp = lto_input_bitpack (ib); - + if (tag != LTO_cgraph_unavail_node) { stack_size = lto_input_sleb128 (ib); @@ -497,6 +596,8 @@ input_node (struct lto_file_decl_data *file_data, size = lto_input_sleb128 (ib); estimated_growth = lto_input_sleb128 (ib); inlined = lto_input_uleb128 (ib); + ref2 = lto_input_sleb128 (ib); + same_body_count = lto_input_uleb128 (ib); /* Make sure that we have not read this node before. Nodes that have already been read will have their tag stored in the 'aux' @@ -522,6 +623,36 @@ input_node (struct lto_file_decl_data *file_data, node->global.estimated_growth = estimated_growth; node->global.inlined = inlined; + /* Store a reference for now, and fix up later to be a pointer. */ + node->same_comdat_group = (cgraph_node_ptr) (intptr_t) ref2; + + while (same_body_count-- > 0) + { + tree alias_decl; + int type; + decl_index = lto_input_uleb128 (ib); + alias_decl = lto_file_decl_data_get_fn_decl (file_data, decl_index); + type = lto_input_uleb128 (ib); + if (!type) + { + tree real_alias; + decl_index = lto_input_uleb128 (ib); + real_alias = lto_file_decl_data_get_fn_decl (file_data, decl_index); + cgraph_same_body_alias (alias_decl, real_alias); + } + else + { + HOST_WIDE_INT fixed_offset = lto_input_uleb128 (ib); + HOST_WIDE_INT virtual_value = lto_input_uleb128 (ib); + tree real_alias; + decl_index = lto_input_uleb128 (ib); + real_alias = lto_file_decl_data_get_fn_decl (file_data, decl_index); + cgraph_add_thunk (alias_decl, fn_decl, type & 2, fixed_offset, + virtual_value, + (type & 4) ? size_int (virtual_value) : NULL_TREE, + real_alias); + } + } return node; } @@ -593,7 +724,7 @@ input_cgraph_1 (struct lto_file_decl_data *file_data, { if (tag == LTO_cgraph_edge) input_edge (ib, nodes); - else + else { node = input_node (file_data, ib, tag); if (node == NULL || node->decl == NULL_TREE) @@ -620,18 +751,55 @@ input_cgraph_1 (struct lto_file_decl_data *file_data, for (i = 0; VEC_iterate (cgraph_node_ptr, nodes, i, node); i++) { - const int ref = (int) (intptr_t) node->global.inlined_to; + int ref = (int) (intptr_t) node->global.inlined_to; /* Fixup inlined_to from reference to pointer. */ if (ref != LCC_NOT_FOUND) node->global.inlined_to = VEC_index (cgraph_node_ptr, nodes, ref); else node->global.inlined_to = NULL; + + ref = (int) (intptr_t) node->same_comdat_group; + + /* Fixup same_comdat_group from reference to pointer. */ + if (ref != LCC_NOT_FOUND) + node->same_comdat_group = VEC_index (cgraph_node_ptr, nodes, ref); + else + node->same_comdat_group = NULL; } VEC_free (cgraph_node_ptr, heap, nodes); } +static struct gcov_ctr_summary lto_gcov_summary; + +/* Input profile_info from IB. */ +static void +input_profile_summary (struct lto_input_block *ib) +{ + unsigned int runs = lto_input_uleb128 (ib); + if (runs) + { + if (!profile_info) + { + profile_info = <o_gcov_summary; + lto_gcov_summary.runs = runs; + lto_gcov_summary.sum_all = lto_input_sleb128 (ib); + lto_gcov_summary.run_max = lto_input_sleb128 (ib); + lto_gcov_summary.sum_max = lto_input_sleb128 (ib); + } + /* We can support this by scaling all counts to nearest common multiple + of all different runs, but it is perhaps not worth the effort. */ + else if (profile_info->runs != runs + || profile_info->sum_all != lto_input_sleb128 (ib) + || profile_info->run_max != lto_input_sleb128 (ib) + || profile_info->sum_max != lto_input_sleb128 (ib)) + sorry ("Combining units with different profiles is not supported."); + /* We allow some units to have profile and other to not have one. This will + just make unprofiled units to be size optimized that is sane. */ + } + +} /* Input and merge the cgraph from each of the .o files passed to lto1. */ @@ -650,17 +818,18 @@ input_cgraph (void) size_t len; struct lto_input_block *ib; - ib = lto_create_simple_input_block (file_data, LTO_section_cgraph, + ib = lto_create_simple_input_block (file_data, LTO_section_cgraph, &data, &len); + input_profile_summary (ib); file_data->cgraph_node_encoder = lto_cgraph_encoder_new (); input_cgraph_1 (file_data, ib); - lto_destroy_simple_input_block (file_data, LTO_section_cgraph, + lto_destroy_simple_input_block (file_data, LTO_section_cgraph, ib, data, len); - + /* Assume that every file read needs to be processed by LTRANS. */ if (flag_wpa) lto_mark_file_for_ltrans (file_data); - } + } /* Clear out the aux field that was used to store enough state to tell which nodes should be overwritten. */