This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[lto]: Patch to serialize cgraph and other changes.


The main purpose of this patch is to serialize the cgraph.  However
there were several major changes that had to be done along the way to
make that work.

1) The only code that uses the older elf utilities in lto/lto-elf.c is
the dwarf reader for types and globals.  All of the other elf sections
are read by new code that reads the elf dictionary once and puts all of
the lto entries into a hash table that can be used later.

The required major surgery to get working.   libelf does not really want
to just give out a pointer to an elf section.   It generally copies it,
applying some transformations based on the source and destination
architecture.    This is unnecessary for the lto functions, and the ipa
sections because they are just in byte encoded streams so the
transformation will always be a memory copy.   But the elf reader copies
it anyway, just in case.   The new code stores an entry with filename,
start and length, so the section reader can just open the file and lseek
to it. 

The current code builds the hash table with the real start byte of the
lto section.   This table for a particular .o is then put into the
cgraph entry for the functions for that file so that the file can be
read later.   This code should work and we should be able to play the
same games with other .o formats except for one caveat:  archives will
require some work because the current offset used is to the beginning of
the .o file, not the beginning of the archive.

2) The big loop now looks like:

for each file:
   {
       read the globals and types.
       read the cgraph
  }

Process the cgraph,

for each node in the cgraph
    read in the function body.

Of course reading every function is not what we want to do in the long
run, but this patch now separates the reading of the functions from the
building of the cgraph and the merging of the types and decls so a
rational policy could now be implemented.  Honza plans to add smarts to
the cgraph analyzing code to read functions on demand and cache the
little ones (or some such policy) and he can now go off and do that
independently loading/merging the globals and types.

3) There was some generalization of the streams debugging so that the
same debugging interface can be used for any ipa stream, not just the
function bodies. 

4) There is still a lot of code in the wrong place.  lto/lto.c contains
a lot of code to read in the cgraph.   This is just going to have to
stay this way until honza makes some changes to the pass manager to
properly support passes that serialize/deserialize/analyze ipa like
passes.  

5) There is now even more bogosity to make local static vars work
properly.  This will be fixed when all of the statics, including the
locals are serialized at one time, and properly restored. 

committed as revision 132954.

Kenny


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-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.

Index: cgraph.c
===================================================================
--- cgraph.c	(revision 132603)
+++ cgraph.c	(working copy)
@@ -326,14 +326,20 @@ cgraph_create_edge (struct cgraph_node *
 		    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 *
   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,
Index: cgraph.h
===================================================================
--- cgraph.h	(revision 132603)
+++ cgraph.h	(working copy)
@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3.  
 #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_availab
 
 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
 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);
 
Index: tree-pass.h
===================================================================
--- tree-pass.h	(revision 132603)
+++ tree-pass.h	(working copy)
@@ -336,6 +336,7 @@ extern struct tree_opt_pass pass_reset_c
 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;
Index: lto-function-out.c
===================================================================
--- lto-function-out.c	(revision 132603)
+++ lto-function-out.c	(working copy)
@@ -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_ty
   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_ty
 #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
       {
 	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 *
 	      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, basi
 	{
 	  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, basi
       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* nod
   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* nod
      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* nod
   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);
Index: cgraphunit.c
===================================================================
--- cgraphunit.c	(revision 132603)
+++ cgraphunit.c	(working copy)
@@ -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, boo
   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)
Index: lto-cgraph.h
===================================================================
--- lto-cgraph.h	(revision 0)
+++ lto-cgraph.h	(revision 0)
@@ -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 */
Index: lto-header.h
===================================================================
--- lto-header.h	(revision 132603)
+++ lto-header.h	(working copy)
@@ -63,6 +63,9 @@ section *lto_get_section (enum lto_secti
 #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_secti
   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_secti
 #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 (stru
 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_d
 #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
Index: lto-tags.h
===================================================================
--- lto-tags.h	(revision 132603)
+++ lto-tags.h	(working copy)
@@ -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_fl
 #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
 
Index: lto/lto.c
===================================================================
--- lto/lto.c	(revision 132603)
+++ lto/lto.c	(working copy)
@@ -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
   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 *f
   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 
           /* 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
   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 ();
 }
 
Index: lto/Make-lang.in
===================================================================
--- lto/Make-lang.in	(revision 132603)
+++ lto/Make-lang.in	(working copy)
@@ -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_
 	$(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
 	$(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
Index: lto/lto-elf.c
===================================================================
--- lto/lto-elf.c	(revision 132603)
+++ lto/lto-elf.c	(working copy)
@@ -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 
   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:
Index: lto/lto.h
===================================================================
--- lto/lto.h	(revision 132603)
+++ lto/lto.h	(working copy)
@@ -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 *fil
    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 (lt
                                       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 (cons
 /* 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
 /* 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
Index: lto/lto-section-in.c
===================================================================
--- lto/lto-section-in.c	(revision 132603)
+++ lto/lto-section-in.c	(working copy)
@@ -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_bloc
 	}
     }
 }
+
+/*****************************************************************************/
+/* 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;
 }
 
Index: lto/lto-cgraph-in.c
===================================================================
--- lto/lto-cgraph-in.c	(revision 0)
+++ lto/lto-cgraph-in.c	(revision 0)
@@ -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);
+}
+
Index: lto/lto-function-in.c
===================================================================
--- lto/lto-function-in.c	(revision 132603)
+++ lto/lto-function-in.c	(working copy)
@@ -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_blo
 
 	      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_blo
 #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
      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 
 	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 dat
 {
   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 dat
       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
 #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
       /* 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 ();
     }
Index: lto/lto-section-in.h
===================================================================
--- lto/lto-section-in.h	(revision 132603)
+++ lto/lto-section-in.h	(working copy)
@@ -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  */
Index: lto-stream-debug.c
===================================================================
--- lto-stream-debug.c	(revision 132603)
+++ lto-stream-debug.c	(working copy)
@@ -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_conte
 		  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_contex
 }
 
 
+/* 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
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 132603)
+++ Makefile.in	(working copy)
@@ -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) $(SYSTE
 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) $(SYST
    $(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 \
Index: passes.c
===================================================================
--- passes.c	(revision 132603)
+++ passes.c	(working copy)
@@ -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);
Index: lto-cgraph-out.c
===================================================================
--- lto-cgraph-out.c	(revision 0)
+++ lto-cgraph-out.c	(revision 0)
@@ -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 */
+};
+
Index: varpool.c
===================================================================
--- varpool.c	(revision 132603)
+++ varpool.c	(working copy)
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  
 #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 varpoo
       && 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.  */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]