aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth Zadeck <zadeck@naturalbridge.com>2008-03-05 21:18:26 +0000
committerKenneth Zadeck <zadeck@naturalbridge.com>2008-03-05 21:18:26 +0000
commite707b6f5ed73965bdd1eac107cf9bdc3b4a14fb7 (patch)
tree8d2f6047cf68f54df973eee81c253614a28ef8f2
parentbdc903d3f1d7f78c975865fa35da936496479200 (diff)
2008-03-05 Kenneth Zadeck <zadeck@naturalbridge.com>
Jan Hubicka <jh@suse.cz> * lto.c (lto_info_fd_init, lto_info_fd_close): Get rid of fd->unmaterialized_fndecls. (lto_get_file_name, lto_materialize_cgraph): New function. (lto_materialize_constructors_and_inits, lto_materialize_function): Read info directly from elf file. (lto_file_read): Made local and initialize dictionary so that other lto sections can be read without reprocessing the elf file. (lto_main): Read all functions after all files have been processed for their types, globals and cgraph. * Make-lang.in (lto.o, lto-cgraph-in.c, lto-section-in): Changed dependencies. * lto-elf.c (lto_elf_file): Removed strtab, symtab fields. (hash_name, eq_name, lto_elf_build_section_table): New functions. (lto_elf_read_symtab): Removed function. (lto_elf_file_open): Removed call to lto_elf_read_symtab. * lto.h (lto_info_fd_struct): Removed unmaterialized_fndecls. (lto_file_read): Made local. (lto_get_file_name, lto_elf_build_section_table, lto_input_cgraph): New function. * lto-section-in.c (lto_read_section_data, lto_get_section_data): New functions. (lto_read_decls): Get the file name. * lto-cgraph-in.c: New file. * lto-function-in.c (tag_to_expr): Stops at LTO_tree_last_tag. (input_expr_operand, lto_read_body): Set lto_debug_context.tag_names. (input_labels): Fixed latent sizeof issue. (input_function): Build stmt array to set call sites into cgraph edges. (lto_read_body): Reset cfun->curr_properties. * lto_section_in.h (lto_section_slot): New structure. (section_hash_table.lto_file_decl_data): New field. 2008-03-05 Kenneth Zadeck <zadeck@naturalbridge.com> Jan Hubicka <jh@suse.cz> * lto.c (lto_info_fd_init, lto_info_fd_close): Get rid of fd->unmaterialized_fndecls. (lto_get_file_name, lto_materialize_cgraph): New function. (lto_materialize_constructors_and_inits, lto_materialize_function): Read info directly from elf file. (lto_file_read): Made local and initialize dictionary so that other lto sections can be read without reprocessing the elf file. (lto_main): Read all functions after all files have been processed for their types, globals and cgraph. * Make-lang.in (lto.o, lto-cgraph-in.c, lto-section-in): Changed dependencies. * lto-elf.c (lto_elf_file): Removed strtab, symtab fields. (hash_name, eq_name, lto_elf_build_section_table): New functions. (lto_elf_read_symtab): Removed function. (lto_elf_file_open): Removed call to lto_elf_read_symtab. * lto.h (lto_info_fd_struct): Removed unmaterialized_fndecls. (lto_file_read): Made local. (lto_get_file_name, lto_elf_build_section_table, lto_input_cgraph): New function. * lto-section-in.c (lto_read_section_data, lto_get_section_data): New functions. (lto_read_decls): Get the file name. * lto-cgraph-in.c: New file. * lto-function-in.c (tag_to_expr): Stops at LTO_tree_last_tag. (input_expr_operand, lto_read_body): Set lto_debug_context.tag_names. (input_labels): Fixed latent sizeof issue. (input_function): Build stmt array to set call sites into cgraph edges. (lto_read_body): Reset cfun->curr_properties. * lto_section_in.h (lto_section_slot): New structure. (section_hash_table.lto_file_decl_data): New field. git-svn-id: https://gcc.gnu.org/svn/gcc/branches/lto@132954 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog.lto31
-rw-r--r--gcc/Makefile.in13
-rw-r--r--gcc/cgraph.c20
-rw-r--r--gcc/cgraph.h24
-rw-r--r--gcc/cgraphunit.c15
-rw-r--r--gcc/lto-cgraph-out.c362
-rw-r--r--gcc/lto-cgraph.h53
-rw-r--r--gcc/lto-function-out.c53
-rw-r--r--gcc/lto-header.h11
-rw-r--r--gcc/lto-stream-debug.c29
-rw-r--r--gcc/lto-tags.h4
-rw-r--r--gcc/lto/ChangeLog37
-rw-r--r--gcc/lto/Make-lang.in19
-rw-r--r--gcc/lto/lto-cgraph-in.c245
-rw-r--r--gcc/lto/lto-elf.c102
-rw-r--r--gcc/lto/lto-function-in.c49
-rw-r--r--gcc/lto/lto-section-in.c68
-rw-r--r--gcc/lto/lto-section-in.h36
-rw-r--r--gcc/lto/lto.c147
-rw-r--r--gcc/lto/lto.h26
-rw-r--r--gcc/passes.c1
-rw-r--r--gcc/tree-pass.h1
-rw-r--r--gcc/varpool.c4
23 files changed, 1202 insertions, 148 deletions
diff --git a/gcc/ChangeLog.lto b/gcc/ChangeLog.lto
index 1d5fa4d7f0f..a1d7e97ece7 100644
--- a/gcc/ChangeLog.lto
+++ b/gcc/ChangeLog.lto
@@ -1,3 +1,34 @@
+2008-03-05 Kenneth Zadeck <zadeck@naturalbridge.com>
+ Jan Hubicka <jh@suse.cz>
+
+ * cgraph.h (cgraph_local_info): Added lto_file_data.
+ (cgraph_decide_is_function_needed): Made public.
+ * tree-pass.h (pass_ipa_lto_cgraph_out): New lto pass.
+ * lto-function-out.c (LTO_tag_names): Renamed to LTO_tree_tag_names.
+ (current_stmt_uid): Removed.
+ (create_output_block): Moved call to lto_get_output_decl_state and set
+ lto_debug_context.tag_names.
+ (output_expr_operand, output_bb, output_constructors_and_inits):
+ Removed current_stmt_id.
+ (lto_static_init): Renamed LTO_tag_names to LTO_tree_tag_names
+ (output_function): Added debugging code.
+ * cgraphunit.c (decide_is_function_needed): Renamed to
+ cgraph_decide_is_function_needed and made public.
+ (cgraph_analyze_functions): Only analyze unanalyzed functions.
+ * lto-cgraph.h: New file.
+ * lto-header.h (LTO_DEBUG_FN_NAME): New macro.
+ (struct lto_debug_context.tag_names): New field.
+ (lto_debug_fn_name): New function.
+ * lto-tags.h (LTO_last_tag): Renamed to LTO_tree_last_tag.
+ * lto-stream-debug.c (lto_debug_indent): Get tag from context.
+ (lto_debug_fn_name): New function.
+ * Makefile.in (lto-stream-debug.o, lto-cgraph-out.o, varpool.o):
+ Fixed dependencies.
+ * passes.c (init_optimization_passes): New
+ pass_ipa_lto_cgraph_out.
+ * lto-cgraph-out.c: New file.
+ * varpool.c (decide_is_variable_needed): Check for in_lto_p.
+
2008-02-09 Kenneth Zadeck <zadeck@naturalbridge.com>
* tree-pass.h: (pass_ipa_lto_out): Renamed to pass_ipa_lto_gimple_out.
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 723de475788..634046b98e9 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1087,6 +1087,7 @@ OBJS-common = \
loop-unroll.o \
loop-unswitch.o \
lower-subreg.o \
+ lto-cgraph-out.o \
lto-function-out.o \
lto-section-out.o \
lto-stream-debug.o \
@@ -1962,8 +1963,14 @@ convert.o: convert.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
double-int.o: double-int.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H)
lto-stream-debug.o : lto-stream-debug.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
- toplev.h $(FLAGS_H) $(PARAMS_H) input.h debug.h $(LTO_TAGS_H) \
- lto-header.h lto-tree-flags.def lto-tree-tags.def $(TREE_H)
+ toplev.h $(FLAGS_H) $(PARAMS_H) input.h debug.h $(TREE_H) \
+ lto-header.h
+lto-cgraph-out.o : lto-cgraph-out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+ $(TM_H) toplev.h $(TREE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \
+ $(VARRAY_H) $(HASHTAB_H) langhooks.h $(BASIC_BLOCK_H) tree-iterator.h \
+ tree-pass.h tree-flow.h $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_H) \
+ except.h debug.h $(TIMEVAR_H) \
+ lto-cgraph.h lto-header.h lto-section-out.h output.h dwarf2asm.h dwarf2out.h
lto-function-out.o : lto-function-out.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
$(TM_H) toplev.h $(TREE_H) $(EXPR_H) $(FLAGS_H) $(PARAMS_H) input.h \
$(VARRAY_H) $(HASHTAB_H) langhooks.h $(BASIC_BLOCK_H) tree-iterator.h \
@@ -2504,7 +2511,7 @@ varpool.o : varpool.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
$(TARGET_H) $(CGRAPH_H) intl.h pointer-set.h $(FUNCTION_H) $(TREE_GIMPLE_H) \
$(TREE_FLOW_H) tree-pass.h $(C_COMMON_H) debug.h $(DIAGNOSTIC_H) \
$(FIBHEAP_H) output.h $(PARAMS_H) $(RTL_H) $(TIMEVAR_H) ipa-prop.h \
- gt-varpool.h
+ gt-varpool.h $(FLAGS_H)
ipa.o : ipa.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(CGRAPH_H) $(FLAGS_H)
ipa-prop.o : ipa-prop.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
langhooks.h $(GGC_H) $(TARGET_H) $(CGRAPH_H) ipa-prop.h \
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index a8bb3eec5dd..4a5f6d523e3 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -326,14 +326,20 @@ cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee,
tree call_stmt, gcov_type count, int freq, int nest)
{
struct cgraph_edge *edge = GGC_NEW (struct cgraph_edge);
-#ifdef ENABLE_CHECKING
- struct cgraph_edge *e;
- for (e = caller->callees; e; e = e->next_callee)
- gcc_assert (e->call_stmt != call_stmt);
+ /* LTO does not actually have access to the call_stmt since these
+ have not been loaded yet. */
+ if (call_stmt)
+ {
+#ifdef ENABLE_CHECKING
+ struct cgraph_edge *e;
+
+ for (e = caller->callees; e; e = e->next_callee)
+ gcc_assert (e->call_stmt != call_stmt);
#endif
-
- gcc_assert (get_call_expr_in (call_stmt));
+
+ gcc_assert (get_call_expr_in (call_stmt));
+ }
if (!DECL_SAVED_TREE (callee->decl))
edge->inline_failed = N_("function body not available");
@@ -366,7 +372,7 @@ cgraph_create_edge (struct cgraph_node *caller, struct cgraph_node *callee,
gcc_assert (freq >= 0);
gcc_assert (freq <= CGRAPH_FREQ_MAX);
edge->loop_nest = nest;
- if (caller->call_site_hash)
+ if (call_stmt && caller->call_site_hash)
{
void **slot;
slot = htab_find_slot_with_hash (caller->call_site_hash,
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 63de65a1fe9..3f624ab287c 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3. If not see
#include "tree.h"
#include "basic-block.h"
+struct lto_file_decl_data;
+
enum availability
{
/* Not yet set by cgraph_function_body_availability. */
@@ -45,6 +47,10 @@ enum availability
AVAIL_LOCAL
};
+/* This is the information that is put into the cgraph local structure
+ to recover a function. */
+struct lto_file_decl_data;
+
extern const char * const cgraph_availability_names[];
/* Information about the function collected locally.
@@ -52,6 +58,22 @@ extern const char * const cgraph_availability_names[];
struct cgraph_local_info GTY(())
{
+ /* FIXME: It is quite likely that we really want to do better than
+ just having the file name here. The current api just opens the .o
+ and finds the section index, it then computes the name of the
+ section from the file name sets the file pointer to where the
+ section starts. We could of course do better than this by putting a
+ start and length field for the section into the
+ lto_function_recovery_info. However we need to be careful to do
+ this in a way that is .o format independent. .o files with hundreds
+ of small function are unlikely to do well by this.
+
+ Also, when this structure is put into the cgraph, the actual section
+ for the function has not been searched for. So we would want to have
+ offset and length fields for finding the function kept separate from
+ the info about where the file is. */
+ struct lto_file_decl_data * GTY ((skip)) lto_file_data;
+
/* Estimated stack frame consumption by the function. */
HOST_WIDE_INT estimated_self_stack_size;
@@ -349,6 +371,8 @@ struct cgraph_node *save_inline_function_body (struct cgraph_node *);
void record_references_in_initializer (tree);
bool cgraph_process_new_functions (void);
+bool cgraph_decide_is_function_needed (struct cgraph_node *);
+
/* In cgraphbuild.c */
unsigned int rebuild_cgraph_edges (void);
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 260add81d34..9e36face489 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -328,10 +328,12 @@ cgraph_build_cdtor_fns (void)
configury, or (if not doing unit-at-a-time) to something we havn't
seen yet. */
-static bool
-decide_is_function_needed (struct cgraph_node *node, tree decl)
+bool
+cgraph_decide_is_function_needed (struct cgraph_node *node)
{
tree origin;
+ tree decl = node->decl;
+
if (MAIN_NAME_P (DECL_NAME (decl))
&& TREE_PUBLIC (decl))
{
@@ -635,7 +637,7 @@ cgraph_finalize_function (tree decl, bool nested)
if (!flag_unit_at_a_time)
cgraph_analyze_function (node);
- if (decide_is_function_needed (node, decl))
+ if (cgraph_decide_is_function_needed (node))
cgraph_mark_needed_node (node);
/* Since we reclaim unreachable nodes at the end of every language
@@ -1005,10 +1007,11 @@ cgraph_analyze_functions (void)
continue;
}
- gcc_assert (!node->analyzed && node->reachable);
- gcc_assert (DECL_SAVED_TREE (decl));
+ gcc_assert (node->reachable);
+ gcc_assert (node->analyzed || DECL_SAVED_TREE (decl));
- cgraph_analyze_function (node);
+ if (!node->analyzed)
+ cgraph_analyze_function (node);
for (edge = node->callees; edge; edge = edge->next_callee)
if (!edge->callee->reachable)
diff --git a/gcc/lto-cgraph-out.c b/gcc/lto-cgraph-out.c
new file mode 100644
index 00000000000..cb038466495
--- /dev/null
+++ b/gcc/lto-cgraph-out.c
@@ -0,0 +1,362 @@
+/* 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 "dwarf2asm.h"
+#include "dwarf2out.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);
+}
+
+
+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.estimated_self_stack_size);
+ LTO_DEBUG_TOKEN ("self_insns");
+ output_sleb128 (ob, node->local.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);
+
+ /* Turn off some DWARF2 bits. */
+ dwarf2_called_from_lto_p = true;
+
+ 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);
+
+ dwarf2_called_from_lto_p = false;
+
+ return 0;
+}
+
+struct tree_opt_pass pass_ipa_lto_cgraph_out =
+{
+ "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 */
+ 0 /* letter */
+};
+
diff --git a/gcc/lto-cgraph.h b/gcc/lto-cgraph.h
new file mode 100644
index 00000000000..ef360a92237
--- /dev/null
+++ b/gcc/lto-cgraph.h
@@ -0,0 +1,53 @@
+/* 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-out.c b/gcc/lto-function-out.c
index 2d7df6f4f7a..26c04510d56 100644
--- a/gcc/lto-function-out.c
+++ b/gcc/lto-function-out.c
@@ -59,7 +59,7 @@ sbitmap lto_flags_needed_for;
sbitmap lto_types_needed_for;
#ifdef LTO_STREAM_DEBUGGING
-const char *LTO_tag_names[LTO_last_tag];
+const char *LTO_tree_tag_names[LTO_tree_last_tag];
#endif
@@ -203,10 +203,6 @@ struct output_block
if we are serializing something else. */
struct cgraph_node *cgraph_node;
- /* The current stmt_uid of the statement we are serializing. -1 if
- we are not serializing a statement. */
- int current_stmt_uid;
-
/* These are the last file and line that were seen in the stream.
If the current node differs from these, it needs to insert
something into the stream and fix these up. */
@@ -244,9 +240,9 @@ create_output_block (enum lto_section_type section_type)
struct output_block *ob = xcalloc (1, sizeof (struct output_block));
ob->section_type = section_type;
+ ob->decl_state = lto_get_out_decl_state ();
ob->main_stream = xcalloc (1, sizeof (struct lto_output_stream));
ob->string_stream = xcalloc (1, sizeof (struct lto_output_stream));
- ob->decl_state = lto_get_out_decl_state ();
if (section_type == LTO_section_function_body)
{
@@ -259,6 +255,7 @@ create_output_block (enum lto_section_type section_type)
#ifdef LTO_STREAM_DEBUGGING
lto_debug_context.out = lto_debug_out_fun;
lto_debug_context.indent = 0;
+ lto_debug_context.tag_names = LTO_tree_tag_names;
#endif
clear_line_info (ob);
@@ -1153,17 +1150,6 @@ output_expr_operand (struct output_block *ob, tree expr)
{
unsigned int count = TREE_INT_CST_LOW (TREE_OPERAND (expr, 0));
unsigned int i;
- struct cgraph_edge *e = ob->cgraph_node->callees;
-
-
- gcc_assert (ob->cgraph_node);
- gcc_assert (ob->current_stmt_uid != -1);
-
- while (e)
- {
- e->lto_stmt_uid = ob->current_stmt_uid;
- e = e->next_callee;
- }
/* Operand 2 is the call chain. */
if (TREE_OPERAND (expr, 2))
@@ -1520,13 +1506,9 @@ output_local_vars (struct output_block *ob, struct function *fn)
bitmap_set_bit (local_statics, DECL_UID (lv));
output_expr_operand (ob, lv);
if (DECL_CONTEXT (lv) == fn->decl)
- {
- output_uleb128 (ob, 1); /* Restore context. */
- }
+ output_uleb128 (ob, 1); /* Restore context. */
else
- {
- output_zero (ob); /* Restore context. */
- }
+ output_zero (ob); /* Restore context. */
if (DECL_INITIAL (lv))
output_expr_operand (ob, DECL_INITIAL (lv));
else
@@ -1732,8 +1714,6 @@ output_bb (struct output_block *ob, basic_block bb, struct function *fn)
{
tree stmt = bsi_stmt (bsi);
- ob->current_stmt_uid = gimple_stmt_uid (stmt);
-
LTO_DEBUG_INDENT_TOKEN ("stmt");
output_expr_operand (ob, stmt);
@@ -1758,8 +1738,6 @@ output_bb (struct output_block *ob, basic_block bb, struct function *fn)
LTO_DEBUG_INDENT_TOKEN ("stmt");
output_zero (ob);
- ob->current_stmt_uid = -1;
-
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
{
LTO_DEBUG_INDENT_TOKEN ("phi");
@@ -1935,7 +1913,7 @@ lto_static_init (void)
#ifdef LTO_STREAM_DEBUGGING
#define LTO_STREAM_DEBUGGING_INIT_NAMES
-#define SET_NAME(index,value) LTO_tag_names[index] = value;
+#define SET_NAME(index,value) LTO_tree_tag_names[index] = value;
#include "lto-tree-tags.def"
#undef SET_NAME
#undef LTO_STREAM_DEBUGGING_INIT_NAMES
@@ -1995,7 +1973,6 @@ output_function (struct cgraph_node* node)
LTO_SET_DEBUGGING_STREAM (debug_main_stream, main_data);
clear_line_info (ob);
ob->cgraph_node = node;
- ob->current_stmt_uid = -1;
gcc_assert (!current_function_decl && !cfun);
@@ -2035,6 +2012,20 @@ output_function (struct cgraph_node* node)
statement numbers. */
renumber_gimple_stmt_uids ();
+#ifdef LOCAL_TRACE
+ fprintf (stderr, "%s\n", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (function)));
+ FOR_ALL_BB_FN (bb, fn)
+ {
+ block_stmt_iterator bsi;
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ tree stmt = bsi_stmt (bsi);
+ fprintf (stderr, "%d = ", gimple_stmt_uid (stmt));
+ print_generic_stmt (stderr, stmt, 0);
+ }
+ }
+#endif
+
/* Output the code for the function. */
FOR_ALL_BB_FN (bb, fn)
output_bb (ob, bb, fn);
@@ -2058,8 +2049,7 @@ output_function (struct cgraph_node* node)
LTO_SET_DEBUGGING_STREAM (debug_label_stream, label_data);
output_named_labels (ob);
- /* Create a file to hold the pickled output of this function. This
- is a temp standin until we start writing sections. */
+ /* Create a section to hold the pickled output of this function. */
produce_asm (ob, function);
destroy_output_block (ob);
@@ -2079,7 +2069,6 @@ output_constructors_and_inits (void)
struct varpool_node *vnode;
ob->cgraph_node = NULL;
- ob->current_stmt_uid = -1;
LTO_SET_DEBUGGING_STREAM (debug_main_stream, main_data);
clear_line_info (ob);
diff --git a/gcc/lto-header.h b/gcc/lto-header.h
index 6d5dd54b7f2..9c2e3ce18b2 100644
--- a/gcc/lto-header.h
+++ b/gcc/lto-header.h
@@ -63,6 +63,9 @@ section *lto_get_section (enum lto_section_type, const char *);
#define LTO_STREAM_DEBUGGING
#ifdef LTO_STREAM_DEBUGGING
+
+struct lto_debug_context;
+
#define LTO_DEBUG_INDENT(tag) \
lto_debug_indent (&lto_debug_context, tag)
#define LTO_DEBUG_INDENT_TOKEN(value) \
@@ -73,6 +76,8 @@ section *lto_get_section (enum lto_section_type, const char *);
lto_debug_string (&lto_debug_context, value, len)
#define LTO_DEBUG_TOKEN(value) \
lto_debug_token (&lto_debug_context, value)
+#define LTO_DEBUG_FN_NAME(value) \
+ lto_debug_fn_name (&lto_debug_context, value)
#define LTO_DEBUG_TREE_FLAGS(code,value) \
lto_debug_tree_flags (&lto_debug_context, code, flags)
#define LTO_DEBUG_UNDENT() \
@@ -80,9 +85,6 @@ section *lto_get_section (enum lto_section_type, const char *);
#define LTO_DEBUG_WIDE(tag,value) \
lto_debug_wide (&lto_debug_context, tag, value)
-
-struct lto_debug_context;
-
typedef void (*lto_debug_out) (struct lto_debug_context *context, char c);
struct lto_debug_context
@@ -96,6 +98,7 @@ struct lto_debug_context
void * ssa_names_data;
void * cfg_data;
void * main_data;
+ const char ** tag_names;
};
extern struct lto_debug_context lto_debug_context;
@@ -105,6 +108,7 @@ extern void lto_debug_indent_token (struct lto_debug_context *, const char *);
extern void lto_debug_integer (struct lto_debug_context *, const char *, HOST_WIDE_INT, HOST_WIDE_INT);
extern void lto_debug_string (struct lto_debug_context *, const char *, int);
extern void lto_debug_token (struct lto_debug_context *, const char *);
+extern void lto_debug_fn_name (struct lto_debug_context *, const tree);
extern void lto_debug_undent (struct lto_debug_context *);
extern void lto_debug_wide (struct lto_debug_context *, const char *, HOST_WIDE_INT);
@@ -114,6 +118,7 @@ extern void lto_debug_wide (struct lto_debug_context *, const char *, HOST_WIDE_
#define LTO_DEBUG_INTEGER(tag,high,low) (void)0
#define LTO_DEBUG_STRING(value,len) (void)0
#define LTO_DEBUG_TOKEN(value) (void)0
+#define LTO_DEBUG_FN_NAME(value) (void)0
#define LTO_DEBUG_TREE_FLAGS(code, value) (void)0
#define LTO_DEBUG_UNDENT() (void)0
#define LTO_DEBUG_WIDE(tag,value) (void)0
diff --git a/gcc/lto-stream-debug.c b/gcc/lto-stream-debug.c
index f0e828f7938..d983aedbb5f 100644
--- a/gcc/lto-stream-debug.c
+++ b/gcc/lto-stream-debug.c
@@ -29,12 +29,11 @@ Boston, MA 02110-1301, USA. */
#include "input.h"
#include "debug.h"
#include "lto-header.h"
-#include "lto-tags.h"
+#include "tree.h"
#include <ctype.h>
#ifdef LTO_STREAM_DEBUGGING
-
/* Print VALUE to CONTEXT. */
static void
@@ -66,7 +65,7 @@ lto_debug_indent (struct lto_debug_context *context,
int tag)
{
int i;
- const char *tag_name = LTO_tag_names[tag];
+ const char *tag_name = context->tag_names[tag];
context->out (context, '\n');
for (i=0; i<context->indent; i++)
context->out (context, ' ');
@@ -127,6 +126,30 @@ lto_debug_token (struct lto_debug_context *context,
}
+/* Write a function name for FN to CONTEXT. */
+
+void
+lto_debug_fn_name (struct lto_debug_context *context,
+ const tree fn)
+{
+ const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fn));
+ char *dot = index (name, '.');
+ int len;
+
+ /* The dwarf reader sometimes adds .nnn to the end of function
+ names. This will mess up the verification protocol since the
+ input will not exactly the output. */
+ if (dot)
+ len = dot - name;
+ else
+ len = strlen (name);
+
+ lto_debug_string_internal (context, " ", 1);
+ lto_debug_string_internal (context, name, len);
+ lto_debug_string_internal (context, " ", 1);
+}
+
+
/* Write ")\n" to CONTEXT and decrement indent. */
void
diff --git a/gcc/lto-tags.h b/gcc/lto-tags.h
index 05bcf021149..33eae2c34b6 100644
--- a/gcc/lto-tags.h
+++ b/gcc/lto-tags.h
@@ -461,7 +461,7 @@ enum LTO_tags {
These next two tags must have their last hex digit be 0. */
LTO_local_var_decl_body0 = 0x0C0,
LTO_parm_decl_body0 = 0x0D0,
- LTO_last_tag = 0x0E0
+ LTO_tree_last_tag = 0x0E0
};
/* This bitmap is indexed by gimple type codes and contains a 1 if the
@@ -501,7 +501,7 @@ typedef unsigned HOST_WIDEST_INT lto_flags_type;
#endif
#ifdef LTO_STREAM_DEBUGGING
-extern const char * LTO_tag_names[LTO_last_tag];
+extern const char * LTO_tree_tag_names[LTO_tree_last_tag];
extern void lto_debug_tree_flags (struct lto_debug_context *, enum tree_code, lto_flags_type);
#endif
diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog
index 1269dd7e442..d2d5bf80517 100644
--- a/gcc/lto/ChangeLog
+++ b/gcc/lto/ChangeLog
@@ -1,3 +1,40 @@
+2008-03-05 Kenneth Zadeck <zadeck@naturalbridge.com>
+ Jan Hubicka <jh@suse.cz>
+
+ * lto.c (lto_info_fd_init, lto_info_fd_close): Get rid of
+ fd->unmaterialized_fndecls.
+ (lto_get_file_name, lto_materialize_cgraph): New function.
+ (lto_materialize_constructors_and_inits,
+ lto_materialize_function): Read info directly from elf file.
+ (lto_file_read): Made local and initialize dictionary so that
+ other lto sections can be read without reprocessing the elf file.
+ (lto_main): Read all functions after all files have been processed
+ for their types, globals and cgraph.
+ * Make-lang.in (lto.o, lto-cgraph-in.c, lto-section-in): Changed
+ dependencies.
+ * lto-elf.c (lto_elf_file): Removed strtab, symtab fields.
+ (hash_name, eq_name, lto_elf_build_section_table): New functions.
+ (lto_elf_read_symtab): Removed function.
+ (lto_elf_file_open): Removed call to lto_elf_read_symtab.
+ * lto.h (lto_info_fd_struct): Removed unmaterialized_fndecls.
+ (lto_file_read): Made local.
+ (lto_get_file_name, lto_elf_build_section_table,
+ lto_input_cgraph):
+ New function.
+ * lto-section-in.c (lto_read_section_data, lto_get_section_data):
+ New functions.
+ (lto_read_decls): Get the file name.
+ * lto-cgraph-in.c: New file.
+ * lto-function-in.c (tag_to_expr): Stops at LTO_tree_last_tag.
+ (input_expr_operand, lto_read_body): Set lto_debug_context.tag_names.
+ (input_labels): Fixed latent sizeof issue.
+ (input_function): Build stmt array to set call sites into cgraph
+ edges.
+ (lto_read_body): Reset cfun->curr_properties.
+ * lto_section_in.h (lto_section_slot): New structure.
+ (section_hash_table.lto_file_decl_data): New field.
+
+
2008-02-09 Kenneth Zadeck <zadeck@naturalbridge.com>
* lto.c (lto_read_variable_formal_parameter_const): Remove code to
diff --git a/gcc/lto/Make-lang.in b/gcc/lto/Make-lang.in
index 7ee9e17557c..3277e201cbc 100644
--- a/gcc/lto/Make-lang.in
+++ b/gcc/lto/Make-lang.in
@@ -26,8 +26,8 @@
# The name of the LTO compiler.
LTO_EXE = lto1$(exeext)
# The LTO-specific object files inclued in $(LTO_EXE).
-LTO_OBJS = lto/lto-lang.o lto/lto.o lto/lto-elf.o lto/lto-function-in.o \
- lto/lto-section-in.o lto/lto-symtab.o attribs.o
+LTO_OBJS = lto/lto-lang.o lto/lto.o lto/lto-elf.o lto/lto-cgraph-in.o \
+ lto/lto-function-in.o lto/lto-section-in.o lto/lto-symtab.o attribs.o
LTO_H = lto/lto.h lto-header.h lto/lto-section-in.h $(HASHTAB_H) $(TREE_H)
########################################################################
@@ -81,11 +81,18 @@ lto/lto-lang.o: lto/lto-lang.c $(CONFIG_H) coretypes.h debug.h \
$(TM_H) lto/lto-tree.h $(LTO_H) gtype-lto.h gt-lto-lto-lang.h
lto/lto.o: lto/lto.c $(CONFIG_H) $(CGRAPH_H) coretypes.h dwarf2.h \
$(GGC_H) opts.h $(SYSTEM_H) toplev.h $(TM_H) $(LTO_H) \
- gt-lto-lto.h
+ gt-lto-lto.h lto/lto-section-in.h
lto/lto-elf.o: lto/lto-elf.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \
- toplev.h $(LTO_H) $(LTO_TAGS_H) $(TM_H)
+ toplev.h $(LTO_H) $(TM_H)
lto/lto-symtab.o: lto/lto-symtab.c $(CONFIG_H) coretypes.h \
$(SYSTEM_H) toplev.h $(LTO_H) lto/lto-tree.h
+lto/lto-cgraph-in.o: lto/lto-cgraph-in.c $(CONFIG_H) $(SYSTEM_H) \
+ coretypes.h $(TM_H) toplev.h $(LTO_H) $(EXPR_H) $(FLAGS_H) \
+ $(PARAMS_H) input.h $(VARRAY_H) $(HASHTAB_H) langhooks.h \
+ $(BASIC_BLOCK_H) tree-iterator.h tree-pass.h tree-flow.h \
+ $(CGRAPH_H) $(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_H) \
+ except.h debug.h $(TIMEVAR_H) $(LTO_TAGS_H) lto-cgraph.h \
+ lto/lto-section-in.h output.h dwarf2asm.h dwarf2out.h
lto/lto-function-in.o: lto/lto-function-in.c $(CONFIG_H) $(SYSTEM_H) \
coretypes.h $(TM_H) toplev.h $(LTO_H) $(EXPR_H) $(FLAGS_H) \
$(PARAMS_H) input.h $(VARRAY_H) $(HASHTAB_H) langhooks.h \
@@ -98,5 +105,5 @@ lto/lto-section-in.o: lto/lto-section-in.c $(CONFIG_H) $(SYSTEM_H) \
$(PARAMS_H) input.h $(VARRAY_H) $(HASHTAB_H) langhooks.h \
$(BASIC_BLOCK_H) tree-iterator.h tree-pass.h tree-flow.h \
$(CGRAPH_H) $(FUNCTION_H) $(GGC_H) $(DIAGNOSTIC_H) \
- except.h debug.h $(TIMEVAR_H) lto-tree-flags.def \
- lto-tree-tags.def lto/lto.h lto/lto-section-in.h output.h dwarf2asm.h dwarf2out.h
+ except.h debug.h $(TIMEVAR_H) lto/lto.h lto/lto-section-in.h \
+ output.h dwarf2asm.h dwarf2out.h
diff --git a/gcc/lto/lto-cgraph-in.c b/gcc/lto/lto-cgraph-in.c
new file mode 100644
index 00000000000..12d986b1a5e
--- /dev/null
+++ b/gcc/lto/lto-cgraph-in.c
@@ -0,0 +1,245 @@
+/* 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 "dwarf2asm.h"
+#include "dwarf2out.h"
+#include "output.h"
+#include "lto-cgraph.h"
+#include "lto.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.estimated_self_stack_size = stack_size;
+ node->local.self_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 void *data)
+{
+ struct lto_cgraph_header * header
+ = (struct lto_cgraph_header *) data;
+ struct data_in data_in;
+
+ 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
+ = {data + debug_main_offset, 0, header->debug_main_size};
+#endif
+
+ struct lto_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_debug_context.current_data = &debug_main;
+ lto_debug_context.indent = 0;
+ 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/lto-elf.c b/gcc/lto/lto-elf.c
index c5a1fc47a56..7f96d535d82 100644
--- a/gcc/lto/lto-elf.c
+++ b/gcc/lto/lto-elf.c
@@ -33,7 +33,6 @@ Boston, MA 02110-1301, USA. */
# error "libelf.h not available"
# endif
#endif
-#include "lto-tags.h"
#include "tm.h"
#include "libiberty.h"
#include "ggc.h"
@@ -49,12 +48,8 @@ struct lto_elf_file
Elf *elf;
/* 32 or 64 bits? */
size_t bits;
- /* Section number of section table. */
- size_t strtab;
/* Section number of string table used for section names. */
size_t sec_strtab;
- /* The ELF symbol table. */
- Elf_Data *symtab;
};
typedef struct lto_elf_file lto_elf_file;
@@ -186,30 +181,102 @@ lto_elf_find_section_data (lto_elf_file *elf_file, const char *section_name)
return data;
}
-/* Read the ELF symbol table from ELF_FILE. */
-static void
-lto_elf_read_symtab (lto_elf_file *elf_file)
+
+/* Returns a hash code for P. */
+
+static hashval_t
+hash_name (const void *p)
+{
+ const struct lto_section_slot *ds = (const struct lto_section_slot *) p;
+ return (hashval_t) htab_hash_string (ds->name);
+}
+
+
+/* Returns nonzero if P1 and P2 are equal. */
+
+static int
+eq_name (const void *p1, const void *p2)
+{
+ const struct lto_section_slot *s1 =
+ (const struct lto_section_slot *) p1;
+ const struct lto_section_slot *s2 =
+ (const struct lto_section_slot *) p2;
+
+ return strcmp (s1->name, s2->name) == 0;
+}
+
+
+/* Build a hash table whose key is the section names and whose data is
+ the start and size of each section in the .o file.
+
+ FIXME! This code will most likely require an upgrade when it comes
+ time to try to read archive files. This means that when we start
+ randomly reading functions out of archives, we will need to load
+ the member of the archive manually rather than just opening the
+ archive as a file and lseeking to the start of the function. */
+
+htab_t
+lto_elf_build_section_table (lto_file *lto_file)
{
+ lto_elf_file *elf_file = (lto_elf_file *)lto_file;
+ htab_t section_hash_table;
Elf_Scn *section;
- Elf64_Shdr *shdr;
- /* Iterate over the section table until we find one with type
- SHT_SYMTAB. */
+ section_hash_table
+ = htab_create (37, hash_name, eq_name, free);
+
for (section = elf_getscn (elf_file->elf, 0);
section;
- section = elf_nextscn (elf_file->elf, section))
+ section = elf_nextscn (elf_file->elf, section))
{
+ Elf64_Shdr *shdr;
+ const char *name;
+ size_t offset;
+ char *new_name;
+ void **slot;
+ struct lto_section_slot s_slot;
+
+ /* Get the name of this section. */
shdr = lto_elf_get_shdr (elf_file, section);
- if (shdr->sh_type == SHT_SYMTAB)
+ offset = shdr->sh_name;
+ name = elf_strptr (elf_file->elf,
+ elf_file->sec_strtab,
+ offset);
+
+ /* Only put lto stuff into the symtab. */
+ if (strncmp (name, LTO_SECTION_NAME_PREFIX,
+ strlen (LTO_SECTION_NAME_PREFIX)) != 0)
{
- /* We have found the symbol table. */
- elf_file->symtab = elf_getdata (section, NULL);
- elf_file->strtab = shdr->sh_link;
+ lto_elf_free_shdr (elf_file, shdr);
+ continue;
+ }
+
+ new_name = xmalloc (strlen (name) + 1);
+ strcpy (new_name, name);
+ s_slot.name = new_name;
+ slot = htab_find_slot (section_hash_table, &s_slot, INSERT);
+ if (*slot == NULL)
+ {
+ struct lto_section_slot *new_slot
+ = xmalloc (sizeof (struct lto_section_slot));
+
+ new_slot->name = new_name;
+ /* The offset into the file for this section. */
+ new_slot->start = shdr->sh_offset;
+ new_slot->len = shdr->sh_size;
+ *slot = new_slot;
+ }
+ else
+ {
+ error ("two or more sections for %s:", new_name);
+ return NULL;
}
lto_elf_free_shdr (elf_file, shdr);
}
+ return section_hash_table;
}
+
lto_file *
lto_elf_file_open (const char *filename)
{
@@ -336,9 +403,6 @@ lto_elf_file_open (const char *filename)
fd->start = (const char *) data->d_buf;
fd->end = fd->start + data->d_size;
- /* Read the ELF symbol table. */
- lto_elf_read_symtab (elf_file);
-
return result;
fail:
diff --git a/gcc/lto/lto-function-in.c b/gcc/lto/lto-function-in.c
index 752b761e77a..23b63c7a8e6 100644
--- a/gcc/lto/lto-function-in.c
+++ b/gcc/lto/lto-function-in.c
@@ -54,7 +54,7 @@ Boston, MA 02110-1301, USA. */
#include <ctype.h>
#include "cpplib.h"
-static enum tree_code tag_to_expr[LTO_last_tag];
+static enum tree_code tag_to_expr[LTO_tree_last_tag];
/* The number of flags that are defined for each tree code. */
static int flags_length_for_code[NUM_TREE_CODES];
@@ -657,6 +657,7 @@ input_expr_operand (struct lto_input_block *ib, struct data_in *data_in,
lto_debug_context.indent = 0;
lto_debug_context.current_data = &debug;
+ lto_debug_context.tag_names = LTO_tree_tag_names;
#endif
lib.data = ib->data;
lib.len = ib->len;
@@ -668,6 +669,7 @@ input_expr_operand (struct lto_input_block *ib, struct data_in *data_in,
#ifdef LTO_STREAM_DEBUGGING
lto_debug_context.indent = current_indent;
lto_debug_context.current_data = current;
+ lto_debug_context.tag_names = LTO_tree_tag_names;
#endif
}
@@ -1061,7 +1063,7 @@ input_labels (struct lto_input_block *ib, struct data_in *data_in,
code, the unnamed labels have a negative index. Their position
in the array can be found by subtracting that index from the
number of named labels. */
- data_in->labels = xcalloc (named_count + unnamed_count, sizeof (tree*));
+ data_in->labels = xcalloc (named_count + unnamed_count, sizeof (tree));
for (i = 0; i < named_count; i++)
{
unsigned int name_index = lto_input_uleb128 (ib);
@@ -1169,12 +1171,10 @@ input_local_var (struct lto_input_block *ib, struct data_in *data_in,
TREE_CHAIN (result) = NULL_TREE;
}
-
flags = input_tree_flags (ib, 0, true);
if (input_line_info (ib, data_in, flags))
set_line_info (data_in, result);
-
LTO_DEBUG_TOKEN ("context");
context = input_expr_operand (ib, data_in, fn, input_record_start (ib));
if (TYPE_P (context))
@@ -1516,6 +1516,9 @@ input_function (tree fn_decl, struct data_in *data_in,
{
struct function *fn = DECL_STRUCT_FUNCTION (fn_decl);
enum LTO_tags tag = input_record_start (ib);
+ tree *stmts;
+ struct cgraph_edge *cedge;
+ basic_block bb;
DECL_INITIAL (fn_decl) = DECL_SAVED_TREE (fn_decl) = make_node (BLOCK);
BLOCK_ABSTRACT_ORIGIN (DECL_SAVED_TREE (fn_decl)) = fn_decl;
@@ -1543,7 +1546,41 @@ input_function (tree fn_decl, struct data_in *data_in,
tag = input_record_start (ib);
}
+ /* Fix up the call stmts that are mentioned in the cgraph_edges. */
renumber_gimple_stmt_uids ();
+ stmts = xcalloc (gimple_stmt_max_uid(fn), sizeof (tree));
+ FOR_ALL_BB (bb)
+ {
+ block_stmt_iterator bsi;
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ tree stmt = bsi_stmt (bsi);
+ stmts [gimple_stmt_uid (stmt)] = stmt;
+#ifdef LOCAL_TRACE
+ fprintf (stderr, "%d = ", gimple_stmt_uid (stmt));
+ print_generic_stmt (stderr, stmt, 0);
+#endif
+ }
+ }
+
+#ifdef LOCAL_TRACE
+ fprintf (stderr, "%s\n", IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fn_decl)));
+#endif
+
+ cedge = cgraph_node (fn_decl)->callees;
+ while (cedge)
+ {
+ cedge->call_stmt = stmts [cedge->lto_stmt_uid];
+#ifdef LOCAL_TRACE
+ fprintf (stderr, "fixing up call %d\n", cedge->lto_stmt_uid);
+#endif
+ cedge = cedge->next_callee;
+ }
+#ifdef LOCAL_TRACE
+ fprintf (stderr, "\n");
+#endif
+
+ free (stmts);
LTO_DEBUG_UNDENT();
}
@@ -1685,6 +1722,7 @@ lto_static_init_local (void)
LTO_section_function_body or LTO_section_static_initializer. IF
section type is LTO_section_function_body, FN must be the decl for
that function. */
+
static void
lto_read_body (struct lto_file_decl_data* file_data,
tree fn_decl,
@@ -1743,6 +1781,7 @@ lto_read_body (struct lto_file_decl_data* file_data,
#ifdef LTO_STREAM_DEBUGGING
lto_debug_context.out = lto_debug_in_fun;
lto_debug_context.indent = 0;
+ lto_debug_context.tag_names = LTO_tree_tag_names;
#endif
memset (&data_in, 0, sizeof (struct data_in));
data_in.file_data = file_data;
@@ -1809,7 +1848,7 @@ lto_read_body (struct lto_file_decl_data* file_data,
/* We should now be in SSA. */
cfun->gimple_df->in_ssa_p = true;
/* Fill in properties we know hold for the rebuilt CFG. */
- cfun->curr_properties = PROP_ssa;
+ cfun->curr_properties = PROP_ssa | PROP_cfg | PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh | PROP_referenced_vars;
pop_cfun ();
}
diff --git a/gcc/lto/lto-section-in.c b/gcc/lto/lto-section-in.c
index 9c483e70a57..07ce7f9e330 100644
--- a/gcc/lto/lto-section-in.c
+++ b/gcc/lto/lto-section-in.c
@@ -50,6 +50,7 @@ Boston, MA 02110-1301, USA. */
#include "output.h"
#include "lto.h"
#include "lto-section.h"
+#include "lto-section-in.h"
#include <ctype.h>
#include "cpplib.h"
@@ -184,6 +185,71 @@ lto_input_integer (struct lto_input_block *ib, tree type)
}
}
}
+
+/*****************************************************************************/
+/* Input routines for reading sections from .o files. */
+/*****************************************************************************/
+
+/* Get the section data of length LEN from FILENAME starting at
+ OFFSET. The data segment must be freed by the caller when the
+ caller is finished. Returns NULL if all was not well. */
+
+static char *
+lto_read_section_data (const char *file_name, size_t offset, size_t len)
+{
+ FILE * ofile = fopen (file_name, "r");
+ char * data;
+ int result;
+
+ if (!ofile)
+ return NULL;
+ data = xmalloc (len);
+
+ result = fseek (ofile, offset, SEEK_SET);
+ if (result)
+ {
+ free (data);
+ fclose (ofile);
+ return NULL;
+ }
+ result = fread (data, len, 1, ofile);
+ if (result == 0)
+ {
+ free (data);
+ fclose (ofile);
+ return NULL;
+ }
+
+ fclose (ofile);
+ return data;
+}
+
+
+/* Get the section data from FILE_DATA of SECTION_TYPE with NAME.
+ NAME will be null unless the section type is for a function
+ body. */
+
+char *
+lto_get_section_data (struct lto_file_decl_data *file_data,
+ enum lto_section_type section_type,
+ const char *name)
+{
+ htab_t section_hash_table = file_data->section_hash_table;
+ struct lto_section_slot *f_slot;
+ struct lto_section_slot s_slot;
+ const char *section_name = lto_get_section_name (section_type, name);
+ char * data = NULL;
+
+ s_slot.name = section_name;
+ f_slot = (struct lto_section_slot *)htab_find (section_hash_table, &s_slot);
+ if (f_slot)
+ data = lto_read_section_data (file_data->file_name, f_slot->start, f_slot->len);
+
+ free ((char *)section_name);
+ return data;
+}
+
+
/*****************************************************************************/
/* This part is used to recover all of the global decls and types that are */
/* serialized out so that a table for this file can be built. */
@@ -250,6 +316,8 @@ lto_read_decls (lto_info_fd *fd,
data_in->types[i] = lto_resolve_type_ref (fd, context, &in_types[i]);
data_in->num_types = header->num_types;
+ data_in->file_name = lto_get_file_name (fd);
+
return data_in;
}
diff --git a/gcc/lto/lto-section-in.h b/gcc/lto/lto-section-in.h
index df6514a02e3..c323624037b 100644
--- a/gcc/lto/lto-section-in.h
+++ b/gcc/lto/lto-section-in.h
@@ -29,6 +29,16 @@ struct lto_input_block
};
+/* Hash table entry to hold the start offset and length of an lto
+ section in a .o file. */
+
+struct lto_section_slot {
+ const char * name;
+ unsigned int start;
+ unsigned int len;
+};
+
+
/* One of these is allocated for each object file that being compiled
by lto. This structure contains the tables that are needed for the
by the serialized functions and ipa passes to connect themselves to
@@ -45,17 +55,29 @@ struct lto_file_decl_data
unsigned int num_var_decls; /* The number of global or static var_decls. */
unsigned int num_type_decls; /* The number of type_decls. */
unsigned int num_types; /* All number of of the types. */
+
+ /* The .o file that these offsets relate to.
+
+ FIXME!!! This will most likely have to be upgraded if the .o files
+ have been archived. */
+ const char * file_name;
+
+ /* Hash table to contains the location of the lto bodies in file_name. */
+ htab_t section_hash_table;
};
-unsigned char lto_input_1_unsigned (struct lto_input_block *);
-unsigned HOST_WIDE_INT lto_input_uleb128 (struct lto_input_block *);
-unsigned HOST_WIDEST_INT lto_input_widest_uint_uleb128 (struct lto_input_block *);
-HOST_WIDE_INT lto_input_sleb128 (struct lto_input_block *);
-tree lto_input_integer (struct lto_input_block *, tree);
+
+extern unsigned char lto_input_1_unsigned (struct lto_input_block *);
+extern unsigned HOST_WIDE_INT lto_input_uleb128 (struct lto_input_block *);
+extern unsigned HOST_WIDEST_INT lto_input_widest_uint_uleb128 (struct lto_input_block *);
+extern HOST_WIDE_INT lto_input_sleb128 (struct lto_input_block *);
+extern tree lto_input_integer (struct lto_input_block *, tree);
+extern char *lto_get_section_data (struct lto_file_decl_data *, enum lto_section_type,
+ const char*);
#ifdef LTO_STREAM_DEBUGGING
-void lto_debug_in_fun (struct lto_debug_context *, char);
-void dump_debug_stream (struct lto_input_block *, char, char);
+extern void lto_debug_in_fun (struct lto_debug_context *, char);
+extern void dump_debug_stream (struct lto_input_block *, char, char);
#endif
#endif /* GCC_LTO_SECTION_IN_H */
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index 3ae77152410..14e8181fa75 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -34,6 +34,7 @@ Boston, MA 02110-1301, USA. */
#include "lto-tree.h"
#include "tree-ssa-operands.h" /* For init_ssa_operands. */
#include "langhooks.h"
+#include "lto-section-in.h"
/* References
@@ -197,7 +198,6 @@ lto_info_fd_init (lto_info_fd *fd, const char *name, lto_file *file)
fd->num_units = 0;
fd->units = NULL;
fd->die_cache = htab_create_ggc (37, lto_cache_hash, lto_cache_eq, NULL);
- fd->unmaterialized_fndecls = VEC_alloc (tree, gc, 32);
}
/* Initialize FD, a newly allocated file descriptor for a DWARF2
@@ -220,10 +220,6 @@ lto_info_fd_close (lto_info_fd *fd)
for (i = 0; i < fd->num_units; ++i)
XDELETE (fd->units[i]);
XDELETEVEC (fd->units);
-
- /* Other people are holding references to the trees contained in this,
- so just free the vector. */
- VEC_free (tree, gc, fd->unmaterialized_fndecls);
}
/* Close FD. */
@@ -625,6 +621,15 @@ find_cu_for_offset (const lto_info_fd *fd,
return fd->units[first - 1];
}
+
+/* Get the file name associated with INFO_FD. */
+const char *
+lto_get_file_name (lto_info_fd *info_fd)
+{
+ return info_fd->base.file->filename;
+}
+
+
/* Resolve a reference to the DIE at offset OFFSET. Returns a pointer
to the DIE, as mapped into memory. Sets *NEW_CONTEXT to CONTEXT,
or to a newly allocated context corresponding to the DIE referred
@@ -2394,7 +2399,14 @@ lto_read_abbrev (lto_info_fd *fd)
return abbrev;
}
-/* Return a pointer to the data for DECL if possible, NULL otherwise. */
+
+/* Return a pointer to the data for DECL if possible, NULL otherwise.
+ FIXME!!! This function will go away when we stop using dwarf for
+ the globals and types. The big difference between this and
+ lto_read_section_data is that this function interpretes uses calls
+ to libelf that cause the data to be interpreted (copied and
+ otherwise manipulated) in a manner that is not necessary for the
+ stream protocols that are used for the rest of lto. */
static const void *
lto_get_body (lto_info_fd *fd,
@@ -2411,48 +2423,65 @@ lto_get_body (lto_info_fd *fd,
/* Read the constructors and initsof FD if possible. */
static void
-lto_materialize_constructors_and_inits (lto_info_fd *fd,
- lto_context *context,
- struct lto_file_decl_data * file_data)
+lto_materialize_constructors_and_inits (struct lto_file_decl_data * file_data)
{
- lto_file *file = fd->base.file;
- const void *body = lto_get_body (fd, context, LTO_section_static_initializer, NULL);
-
- lto_input_constructors_and_inits (file_data, body);
- file->vtable->unmap_section (file, NULL, body);
+ const char *data = lto_get_section_data (file_data, LTO_section_static_initializer, NULL);
+ lto_input_constructors_and_inits (file_data, data);
+ free ((char *)data);
}
/* Read the function body for DECL out of FD if possible. */
static void
-lto_materialize_function (lto_info_fd *fd,
- lto_context *context,
- struct lto_file_decl_data * file_data,
- tree decl)
+lto_materialize_function (struct cgraph_node *node)
{
- lto_file *file = fd->base.file;
- const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
- const void *body = lto_get_body (fd, context, LTO_section_function_body, name);
+ tree decl = node->decl;
+ struct lto_file_decl_data *file_data = node->local.lto_file_data;
+ const char *data = lto_get_section_data (file_data,
+ LTO_section_function_body,
+ IDENTIFIER_POINTER (DECL_NAME (decl)));
+ tree step;
- if (body)
+ if (data)
{
/* This function has a definition. */
TREE_STATIC (decl) = 1;
DECL_EXTERNAL (decl) = 0;
allocate_struct_function (decl);
- lto_input_function_body (file_data, decl, body);
- file->vtable->unmap_section (file, name, body);
+ lto_input_function_body (file_data, decl, data);
+ free ((char *)data);
}
else
DECL_EXTERNAL (decl) = 1;
+ /* Look for initializers of constant variables and private statics. */
+ for (step = cfun->unexpanded_var_list;
+ step;
+ step = TREE_CHAIN (step))
+ {
+ tree decl = TREE_VALUE (step);
+ if (TREE_CODE (decl) == VAR_DECL
+ && (TREE_STATIC (decl) && !DECL_EXTERNAL (decl))
+ && flag_unit_at_a_time)
+ varpool_finalize_decl (decl);
+ }
/* Let the middle end know about the function. */
rest_of_decl_compilation (decl,
/*top_level=*/1,
/*at_end=*/0);
- if (body)
- cgraph_finalize_function (decl, /*nested=*/false);
+ if (cgraph_node (decl)->needed)
+ cgraph_mark_reachable_node (cgraph_node (decl));
+}
+
+/* Read the function body for DECL out of FD if possible. */
+
+static void
+lto_materialize_cgraph (struct lto_file_decl_data * file_data)
+{
+ const char *data = lto_get_section_data (file_data, LTO_section_cgraph, NULL);
+ lto_input_cgraph (file_data, data);
+ free ((char *)data);
}
/* Read the indirection tables for the global decls and types. */
@@ -2719,12 +2748,6 @@ lto_read_subroutine_type_subprogram_DIE (lto_info_fd *fd,
/* Record this function in the DIE cache so that it can be
resolved from the bodies of functions. */
lto_cache_store_DIE (fd, die, result);
-
- /* We want to read in its body from the LTO data only if we
- haven't already done so. FIXME: we will need to handle
- multiple conflicting definitions one day... */
- if (!DECL_STRUCT_FUNCTION (result))
- VEC_safe_push (tree, gc, fd->unmaterialized_fndecls, result);
}
}
@@ -3503,14 +3526,23 @@ lto_set_cu_context (lto_context *context, lto_info_fd *fd,
context->cu = unit;
}
-bool
+
+/* Generate a TREE representation for all types and external decls
+ entities in FILE. If an entity in FILE has already been read (from
+ another object file), merge the two entities. Returns TRUE iff
+ FILE was successfully processed.
+
+ Read all of the lto dwarf out of the file. Then read the cgraph
+ and process the .o index into the cgraph nodes so that it can open
+ the .o file to load the functions and ipa information. */
+
+static bool
lto_file_read (lto_file *file)
{
struct lto_file_decl_data* file_data;
size_t i;
/* The descriptor for the .debug_info section. */
lto_fd *fd;
-
/* Read the abbreviation entries. */
lto_abbrev_read (&file->debug_abbrev);
/* Read the compilation units. */
@@ -3524,9 +3556,8 @@ lto_file_read (lto_file *file)
DWARF2_CompUnit *unit = file->debug_info.units[i];
/* The context information for this compilation unit. */
lto_context context;
- size_t j;
- tree decl;
-
+ htab_t section_hash_table;
+
/* Set up the context. */
lto_set_cu_context (&context, &file->debug_info, unit);
fd->cur = context.cu_start + unit->cu_header_length;
@@ -3563,17 +3594,13 @@ lto_file_read (lto_file *file)
lto_read_DIE (&file->debug_info, &context, NULL);
}
+ section_hash_table = lto_elf_build_section_table (file);
file_data = lto_materialize_file_data (&file->debug_info, &context);
+ file_data->section_hash_table = section_hash_table;
- lto_materialize_constructors_and_inits (&file->debug_info, &context, file_data);
+ lto_materialize_constructors_and_inits (file_data);
- /* Read in function bodies now that we have the full DWARF tree
- available. */
- for (j = 0;
- VEC_iterate (tree, file->debug_info.unmaterialized_fndecls,
- j, decl);
- j++)
- lto_materialize_function (&file->debug_info, &context, file_data, decl);
+ lto_materialize_cgraph (file_data);
}
return true;
@@ -3723,6 +3750,7 @@ lto_main (int debug_p ATTRIBUTE_UNUSED)
{
unsigned i;
tree decl;
+ struct cgraph_node *node;
/* Read all of the object files specified on the command line. */
for (i = 0; i < num_in_fnames; ++i)
@@ -3736,6 +3764,33 @@ lto_main (int debug_p ATTRIBUTE_UNUSED)
current_lto_file = NULL;
}
+ /* Now that we have input the cgraph, we need to clear all of the aux
+ nodes and read the functions.
+
+ FIXME!!!!! This loop obviously leaves a lot to be desired:
+ 1) it loads all of the functions at once.
+ 2) it closes and reopens the files over and over again.
+
+ It would obviously be better for the cgraph code to look to load
+ a batch of functions and sort those functions by the file they
+ come from and then load all of the functions from a give .o file
+ at one time. This of course will require that the open and close
+ code be pulled out of lto_materialize_function, but that is a
+ small part of what will be a complex set of management
+ issues. */
+ for (node = cgraph_nodes; node; node = node->next)
+ {
+ node->aux = NULL;
+ /* FIXME!!! There really needs to be some check to see if the
+ function is really not external here. Currently the only
+ check is to see if the section was defined in the file_data
+ index. There is of course the value in the node->aux field
+ that is nulled out in the previous line, but we should really
+ be able to look at the cgraph info at the is point and make
+ the proper determination. Honza will fix this. */
+ lto_materialize_function (node);
+ }
+
/* Inform the middle end about the global variables we have seen. */
for (i = 0; VEC_iterate (tree, lto_global_var_decls, i, decl); i++)
rest_of_decl_compilation (decl,
@@ -3744,7 +3799,7 @@ lto_main (int debug_p ATTRIBUTE_UNUSED)
/* Let the middle end know that we have read and merged all of the
input files. */
- cgraph_finalize_compilation_unit ();
+ /*cgraph_finalize_compilation_unit ();*/
cgraph_optimize ();
}
diff --git a/gcc/lto/lto.h b/gcc/lto/lto.h
index 0885311c447..4bf3917240f 100644
--- a/gcc/lto/lto.h
+++ b/gcc/lto/lto.h
@@ -129,8 +129,6 @@ typedef struct lto_info_fd_struct GTY(())
/* A map from DIEs to trees. The keys are offsets into the DWARF
information section; the values are trees. */
htab_t GTY((param_is (lto_die_cache_entry))) die_cache;
- /* A vector of FUNCTION_DECLs whose bodies have not yet been read in. */
- VEC (tree, gc) *unmaterialized_fndecls;
}
lto_info_fd;
@@ -201,12 +199,6 @@ extern void lto_file_init (lto_file *file,
deallocated by this function. */
extern void lto_file_close (lto_file *file);
-/* Generate a TREE representation for all entities in FILE. If an
- entity in FILE has already been read (from another object file),
- merge the two entities. Returns TRUE iff FILE was successfully
- processed. */
-extern bool lto_file_read (lto_file *file);
-
/* Return the TYPE referred to by REF. */
extern tree lto_resolve_type_ref (lto_info_fd *info_fd,
lto_context *context,
@@ -232,6 +224,9 @@ extern tree lto_resolve_typedecl_ref (lto_info_fd *info_fd,
lto_context *context,
const lto_ref *ref);
+/* Get the file name associated with INFO_FD. */
+extern const char *lto_get_file_name (lto_info_fd *info_fd);
+
/* lto-elf.c */
/* Open the ELF input file indicated by FILENAME. Return */
@@ -240,6 +235,9 @@ extern lto_file *lto_elf_file_open (const char *filename);
/* Close an ELF input file. */
extern void lto_elf_file_close (lto_file *file);
+/* Build and index of all lto sections in an elf file. */
+extern htab_t lto_elf_build_section_table (lto_file *file);
+
/* lto-function-in.c */
struct lto_file_decl_data* lto_read_decls (lto_info_fd *, lto_context *, const void *data);
@@ -260,10 +258,20 @@ lto_input_function_body (struct lto_file_decl_data* file_data,
/* DATA is the LTO data written out during ordinary compilation,
encoding the initializers for the static and external vars.
FILE_DATA are the tables holding all of the global types and decls
- used by FN. */
+ used in that file. */
extern void
lto_input_constructors_and_inits (struct lto_file_decl_data* file_data,
const void *data);
+
+/* DATA is the LTO data written out during ordinary compilation,
+ encoding the initializers for the static and external vars.
+ FILE_DATA are the tables holding all of the global types and decls
+ used un that file. */
+extern void
+lto_input_cgraph (struct lto_file_decl_data* file_data,
+ const void *data);
+
+
/* lto-symtab.c */
/* The NEW_VAR (a VAR_DECL) has just been read. If there is an
diff --git a/gcc/passes.c b/gcc/passes.c
index 47b5a30c42d..4f5077647e6 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -539,6 +539,7 @@ init_optimization_passes (void)
NEXT_PASS (pass_inline_parameters);
}
NEXT_PASS (pass_ipa_lto_gimple_out);
+ NEXT_PASS (pass_ipa_lto_cgraph_out);
NEXT_PASS (pass_ipa_increase_alignment);
NEXT_PASS (pass_ipa_matrix_reorg);
NEXT_PASS (pass_ipa_cp);
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index d4ffb6ceb31..7e2f16a5509 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -336,6 +336,7 @@ extern struct tree_opt_pass pass_reset_cc_flags;
extern struct tree_opt_pass pass_ipa_matrix_reorg;
extern struct tree_opt_pass pass_ipa_cp;
extern struct tree_opt_pass pass_ipa_lto_gimple_out;
+extern struct tree_opt_pass pass_ipa_lto_cgraph_out;
extern struct tree_opt_pass pass_ipa_inline;
extern struct tree_opt_pass pass_ipa_early_inline;
extern struct tree_opt_pass pass_ipa_reference;
diff --git a/gcc/varpool.c b/gcc/varpool.c
index 4149c1d1d21..2e77f62c59e 100644
--- a/gcc/varpool.c
+++ b/gcc/varpool.c
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3. If not see
#include "output.h"
#include "tree-gimple.h"
#include "tree-flow.h"
+#include "flags.h"
/* This file contains basic routines manipulating variable pool.
@@ -226,6 +227,9 @@ decide_is_variable_needed (struct varpool_node *node, tree decl)
&& lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
return true;
+ if (in_lto_p)
+ return true;
+
/* ??? If the assembler name is set by hand, it is possible to assemble
the name later after finalizing the function and the fact is noticed
in assemble_name then. This is arguably a bug. */