diff options
-rw-r--r-- | gcc/ChangeLog.lto | 4 | ||||
-rw-r--r-- | gcc/lto-cgraph-in.c | 244 | ||||
-rw-r--r-- | gcc/lto-cgraph-out.c | 359 | ||||
-rw-r--r-- | gcc/lto-cgraph.c | 426 | ||||
-rw-r--r-- | gcc/lto-cgraph.h | 53 | ||||
-rw-r--r-- | gcc/lto-function-in.c | 1 | ||||
-rw-r--r-- | gcc/lto-function-out.c | 73 | ||||
-rw-r--r-- | gcc/lto-section-in.h | 2 | ||||
-rw-r--r-- | gcc/lto-section-out.c | 13 | ||||
-rw-r--r-- | gcc/lto/ChangeLog | 32 | ||||
-rw-r--r-- | gcc/lto/lto.c | 12 |
11 files changed, 474 insertions, 745 deletions
diff --git a/gcc/ChangeLog.lto b/gcc/ChangeLog.lto index deab6dfe4ce..29d80887efd 100644 --- a/gcc/ChangeLog.lto +++ b/gcc/ChangeLog.lto @@ -1,3 +1,7 @@ +2008-06-11 Diego Novillo <dnovillo@google.com> + + Merge with lto r136640. + 2008-06-10 Diego Novillo <dnovillo@google.com> * lto-function-out.c (output_type_ref, output_expr_operand, diff --git a/gcc/lto-cgraph-in.c b/gcc/lto-cgraph-in.c deleted file mode 100644 index 6093f4ea81d..00000000000 --- a/gcc/lto-cgraph-in.c +++ /dev/null @@ -1,244 +0,0 @@ -/* Read the cgraph from the memory mapped representation of a a .o file. - - Copyright 2008 Free Software Foundation, Inc. - Contributed by Kenneth Zadeck <zadeck@naturalbridge.com> - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "toplev.h" -#include "tree.h" -#include "expr.h" -#include "flags.h" -#include "params.h" -#include "input.h" -#include "varray.h" -#include "hashtab.h" -#include "langhooks.h" -#include "basic-block.h" -#include "tree-iterator.h" -#include "tree-pass.h" -#include "tree-flow.h" -#include "cgraph.h" -#include "function.h" -#include "ggc.h" -#include "diagnostic.h" -#include "except.h" -#include "debug.h" -#include "vec.h" -#include "timevar.h" -#include "output.h" -#include "lto-cgraph.h" -#include "lto-section-in.h" -#include <ctype.h> -#include "cpplib.h" - -struct data_in -{ - /* That global decls and types. */ - struct lto_file_decl_data* file_data; -}; - - -/* Return 0 or 1 based on the last bit of FLAGS and right shift FLAGS - by 1. */ - -static unsigned int -add_flag (unsigned int *flags) -{ - unsigned int result = *flags & 1; - *flags = *flags >> 1; - return result; -} - -/* Overwrite the information in NODE based on DATA_IN, TAG, FLAGS, - STACK_SIZE and SELF_INSNS. This is called either to initialize - NODE or to replace the values in it, for instance becasue the first - time we saw it, the function body was not available but now it - is. */ -static void -overwrite_node (struct data_in *data_in, - struct cgraph_node *node, - enum LTO_cgraph_tags tag, - unsigned int flags, - unsigned int stack_size, - unsigned int self_insns) -{ - node->aux = (void *)tag; - node->local.inline_summary.estimated_self_stack_size = stack_size; - node->local.inline_summary.self_insns = self_insns; - node->global.insns = self_insns; - if (!node->local.lto_file_data) - node->local.lto_file_data = xcalloc (1, sizeof (struct lto_file_decl_data)); - - node->local.lto_file_data = data_in->file_data; - - /* This list must be in the reverse order that they are set in - lto-section-out.c:outout_node. */ - node->local.vtable_method = add_flag (&flags); - node->local.for_functions_valid = add_flag (&flags); - node->local.redefined_extern_inline = add_flag (&flags); - node->local.disregard_inline_limits = add_flag (&flags); - node->local.inlinable = add_flag (&flags); - node->local.finalized = add_flag (&flags); - node->local.externally_visible = add_flag (&flags); - node->local.local = add_flag (&flags); - node->analyzed = node->local.finalized; - node->lowered = node->local.finalized; - if (cgraph_decide_is_function_needed (node)) - cgraph_mark_needed_node (node); -} - - -/* Input a cgraph from IB using the info in DATA_IN. */ - -static void -input_cgraph (struct lto_input_block *ib, - struct data_in *data_in) -{ - enum LTO_cgraph_tags tag; - struct cgraph_node *last_caller = NULL; - - tag = lto_input_uleb128 (ib); - while (tag) - { - LTO_DEBUG_INDENT (tag); - - if (tag == LTO_cgraph_edge) - { - tree callee_decl; - struct cgraph_node *callee; - struct cgraph_edge *edge; - unsigned int stmt_id; - unsigned int count; - unsigned int freq; - unsigned int nest; - - callee_decl = data_in->file_data->fn_decls [lto_input_uleb128 (ib)]; - LTO_DEBUG_FN_NAME (callee_decl); - callee = cgraph_node (callee_decl); - - LTO_DEBUG_TOKEN ("stmt"); - stmt_id = lto_input_uleb128 (ib); - LTO_DEBUG_TOKEN ("count"); - count = lto_input_uleb128 (ib); - LTO_DEBUG_TOKEN ("frequency"); - freq = lto_input_uleb128 (ib); - LTO_DEBUG_TOKEN ("loop_next"); - nest = lto_input_uleb128 (ib); - - edge = cgraph_create_edge (last_caller, callee, NULL, count, freq, nest); - edge->lto_stmt_uid = stmt_id; - } - else - { - tree fn_decl; - struct cgraph_node *node; - unsigned int flags; - int stack_size = 0; - int self_insns = 0; - - fn_decl = data_in->file_data->fn_decls [lto_input_uleb128 (ib)]; - LTO_DEBUG_FN_NAME (fn_decl); - LTO_DEBUG_TOKEN ("flags"); - flags = lto_input_uleb128 (ib); - - if (tag == LTO_cgraph_avail_node) - { - LTO_DEBUG_TOKEN ("stack_size"); - stack_size = lto_input_sleb128 (ib); - LTO_DEBUG_TOKEN ("self_insns"); - self_insns = lto_input_sleb128 (ib); - } - - node = cgraph_node (fn_decl); - - switch (tag) - { - case LTO_cgraph_avail_node: - /* We cannot have two avail functions that are the same. */ - gcc_assert (((enum LTO_cgraph_tags)(node->aux)) != LTO_cgraph_avail_node); - overwrite_node (data_in, node, tag, flags, stack_size, self_insns); - break; - - case LTO_cgraph_unavail_node: - /* We only overwrite the node if this is a brand new node. */ - if (!node->aux) - overwrite_node (data_in, node, tag, flags, stack_size, self_insns); - break; - - case LTO_cgraph_overwritable_node: - /* FIXME!!!! This code is written to take the last - overwrittable version. I do not speak linker but if the - linker supposed to take the first one, then we need to - change the test. */ - if (((enum LTO_cgraph_tags)(node->aux)) != LTO_cgraph_avail_node) - overwrite_node (data_in, node, tag, flags, stack_size, self_insns); - break; - - default: - gcc_unreachable (); - } - - /* Set this up so that we can handle the edges which follow and - only have the callee in them. */ - last_caller = node; - } - LTO_DEBUG_UNDENT(); - tag = lto_input_uleb128 (ib); - } -} - -/* Read the body form DATA using the symbols in FILE_DATA to - reconstruct the part of the cgraph associated with FILE_DATA. */ - -void -lto_input_cgraph (struct lto_file_decl_data* file_data, const char *data) -{ - const struct lto_cgraph_header * header - = (const struct lto_cgraph_header *) data; - struct data_in data_in; - struct lto_input_block ib_main; - - int32_t main_offset = sizeof (struct lto_cgraph_header); -#ifdef LTO_STREAM_DEBUGGING - int32_t debug_main_offset = main_offset + header->main_size; - struct lto_input_block debug_main; -#endif - - LTO_INIT_INPUT_BLOCK (ib_main, data + main_offset, - 0, header->main_size); - memset (&data_in, 0, sizeof (struct data_in)); - data_in.file_data = file_data; - -#ifdef LTO_STREAM_DEBUGGING - LTO_INIT_INPUT_BLOCK (debug_main, data + debug_main_offset, - 0, header->debug_main_size); - lto_debug_context.current_data = &debug_main; - lto_debug_context.indent = 0; - lto_debug_context.stream_name = "cgraph"; - lto_debug_context.tag_names = LTO_cgraph_tag_names; -#endif - /* Read in the cgraph for this file and merge it into the main - one. */ - input_cgraph (&ib_main, &data_in); -} - diff --git a/gcc/lto-cgraph-out.c b/gcc/lto-cgraph-out.c deleted file mode 100644 index 7382c016970..00000000000 --- a/gcc/lto-cgraph-out.c +++ /dev/null @@ -1,359 +0,0 @@ -/* Write the cgraph to a .o file. - - Copyright 2008 Free Software Foundation, Inc. - Contributed by Kenneth Zadeck <zadeck@naturalbridge.com> - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING. If not, write to -the Free Software Foundation, 51 Franklin Street, Fifth Floor, -Boston, MA 02110-1301, USA. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "tm.h" -#include "toplev.h" -#include "tree.h" -#include "expr.h" -#include "flags.h" -#include "params.h" -#include "input.h" -#include "varray.h" -#include "hashtab.h" -#include "langhooks.h" -#include "basic-block.h" -#include "tree-iterator.h" -#include "tree-pass.h" -#include "tree-flow.h" -#include "cgraph.h" -#include "function.h" -#include "ggc.h" -#include "diagnostic.h" -#include "except.h" -#include "debug.h" -#include "vec.h" -#include "tree-vectorizer.h" -#include "timevar.h" -#include "output.h" -#include "lto-cgraph.h" -#include "lto-section-out.h" -#include <ctype.h> - - -const char * LTO_cgraph_tag_names[LTO_cgraph_last_tag] = -{"", "avail", "overwrite", "unavail", "edge"}; - - -struct output_block -{ - enum lto_section_type section_type; - struct lto_out_decl_state *decl_state; - - /* The stream that the main tree codes are written to. */ - struct lto_output_stream *main_stream; - -#ifdef LTO_STREAM_DEBUGGING - /* The stream that contains the gimple debugging information. */ - struct lto_output_stream *debug_main_stream; -#endif -}; - - -/* Create the output block and return it. */ - -static struct output_block * -create_output_block (void) -{ - struct output_block *ob = xcalloc (1, sizeof (struct output_block)); - ob->section_type = LTO_section_cgraph; - ob->decl_state = lto_get_out_decl_state (); - ob->main_stream = xcalloc (1, sizeof (struct lto_output_stream)); - -#ifdef LTO_STREAM_DEBUGGING - lto_debug_context.out = lto_debug_out_fun; - lto_debug_context.indent = 0; - lto_debug_context.tag_names = LTO_cgraph_tag_names; -#endif - - return ob; -} - - -/* Destroy the output block OB. IS_FUNTION is true if this is for a - function and false for a constructor. */ - -static void -destroy_output_block (struct output_block * ob) -{ - free (ob->main_stream); - LTO_CLEAR_DEBUGGING_STREAM (debug_main_stream); - free (ob); -} - - -/* Output an unsigned LEB128 quantity to OB->main_stream. */ - -static void -output_uleb128 (struct output_block *ob, unsigned HOST_WIDE_INT work) -{ - lto_output_uleb128_stream (ob->main_stream, work); -} - - -/* Output a signed LEB128 quantity to OB->main_stream. */ - -static void -output_sleb128 (struct output_block *ob, HOST_WIDE_INT work) -{ - lto_output_sleb128_stream (ob->main_stream, work); -} - - -/* Output FUNCTION_DECL EXPR to output block OB. */ - -static void -output_fn_decl (struct output_block *ob, tree expr) -{ - unsigned int index; - bool new; - - new = lto_output_decl_index (ob->main_stream, - ob->decl_state->fn_decl_hash_table, - &ob->decl_state->next_fn_decl_index, - expr, &index); - if (new) - VEC_safe_push (tree, heap, ob->decl_state->fn_decls, expr); -} - - -/* Output the cgraph EDGE to OB. */ - -static void -output_edge (struct output_block *ob, struct cgraph_edge *edge) -{ - output_uleb128 (ob, LTO_cgraph_edge); - LTO_DEBUG_INDENT (LTO_cgraph_edge); - output_fn_decl (ob, edge->callee->decl); - LTO_DEBUG_FN_NAME (edge->callee->decl); - - LTO_DEBUG_TOKEN ("stmt"); - output_uleb128 (ob, gimple_stmt_uid (edge->call_stmt)); - LTO_DEBUG_TOKEN ("count"); - output_uleb128 (ob, edge->count); - LTO_DEBUG_TOKEN ("frequency"); - output_uleb128 (ob, edge->frequency); - LTO_DEBUG_TOKEN ("loop_next"); - output_uleb128 (ob, edge->loop_nest); - LTO_DEBUG_UNDENT(); -} - - -/* Add FLAG onto the end of BASE. */ - -static void -add_flag (unsigned int *base, unsigned int flag) -{ - *base = *base << 1; - if (flag) - *base |= 1; -} - - -/* Output the cgraph NODE to OB. */ - -static void -output_node (struct output_block *ob, struct cgraph_node *node) -{ - unsigned int tag; - unsigned int flags = 0; - struct cgraph_edge *callees = node->callees; - - switch (cgraph_function_body_availability (node)) - { - case AVAIL_NOT_AVAILABLE: - tag = LTO_cgraph_unavail_node; - break; - - case AVAIL_AVAILABLE: - case AVAIL_LOCAL: - tag = LTO_cgraph_avail_node; - break; - - case AVAIL_OVERWRITABLE: - tag = LTO_cgraph_overwritable_node; - break; - - default: - gcc_unreachable(); - } - - output_uleb128 (ob, tag); - LTO_DEBUG_INDENT (tag); - - output_fn_decl (ob, node->decl); - LTO_DEBUG_FN_NAME (node->decl); - add_flag (&flags, node->local.local); - add_flag (&flags, node->local.externally_visible); - add_flag (&flags, node->local.finalized); - add_flag (&flags, node->local.inlinable); - add_flag (&flags, node->local.disregard_inline_limits); - add_flag (&flags, node->local.redefined_extern_inline); - add_flag (&flags, node->local.for_functions_valid); - add_flag (&flags, node->local.vtable_method); - - LTO_DEBUG_TOKEN ("flags"); - output_uleb128 (ob, flags); - - if (tag != LTO_cgraph_unavail_node) - { - LTO_DEBUG_TOKEN ("stack_size"); - output_sleb128 (ob, node->local.inline_summary.estimated_self_stack_size); - LTO_DEBUG_TOKEN ("self_insns"); - output_sleb128 (ob, node->local.inline_summary.self_insns); - } - - LTO_DEBUG_UNDENT(); - -#ifdef LTO_STREAM_DEBUGGING - gcc_assert (lto_debug_context.indent == 0); -#endif - - while (callees) - { - output_edge (ob, callees); - callees = callees->next_callee; - } - -#ifdef LTO_STREAM_DEBUGGING - gcc_assert (lto_debug_context.indent == 0); -#endif -} - - -/* Produce the section that holds the cgraph. */ - -static void -produce_asm (struct output_block *ob) -{ - struct lto_cgraph_header header; - section *section = lto_get_section (LTO_section_cgraph, NULL); - - memset (&header, 0, sizeof (struct lto_cgraph_header)); - - /* The entire header is stream computed here. */ - switch_to_section (section); - - /* Write the header which says how to decode the pieces of the - t. */ - header.lto_header.major_version = LTO_major_version; - header.lto_header.minor_version = LTO_minor_version; - header.lto_header.section_type = LTO_section_cgraph; - - header.compressed_size = 0; - - header.main_size = ob->main_stream->total_size; -#ifdef LTO_STREAM_DEBUGGING - header.debug_main_size = ob->debug_main_stream->total_size; -#else - header.debug_main_size = -1; -#endif - - assemble_string ((const char *)&header, - sizeof (struct lto_cgraph_header)); - - lto_write_stream (ob->main_stream); -#ifdef LTO_STREAM_DEBUGGING - lto_write_stream (ob->debug_main_stream); -#endif -} - - -/* Output the cgraph. */ - -static unsigned int -lto_output_cgraph (void) -{ - struct cgraph_node *node; - section *saved_section = in_section; - struct output_block *ob = create_output_block (); - - LTO_SET_DEBUGGING_STREAM (debug_main_stream, main_data); - - for (node = cgraph_nodes; node; node = node->next) - { - output_node (ob, node); - -#ifdef ENABLE_CHECKING - /* Just a little sanity check to keep Honza honest. At the - point where we stream out the functions there must only be - master_clone nodes or nodes that have no function bodies. */ - - switch (cgraph_function_body_availability (node)) - { - case AVAIL_UNSET: - fprintf (stderr, "found unset function\n."); - gcc_assert (0); - break; - - case AVAIL_NOT_AVAILABLE: - break; - - case AVAIL_OVERWRITABLE: - case AVAIL_AVAILABLE: - case AVAIL_LOCAL: - if (node != cgraph_master_clone (node, false)) - { - fprintf (stderr, "found clone\n."); - gcc_assert (0); - } - break; - } -#endif - } - - output_uleb128 (ob, 0); - - /* Create a section to hold the pickled output the cgraph. */ - produce_asm (ob); - - destroy_output_block (ob); - - /* Put back the assembly section that was there before we started - writing lto info. */ - if (saved_section) - switch_to_section (saved_section); - - return 0; -} - -struct simple_ipa_opt_pass pass_ipa_lto_cgraph_out = -{ - { - SIMPLE_IPA_PASS, - "lto_cgraph_out", /* name */ - gate_lto_out, /* gate */ - lto_output_cgraph, /* execute */ - NULL, /* sub */ - NULL, /* next */ - 0, /* static_pass_number */ - TV_IPA_LTO_OUT, /* tv_id */ - 0, /* properties_required */ - 0, /* properties_provided */ - 0, /* properties_destroyed */ - 0, /* todo_flags_start */ - TODO_dump_func /* todo_flags_finish */ - } -}; - diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c new file mode 100644 index 00000000000..81eab87de40 --- /dev/null +++ b/gcc/lto-cgraph.c @@ -0,0 +1,426 @@ +/* Write and read the cgraph to the memory mapped representation of a + .o file. + + Copyright 2008 Free Software Foundation, Inc. + Contributed by Kenneth Zadeck <zadeck@naturalbridge.com> + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "toplev.h" +#include "tree.h" +#include "expr.h" +#include "flags.h" +#include "params.h" +#include "input.h" +#include "varray.h" +#include "hashtab.h" +#include "langhooks.h" +#include "basic-block.h" +#include "tree-pass.h" +#include "tree-flow.h" +#include "cgraph.h" +#include "function.h" +#include "ggc.h" +#include "diagnostic.h" +#include "except.h" +#include "debug.h" +#include "vec.h" +#include "timevar.h" +#include "dwarf2asm.h" +#include "dwarf2out.h" +#include "output.h" +#include "lto-section-in.h" +#include "lto-section-out.h" +#include <ctype.h> + +enum LTO_cgraph_tags +{ + /* Must leave 0 for the stopper. */ + LTO_cgraph_avail_node = 1, + LTO_cgraph_overwritable_node, + LTO_cgraph_unavail_node, + LTO_cgraph_edge, + LTO_cgraph_last_tag +}; + +#ifdef LTO_STREAM_DEBUGGING +static const char * LTO_cgraph_tag_names[LTO_cgraph_last_tag] = +{"", "avail", "overwrite", "unavail", "edge"}; +#endif + + +/* Output the cgraph EDGE to OB. */ + +static void +output_edge (struct lto_simple_output_block *ob, struct cgraph_edge *edge) +{ + lto_output_uleb128_stream (ob->main_stream, LTO_cgraph_edge); + LTO_DEBUG_INDENT (LTO_cgraph_edge); + lto_output_fn_decl_index (ob->decl_state, ob->main_stream, edge->callee->decl); + LTO_DEBUG_FN_NAME (edge->callee->decl); + + LTO_DEBUG_TOKEN ("stmt"); + lto_output_uleb128_stream (ob->main_stream, gimple_stmt_uid (edge->call_stmt)); + LTO_DEBUG_TOKEN ("count"); + lto_output_uleb128_stream (ob->main_stream, edge->count); + LTO_DEBUG_TOKEN ("frequency"); + lto_output_uleb128_stream (ob->main_stream, edge->frequency); + LTO_DEBUG_TOKEN ("loop_next"); + lto_output_uleb128_stream (ob->main_stream, edge->loop_nest); + LTO_DEBUG_UNDENT(); +} + + +/* Output the cgraph NODE to OB. */ + +static void +output_node (struct lto_simple_output_block *ob, struct cgraph_node *node) +{ + unsigned int tag; + unsigned HOST_WIDEST_INT flags = 0; + struct cgraph_edge *callees = node->callees; + + switch (cgraph_function_body_availability (node)) + { + case AVAIL_NOT_AVAILABLE: + tag = LTO_cgraph_unavail_node; + break; + + case AVAIL_AVAILABLE: + case AVAIL_LOCAL: + tag = LTO_cgraph_avail_node; + break; + + case AVAIL_OVERWRITABLE: + tag = LTO_cgraph_overwritable_node; + break; + + default: + gcc_unreachable(); + } + + lto_output_uleb128_stream (ob->main_stream, tag); + LTO_DEBUG_INDENT (tag); + + lto_output_fn_decl_index (ob->decl_state, ob->main_stream, node->decl); + LTO_DEBUG_FN_NAME (node->decl); + lto_set_flag (&flags, node->local.local); + lto_set_flag (&flags, node->local.externally_visible); + lto_set_flag (&flags, node->local.finalized); + lto_set_flag (&flags, node->local.inlinable); + lto_set_flag (&flags, node->local.disregard_inline_limits); + lto_set_flag (&flags, node->local.redefined_extern_inline); + lto_set_flag (&flags, node->local.for_functions_valid); + lto_set_flag (&flags, node->local.vtable_method); + + LTO_DEBUG_TOKEN ("flags"); + lto_output_uleb128_stream (ob->main_stream, flags); + + if (tag != LTO_cgraph_unavail_node) + { + LTO_DEBUG_TOKEN ("stack_size"); + lto_output_sleb128_stream (ob->main_stream, + node->local.inline_summary.estimated_self_stack_size); + LTO_DEBUG_TOKEN ("self_insns"); + lto_output_sleb128_stream (ob->main_stream, + node->local.inline_summary.self_insns); + } + + LTO_DEBUG_UNDENT(); + +#ifdef LTO_STREAM_DEBUGGING + gcc_assert (lto_debug_context.indent == 0); +#endif + + while (callees) + { + output_edge (ob, callees); + callees = callees->next_callee; + } + +#ifdef LTO_STREAM_DEBUGGING + gcc_assert (lto_debug_context.indent == 0); +#endif +} + + +/* Output the cgraph. */ + +static void +output_cgraph (void) +{ + struct cgraph_node *node; + struct lto_simple_output_block *ob + = lto_create_simple_output_block (LTO_section_cgraph); + int i = 0; + +#ifdef LTO_STREAM_DEBUGGING + lto_debug_context.tag_names = LTO_cgraph_tag_names; + lto_debug_context.stream_name = "cgraph"; +#endif + + for (node = cgraph_nodes; node; node = node->next) + { +#ifdef ENABLE_CHECKING + /* Just a little sanity check to keep Honza honest. At the + point where we stream out the functions there must only be + master_clone nodes or nodes that have no function bodies. */ + + switch (cgraph_function_body_availability (node)) + { + case AVAIL_UNSET: + fprintf (stderr, "found unset function\n."); + gcc_assert (0); + break; + + case AVAIL_NOT_AVAILABLE: + break; + + case AVAIL_OVERWRITABLE: + case AVAIL_AVAILABLE: + case AVAIL_LOCAL: + if (node != cgraph_master_clone (node, false)) + { + fprintf (stderr, "found clone\n."); + gcc_assert (0); + } + break; + } +#endif + output_node (ob, node); + i++; + } + + lto_output_uleb128_stream (ob->main_stream, 0); + + /* Create a section to hold the pickled output the cgraph. */ + lto_destroy_simple_output_block (ob); +} + + +/* Overwrite the information in NODE based on FILE_DATA, TAG, FLAGS, + STACK_SIZE and SELF_INSNS. This is called either to initialize + NODE or to replace the values in it, for instance becasue the first + time we saw it, the function body was not available but now it + is. */ +static void +input_overwrite_node (struct lto_file_decl_data* file_data, + struct cgraph_node *node, + enum LTO_cgraph_tags tag, + unsigned HOST_WIDEST_INT flags, + unsigned int stack_size, + unsigned int self_insns) +{ + node->aux = (void *)tag; + node->local.inline_summary.estimated_self_stack_size = stack_size; + node->local.inline_summary.self_insns = self_insns; + node->global.insns = self_insns; + node->local.lto_file_data = file_data; + + /* This list must be in the reverse order that they are set in + lto-section-out.c:outout_node. */ + node->local.vtable_method = lto_get_flag (&flags); + node->local.for_functions_valid = lto_get_flag (&flags); + node->local.redefined_extern_inline = lto_get_flag (&flags); + node->local.disregard_inline_limits = lto_get_flag (&flags); + node->local.inlinable = lto_get_flag (&flags); + node->local.finalized = lto_get_flag (&flags); + node->local.externally_visible = lto_get_flag (&flags); + node->local.local = lto_get_flag (&flags); + node->analyzed = node->local.finalized; + node->lowered = node->local.finalized; + if (cgraph_decide_is_function_needed (node)) + cgraph_mark_needed_node (node); +} + + +/* Input a cgraph from IB using the info in FILE_DATA. */ + +static void +input_cgraph_1 (struct lto_file_decl_data* file_data, + struct lto_input_block *ib) +{ + enum LTO_cgraph_tags tag; + struct cgraph_node *last_caller = NULL; + + tag = lto_input_uleb128 (ib); + while (tag) + { + LTO_DEBUG_INDENT (tag); + + if (tag == LTO_cgraph_edge) + { + tree callee_decl; + struct cgraph_node *callee; + struct cgraph_edge *edge; + unsigned int stmt_id; + unsigned int count; + unsigned int freq; + unsigned int nest; + + callee_decl = file_data->fn_decls [lto_input_uleb128 (ib)]; + LTO_DEBUG_FN_NAME (callee_decl); + callee = cgraph_node (callee_decl); + + LTO_DEBUG_TOKEN ("stmt"); + stmt_id = lto_input_uleb128 (ib); + LTO_DEBUG_TOKEN ("count"); + count = lto_input_uleb128 (ib); + LTO_DEBUG_TOKEN ("frequency"); + freq = lto_input_uleb128 (ib); + LTO_DEBUG_TOKEN ("loop_next"); + nest = lto_input_uleb128 (ib); + + edge = cgraph_create_edge (last_caller, callee, NULL, count, freq, nest); + edge->lto_stmt_uid = stmt_id; + } + else + { + tree fn_decl; + struct cgraph_node *node; + unsigned int flags; + int stack_size = 0; + int self_insns = 0; + + fn_decl = file_data->fn_decls [lto_input_uleb128 (ib)]; + LTO_DEBUG_FN_NAME (fn_decl); + LTO_DEBUG_TOKEN ("flags"); + flags = lto_input_uleb128 (ib); + + if (tag == LTO_cgraph_avail_node) + { + LTO_DEBUG_TOKEN ("stack_size"); + stack_size = lto_input_sleb128 (ib); + LTO_DEBUG_TOKEN ("self_insns"); + self_insns = lto_input_sleb128 (ib); + } + + node = cgraph_node (fn_decl); + + switch (tag) + { + case LTO_cgraph_avail_node: + /* We cannot have two avail functions that are the same. */ + gcc_assert (((enum LTO_cgraph_tags)(node->aux)) != LTO_cgraph_avail_node); + input_overwrite_node (file_data, node, tag, + flags, stack_size, self_insns); + break; + + case LTO_cgraph_unavail_node: + /* We only overwrite the node if this is a brand new node. */ + if (!node->aux) + input_overwrite_node (file_data, node, tag, + flags, stack_size, self_insns); + break; + + case LTO_cgraph_overwritable_node: + /* FIXME!!!! This code is written to take the last + overwrittable version. I do not speak linker but if the + linker supposed to take the first one, then we need to + change the test. */ + if (((enum LTO_cgraph_tags)(node->aux)) != LTO_cgraph_avail_node) + input_overwrite_node (file_data, node, tag, + flags, stack_size, self_insns); + break; + + default: + gcc_unreachable (); + } + + /* Set this up so that we can handle the edges which follow and + only have the callee in them. */ + last_caller = node; + } + LTO_DEBUG_UNDENT(); + tag = lto_input_uleb128 (ib); + } +} + + +/* Input and merge the cgraph from each of the .o files passed to + lto1. */ + +static void +input_cgraph (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; + struct cgraph_node *node; + +#ifdef LTO_STREAM_DEBUGGING + lto_debug_context.tag_names = LTO_cgraph_tag_names; + lto_debug_context.stream_name = "cgraph"; +#endif + + while ((file_data = file_data_vec[j++])) + { + const char *data; + size_t len; + struct lto_input_block *ib + = lto_create_simple_input_block (file_data, + LTO_section_cgraph, + &data, &len); + input_cgraph_1 (file_data, ib); + lto_destroy_simple_input_block (file_data, + LTO_section_cgraph, + ib, data, len); + } + + /* Clear out the aux field that was used to store enough state to + tell which nodes should be overwritten. */ + for (node = cgraph_nodes; node; node = node->next) + { + gcc_assert (node->local.lto_file_data); + node->aux = NULL; + } +} + + + +struct ipa_opt_pass pass_ipa_lto_cgraph = +{ + { + IPA_PASS, + "lto_cgraph", /* name */ + gate_lto_out, /* gate */ + NULL, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + TV_IPA_LTO_OUT, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func /* todo_flags_finish */ + }, + NULL, /* generate_summary */ + output_cgraph, /* write_summary */ + input_cgraph, /* read_summary */ + NULL, /* function_read_summary */ + 0, /* TODOs */ + NULL, /* function_transform */ + NULL /* variable_transform */ +}; + diff --git a/gcc/lto-cgraph.h b/gcc/lto-cgraph.h deleted file mode 100644 index ef360a92237..00000000000 --- a/gcc/lto-cgraph.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Declarations and definitions relating to the encoding of the cgraph - into the object files. - - Copyright (C) 2008 Free Software Foundation, Inc. - Contributed by Kenneth Zadeck <zadeck@naturalbridge.com> - - This file is part of GCC. - - GCC is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 2, or (at your option) any later - version. - - GCC is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - You should have received a copy of the GNU General Public License - along with GCC; see the file COPYING. If not, write to the Free - Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301, USA. */ - -#ifndef GCC_LTO_CGRAPH_H -#define GCC_LTO_CGRAPH_H - -#include "tree.h" -#include "lto-header.h" - -enum LTO_cgraph_tags -{ - /* Must leave 0 for the stopper. */ - LTO_cgraph_avail_node = 1, - LTO_cgraph_overwritable_node, - LTO_cgraph_unavail_node, - LTO_cgraph_edge, - LTO_cgraph_last_tag -}; - -/* The is the first part of the cgraph record in the .o file. */ -struct lto_cgraph_header -{ - struct lto_header lto_header; /* The header for all types of sections. */ - int32_t main_size; /* Size of main gimple body of function. */ - int32_t debug_main_size; /* Size of main stream debugging information. */ - int32_t compressed_size; -}; - -#ifdef LTO_STREAM_DEBUGGING -extern const char * LTO_cgraph_tag_names[LTO_cgraph_last_tag]; -#endif - -#endif /* GCC_LTO_CGRAPH_H */ diff --git a/gcc/lto-function-in.c b/gcc/lto-function-in.c index 83e1a93fb94..7ed18617923 100644 --- a/gcc/lto-function-in.c +++ b/gcc/lto-function-in.c @@ -140,7 +140,6 @@ input_string_internal (struct data_in *data_in, unsigned int loc, LTO_INIT_INPUT_BLOCK (str_tab, data_in->strings, loc, data_in->strings_len); - len = lto_input_uleb128 (&str_tab); *rlen = len; gcc_assert (str_tab.p + len <= data_in->strings_len); diff --git a/gcc/lto-function-out.c b/gcc/lto-function-out.c index 6e240aadbca..690fac4dc12 100644 --- a/gcc/lto-function-out.c +++ b/gcc/lto-function-out.c @@ -610,18 +610,8 @@ output_type_ref_1 (struct output_block *ob, tree node) else #endif { - bool new; - unsigned int index; - output_record_start (ob, NULL, NULL, LTO_global_type_ref); - - new = lto_output_decl_index (ob->main_stream, - ob->decl_state->type_hash_table, - &ob->decl_state->next_type_index, - node, &index); - - if (new) - VEC_safe_push (tree, heap, ob->decl_state->types, node); + lto_output_type_ref_index (ob->decl_state, ob->main_stream, node); } LTO_DEBUG_UNDENT(); @@ -1048,16 +1038,8 @@ output_expr_operand (struct output_block *ob, tree expr) case FIELD_DECL: if (!field_decl_is_local (expr)) { - unsigned int index; - bool new; output_record_start (ob, NULL, NULL, LTO_field_decl1); - - new = lto_output_decl_index (ob->main_stream, - ob->decl_state->field_decl_hash_table, - &ob->decl_state->next_field_decl_index, - expr, &index); - if (new) - VEC_safe_push (tree, heap, ob->decl_state->field_decls, expr); + lto_output_field_decl_index (ob->decl_state, ob->main_stream, expr); } else { @@ -1070,34 +1052,15 @@ output_expr_operand (struct output_block *ob, tree expr) case FUNCTION_DECL: /* FIXME: Local FUNCTION_DECLS are possible, i.e., nested functions. */ - { - unsigned int index; - bool new; - output_record_start (ob, NULL, NULL, tag); - - new = lto_output_decl_index (ob->main_stream, - ob->decl_state->fn_decl_hash_table, - &ob->decl_state->next_fn_decl_index, - expr, &index); - if (new) - VEC_safe_push (tree, heap, ob->decl_state->fn_decls, expr); - } + output_record_start (ob, NULL, NULL, tag); + lto_output_fn_decl_index (ob->decl_state, ob->main_stream, expr); break; case VAR_DECL: if (TREE_STATIC (expr) || DECL_EXTERNAL (expr)) { - /* Static or extern VAR_DECLs. */ - unsigned int index; - bool new; output_record_start (ob, NULL, NULL, LTO_var_decl1); - - new = lto_output_decl_index (ob->main_stream, - ob->decl_state->var_decl_hash_table, - &ob->decl_state->next_var_decl_index, - expr, &index); - if (new) - VEC_safe_push (tree, heap, ob->decl_state->var_decls, expr); + lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr); } else { @@ -1110,16 +1073,8 @@ output_expr_operand (struct output_block *ob, tree expr) case TYPE_DECL: if (!type_decl_is_local (expr)) { - unsigned int index; - bool new; output_record_start (ob, NULL, NULL, LTO_type_decl1); - - new = lto_output_decl_index (ob->main_stream, - ob->decl_state->type_decl_hash_table, - &ob->decl_state->next_type_decl_index, - expr, &index); - if (new) - VEC_safe_push (tree, heap, ob->decl_state->type_decls, expr); + lto_output_type_decl_index (ob->decl_state, ob->main_stream, expr); } else { @@ -1130,18 +1085,8 @@ output_expr_operand (struct output_block *ob, tree expr) break; case NAMESPACE_DECL: - { - unsigned int index; - bool new; - output_record_start (ob, NULL, NULL, tag); - - new = lto_output_decl_index (ob->main_stream, - ob->decl_state->namespace_decl_hash_table, - &ob->decl_state->next_namespace_decl_index, - expr, &index); - if (new) - VEC_safe_push (tree, heap, ob->decl_state->namespace_decls, expr); - } + output_record_start (ob, NULL, NULL, tag); + lto_output_namespace_decl_index (ob->decl_state, ob->main_stream, expr); break; case PARM_DECL: @@ -2280,7 +2225,7 @@ output_function (struct cgraph_node* node) else if (TYPE_P (context)) { output_record_start (ob, NULL, NULL, LTO_type); - output_type_ref_1 (ob, context); + lto_output_type_ref_index (ob->decl_state, ob->main_stream, context); LTO_DEBUG_UNDENT (); } else diff --git a/gcc/lto-section-in.h b/gcc/lto-section-in.h index 2bcbba02e27..17582a0b8fe 100644 --- a/gcc/lto-section-in.h +++ b/gcc/lto-section-in.h @@ -77,6 +77,8 @@ struct lto_file_decl_data htab_t section_hash_table; }; +struct lto_file_decl_data; + /* Return a char pointer to the start of a data stream for an lto pass or function. The first parameter is the file data that contains the information. The second parameter is the type of information diff --git a/gcc/lto-section-out.c b/gcc/lto-section-out.c index 5d4df6ad9b7..5a98a333ca8 100644 --- a/gcc/lto-section-out.c +++ b/gcc/lto-section-out.c @@ -618,11 +618,12 @@ lto_destroy_simple_output_block (struct lto_simple_output_block *ob) } -/* This part is used to store all of the global decls and types that - are serialized out in this file so that a table for this file can - be built that allows the decls and types to be reconnected to the - code or the ipa summary information. */ - +/***************************************************************************** + This part is used to store all of the global decls and types that + are serialized out in this file so that a table for this file can be + built that allows the decls and types to be reconnected to the code + or the ipa summary information. +*****************************************************************************/ struct lto_out_decl_state * lto_get_out_decl_state (void) { @@ -802,7 +803,7 @@ produce_asm_for_decls (void) /* Assign reference indices for predefined trees. These need not be serialized. */ preload_common_nodes (ob); - + memset (&header, 0, sizeof (struct lto_decl_header)); switch_to_section (decl_section); diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog index a288a0034ab..8cf2a09223d 100644 --- a/gcc/lto/ChangeLog +++ b/gcc/lto/ChangeLog @@ -1,19 +1,3 @@ -2008-06-07 Kenneth Zadeck <zadeck@naturalbridge.com> - Jan Hubicka <jh@suse.cz> - - * lto.c (sys/mman.h, tree-pass.h): New includes. - (lto_materialize_constructors_and_inits, - lto_materialize_function): Keeps length of section. - (lto_materialize_cgraph): Removed. - (lto_read_decls): Initialize fd field. - (lto_file_read): Different return type and removed much code to - lto_main. - (page_mask): New variable. - (lto_read_section_data, get_section_data, free_section_data): New - functions. - (lto_main): Now calls pass manager, sets the hooks so that the ipa - passes can get the section data. - 2008-06-04 Ollie Wild <aaw@google.com> * lto.c: Remove inclusion of dwarf2.h and dwarf2out.h. @@ -79,6 +63,22 @@ * lto-section-out.h (lto_hash_global_slot_node, lto_eq_global_slot_node): Declare. +2008-06-07 Kenneth Zadeck <zadeck@naturalbridge.com> + Jan Hubicka <jh@suse.cz> + + * lto.c (sys/mman.h, tree-pass.h): New includes. + (lto_materialize_constructors_and_inits, + lto_materialize_function): Keeps length of section. + (lto_materialize_cgraph): Removed. + (lto_read_decls): Initialize fd field. + (lto_file_read): Different return type and removed much code to + lto_main. + (page_mask): New variable. + (lto_read_section_data, get_section_data, free_section_data): New + functions. + (lto_main): Now calls pass manager, sets the hooks so that the ipa + passes can get the section data. + 2008-05-27 Kenneth Zadeck <zadeck@naturalbridge.com> * lto.h (lto_read_decls): Made local. diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c index 2b7e5a242e3..c996f6737b5 100644 --- a/gcc/lto/lto.c +++ b/gcc/lto/lto.c @@ -46,7 +46,7 @@ static void lto_materialize_constructors_and_inits (struct lto_file_decl_data * file_data) { size_t len; - const char *data = lto_get_section_data (file_data, + const char *data = lto_get_section_data (file_data, LTO_section_static_initializer, NULL, &len); lto_input_constructors_and_inits (file_data, data); lto_free_section_data (file_data, LTO_section_static_initializer, NULL, data, len); @@ -62,7 +62,7 @@ lto_materialize_function (struct cgraph_node *node) const char *data; size_t len; tree step; - const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); + const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); data = lto_get_section_data (file_data, LTO_section_function_body, name, &len); @@ -422,6 +422,7 @@ lto_main (int debug_p ATTRIBUTE_UNUSED) /* Read all of the object files specified on the command line. */ for (i = 0; i < num_in_fnames; ++i) { + htab_t section_hash_table; current_lto_file = lto_elf_file_open (in_fnames[i]); if (!current_lto_file) break; @@ -429,6 +430,9 @@ lto_main (int debug_p ATTRIBUTE_UNUSED) if (!file_data) break; + section_hash_table = lto_elf_build_section_table (current_lto_file); + file_data->section_hash_table = section_hash_table; + all_file_decl_data [j++] = file_data; lto_elf_file_close (current_lto_file); @@ -437,6 +441,10 @@ lto_main (int debug_p ATTRIBUTE_UNUSED) all_file_decl_data [j] = NULL; + /* Set the hooks so that all of the ipa passes can read in their data. */ + lto_set_in_hooks (all_file_decl_data, get_section_data, + free_section_data); + /* FIXME!!! This loop needs to be changed to use the pass manager to call the ipa passes directly. */ for (i = 0; i < j; i++) |