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 committed to serialize several ipa passes and use pass manager.


This patch does several things:

1) This patch properly integrates lto with the new IPA pass manager structure. There are now several true IPA_PASSES, including serializing/deserializing the cgraph, the pure-const ipa pass, and the decl and type indexes.

I did not convert and of the other simple ipa passes yet. This is next on my plate. I also did not convert the code that serializes the constructors and initializers. Bill Maddox is reworking this code and i did not want to make his life any harder than it was.

There is a restriction that all of the true IPA_PASSES have to be put together in passes.c, i.e. there can be no SIMPLE_IPA_PASSES in the middle. I have 8 hours of time in the car with honza on the way back from the summit to convince him that this is a bad restriction.

lto-cgraph-in.c lto-cgraph.out.c and lto-cgraph.h have been merged into lto-cgraph.c. This allows their to be one pass manager structure to drive them.

2) This patch also properly divides the functionality that needs to be in the lto front end from what is in the core compiler. Each ipa pass now calls thru hooks to get and release it's the raw data that has been serialized for it. Right now there is a single implementation of how that data is stored: elf sections in .o files, but it will not be hard to support other representations like ar files, without changing the passes that use the information.

The .o files are now read using mmap. However, I do not know how this is going to play on non unix systems. I was careful to not use any of the fancy linux specific options. The one issue that someone like will willy or iant may want to comment on is that i do not actually close any files. I am careful to unmap sections, but i leave the files open. I have no idea if i am going to run out of handles. This is easy to change.

3) There were also several bugs fixed in the string hashing and reading for the function bodies. I noticed these initially while valgrinding to find another problem.

4) There was code pulled out of lto-function-out.c that has been put into lto-section-out. This is the code that finds and assigns the index for all global decls and types. These functions are needed by other ipa passes. I hope that this is not a problem for bill to merge with. Aside from that Bill will also have to deal with my changes to lto/lto.c. Nothing should be incompatible with his changes, but he has made such drastic changes to that file on his branch, every other change is bound to require merging by hand.

We now have about 121 regressions in the c suite. Almost all of these are nested functions, functions renamed in the assembly file, or places where the c front end has not lowered initializers at lto serialization time.

Committed as revision 136488.

Kenny


2008-05-05 Kenneth Zadeck <zadeck@naturalbridge.com>
Jan Hubicka <jh@suse.cz>
* tree-pass.h (ipa_opt_pass pass_ipa_lto_gimple_out,
pass_ipa_pure_const, pass_ipa_lto_finish_out): Changed from being
simple_ipa_opt_pass to ipa_opt_pass.
(ipa_opt_pass pass_ipa_lto_cgraph): Renamed from
ipa_opt_pass pass_ipa_lto_cgraph_out.
(ipa_write_summaries, ipa_read_summaries): New functions.
* lto-function-out.c (string_slot_free): New function.
(next_string_index): Removed.
(string_hash_table): Now use string_slot_free.
(output_string): Copy string to malloced space and properly
initialize slots.
(output_type_ref_1): Renamed to lto_output_type_ref_index and
moved to lto_section_out.c
(output_type_ref, output_function): Now calls lto_output_type_ref_index.
(output_expr_operand): Moved bodies of FIELD_DECL, FUNCTION_DECL,
VAR_DECL, TYPE_DECL, NAMESPACE_DECL to new functions in
lto_section_out.c.
(lto_output): Now returns void.
(pass_ipa_lto_gimple_out): Now a IPA_PASS with lto_output as
write_summary method.
* lto-function-in.c (input_string_internal): Moved initialization
of len to proper place.
* lto-cgraph.c: New file that is combination of lto-cgraph-out.c
lto-cgraph-in.c and cgraph.h.
(lto-section-in.h, lto-section-out.h): Added includes.
(tree-vectorizer.h, tree-iterator.h): Removed includes.
(LTO_cgraph_tag_names, LTO_cgraph_tags): Added from cgraph.h.
(create_output_block, destroy_output_block, output_uleb128,
output_sleb128, output_fun_decl, add_flag): Moved to
lto-section-out.c, renamed with "lto_" prefix and generalized.
(output_node, output_cgraph, input_overwrite_mode, input_cgraph):
Changed to call moved and renamed functions.
(input_overwrite_mode): Renamed from overwrite_mode.
(input_cgraph): Renamed from lto_input_cgraph and made private and
now loops over all file_datas.
(pass_ipa_lto_cgraph): Renamed from pass_ipa_lto_cgraph_out and
made into IPA_PASS.
* lto-cgraph.h: File deleted and all infomation moved to
lto-cgraph.c.
* lto-header.h (LTO_section_ipa_pure_const): New section type.
(lto_simple_header): New structure.
* ipa-pure-const.c (lto-section-in.h, lto-section-out.h): New
includes.
(init_state, finish_state, set_function_state, generate_summary,
write_summary, read_summary): New functions.
(scan_stmt): Renamed from scan_function. Changed to keep state in
local static vars rather than cgraph aux field.
(propagate): Renamed from static_execute. Changed to keep state in
local static vars rather than cgraph aux field.
(pass_ipa_pure_const): Changed from SIMPLE_IPA_PASS to IPA_PASS.
* lto-cgraph-in.c: Content moved to lto-cgraph.c.
* lto-section-in.c (lto_get_flag, lto_get_flags): Moved from
lto-cgraph-in.c and renamed from add_flag and add_flags.
(lto_read_section_data): Moved to lto/lto.c and modified to use
mmap.
(lto_set_in_hooks, lto_get_file_decl_data, lto_free_section_data,
lto_create_simple_input_block, lto_destroy_simple_input_block):
New functions.
(lto_get_section_data): Modified to call hook in lto front end.
* lto-section-in.h (lto_section_slot): Moved to lto.h.
(LTO_INIT_INPUT_BLOCK_PTR): New macro.
(lto_file_decl_data.fd): New field.
(lto_get_section_data_f, lto_free_section_data_f): New typedefs.
(lto_create_simple_input_block, lto_destroy_simple_input_block,
lto_get_flag, lto_get_flags, lto_set_in_hooks, lto_file_decl_data,
lto_free_section_data): New functions.
(lto_get_section_data): Added parms.
* Makefile.in (lto-cgaph.o): Combined rules from lto-cgraph-in.o
and lto-cgraph-out.o.
(lto-function-in.o, lto-function-out.o): Added dependencies.
* passes.c (init_optimization_passes): Reordered ipa passes.
(execute_ipa_summary_passes): Added check to see that pass was
there.
(ipa_write_summaries_1, ipa_write_summaries,
ipa_read_summaries_1): New function.
(execute_ipa_pass_list): Added call to ipa_write_summaries and
fixed bug.
* lto-cgraph-out.c: Content moved to lto-cgraph.c.
* lto-section-out.c (lto_set_flag, lto_set_flags): Functions moved
and renamed (with lto_ prefix) from lto-cgraph-out.c.
(lto_output_field_decl_index, lto_output_fn_decl_index,
lto_output_namespace_decl_index, lto_output_var_decl_index,
lto_output_type_decl_index, lto_output_type_ref_index): New
functions. The code for these functions was taken from
lto-function-out.c
(lto_create_simple_output_block, lto_destroy_simple_output_block):
New functions.
(produce_asm_for_decls): Now returns void.
(pass_ipa_lto_finish_out): Now an IPA_PASS.
* lto-section-out.h (lto_simple_output_block): New structure.
(lto_set_flag, lto_set_flags, lto_output_field_decl_index,
lto_output_fn_decl_index, lto_output_namespace_decl_index,
lto_output_var_decl_index, lto_output_type_decl_index,
lto_output_type_ref_index, lto_create_simple_output_block,
lto_destroy_simple_output_block): New functions.
(lto_get_out_decl_state): Removed function
(lto_output_decl_index): Added parms.


2008-06-07 Kenneth Zadeck <zadeck@naturalbridge.com>
Jan Hubicka <jh@suse.cz>
* lto.c (sys/mman.h, tree-pass.h): New includes.
(lto_materialize_constructors_and_inits,
lto_materialize_function): Keeps length of section.
(lto_materialize_cgraph): Removed.
(lto_read_decls): Initialize fd field.
(lto_file_read): Different return type and removed much code to
lto_main.
(page_mask): New variable.
(lto_read_section_data, get_section_data, free_section_data): New
functions.
(lto_main): Now calls pass manager, sets the hooks so that the ipa
passes can get the section data.
Index: tree-pass.h
===================================================================
--- tree-pass.h	(revision 136409)
+++ tree-pass.h	(working copy)
@@ -384,22 +384,23 @@ extern struct gimple_opt_pass pass_build
 extern struct gimple_opt_pass pass_reset_cc_flags;
 
 /* IPA Passes */
-extern struct ipa_opt_pass pass_ipa_inline;
-extern struct simple_ipa_opt_pass pass_ipa_reference;
+extern struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility;
+extern struct simple_ipa_opt_pass pass_ipa_early_inline;
 
+extern struct simple_ipa_opt_pass pass_early_local_passes;
+
+extern struct ipa_opt_pass pass_ipa_lto_gimple_out;
+extern struct ipa_opt_pass pass_ipa_lto_cgraph;
+extern struct simple_ipa_opt_pass pass_ipa_increase_alignment;
 extern struct simple_ipa_opt_pass pass_ipa_matrix_reorg;
 extern struct simple_ipa_opt_pass pass_ipa_cp;
-extern struct simple_ipa_opt_pass pass_ipa_lto_gimple_out;
-extern struct simple_ipa_opt_pass pass_ipa_lto_cgraph_out;
-extern struct simple_ipa_opt_pass pass_ipa_early_inline;
-extern struct simple_ipa_opt_pass pass_ipa_pure_const;
+extern struct ipa_opt_pass pass_ipa_inline;
+extern struct simple_ipa_opt_pass pass_ipa_reference;
+extern struct ipa_opt_pass pass_ipa_pure_const;
 extern struct simple_ipa_opt_pass pass_ipa_type_escape;
 extern struct simple_ipa_opt_pass pass_ipa_pta;
 extern struct simple_ipa_opt_pass pass_ipa_struct_reorg;
-extern struct simple_ipa_opt_pass pass_ipa_lto_finish_out;
-extern struct simple_ipa_opt_pass pass_early_local_passes;
-extern struct simple_ipa_opt_pass pass_ipa_increase_alignment;
-extern struct simple_ipa_opt_pass pass_ipa_function_and_variable_visibility;
+extern struct ipa_opt_pass pass_ipa_lto_finish_out;
 
 extern struct gimple_opt_pass pass_all_optimizations;
 extern struct gimple_opt_pass pass_cleanup_cfg_post_optimizing;
@@ -521,6 +522,8 @@ extern void execute_pass_list (struct op
 extern void execute_ipa_pass_list (struct opt_pass *);
 extern void print_current_pass (FILE *);
 extern void debug_pass (void);
+extern void ipa_write_summaries (void);
+extern void ipa_read_summaries (void);
 
 /* Set to true if the pass is called the first time during compilation of the
    current function.  Note that using this information in the optimization
Index: lto-function-out.c
===================================================================
--- lto-function-out.c	(revision 136409)
+++ lto-function-out.c	(working copy)
@@ -93,7 +93,6 @@ hash_label_slot_node (const void *p)
 }
 
 
-
 struct string_slot {
   const char *s;
   int len;
@@ -132,6 +131,18 @@ eq_string_slot_node (const void *p1, con
   else return 0;
 }
 
+
+/* Free the string slot.  */
+
+static void 
+string_slot_free (void *p)
+{
+  struct string_slot *slot = (struct string_slot *)p;
+  free ((void *)slot->s);
+  free (slot);
+}
+
+
 /* The fields written to a function or extern variable header.  */
 
 struct output_block
@@ -196,8 +207,6 @@ struct output_block
   /* The hash table that contains the set of strings we have seen so
      far and the indexes assigned to them.  */
   htab_t string_hash_table;
-  unsigned int next_string_index;
-
 
   /* The current cgraph_node that we are currently serializing.  Null
      if we are serializing something else.  */
@@ -265,7 +274,7 @@ create_output_block (enum lto_section_ty
     }
 
   ob->string_hash_table
-    = htab_create (37, hash_string_slot_node, eq_string_slot_node, free);
+    = htab_create (37, hash_string_slot_node, eq_string_slot_node, string_slot_free);
 
   /* The unnamed labels must all be negative.  */
   ob->next_unnamed_label_index = -1;
@@ -337,6 +346,7 @@ output_string (struct output_block *ob, 
   struct string_slot s_slot;
   s_slot.s = string;
   s_slot.len = len;
+  s_slot.slot_num = 0;
 
   slot = htab_find_slot (ob->string_hash_table, &s_slot, INSERT);
   if (*slot == NULL)
@@ -346,8 +356,11 @@ output_string (struct output_block *ob, 
       struct string_slot *new_slot
 	= xmalloc (sizeof (struct string_slot));
       unsigned int i;
+      char *new_string = xmalloc (len);
 
-      new_slot->s = string;
+      memcpy (new_string, string, len);
+      new_slot->s = new_string;
+      new_slot->len = len;
       new_slot->slot_num = start;
       *slot = new_slot;
       lto_output_uleb128_stream (index_stream, start);
@@ -594,24 +607,6 @@ output_tree_flags (struct output_block *
 }
 
 
-/* Like output_type_ref, but no debug information is written.  */
-
-static void
-output_type_ref_1 (struct output_block *ob, tree node)
-{
-  bool new;
-  unsigned int index;
-
-  new = lto_output_decl_index (ob->main_stream, 
-			       ob->decl_state->type_hash_table,
-			       &ob->decl_state->next_type_index, 
-			       node, &index);
-
-  if (new)
-    VEC_safe_push (tree, heap, ob->decl_state->types, node);
-}
-
-
 /* Look up NODE in the type table and write the uleb128 index for it to OB.
    This is a hack and will be replaced with a real reference to the type.  */
 
@@ -619,7 +614,7 @@ static void
 output_type_ref (struct output_block *ob, tree node)
 {
   LTO_DEBUG_TOKEN ("type");
-  output_type_ref_1 (ob, node);
+  lto_output_type_ref_index (ob->decl_state, ob->main_stream, node);
 }
 
 
@@ -1029,49 +1024,20 @@ output_expr_operand (struct output_block
       break;
 
     case FIELD_DECL:
-      {
-	unsigned int index;
-	bool new;
-	output_record_start (ob, NULL, NULL, tag);
-	
-	new = lto_output_decl_index (ob->main_stream, 
-				     ob->decl_state->field_decl_hash_table,
-				     &ob->decl_state->next_field_decl_index, 
-				     expr, &index);
-	if (new)
-	  VEC_safe_push (tree, heap, ob->decl_state->field_decls, expr);
-      }
+      output_record_start (ob, NULL, NULL, tag);
+      lto_output_field_decl_index (ob->decl_state, ob->main_stream, expr);
       break;
 
     case FUNCTION_DECL:
-      {
-	unsigned int index;
-	bool new;
-	output_record_start (ob, NULL, NULL, tag);
-	
-	new = lto_output_decl_index (ob->main_stream, 
-				     ob->decl_state->fn_decl_hash_table,
-				     &ob->decl_state->next_fn_decl_index, 
-				     expr, &index);
-	if (new)
-	  VEC_safe_push (tree, heap, ob->decl_state->fn_decls, expr);
-      }
+      output_record_start (ob, NULL, NULL, tag);
+      lto_output_fn_decl_index (ob->decl_state, ob->main_stream, expr);
       break;
 
     case VAR_DECL:
       if (TREE_STATIC (expr) || DECL_EXTERNAL (expr))
 	{
-	  /* Static or extern VAR_DECLs.  */
-	  unsigned int index;
-	  bool new;
 	  output_record_start (ob, NULL, NULL, LTO_var_decl1);
-
-	  new = lto_output_decl_index (ob->main_stream, 
-				       ob->decl_state->var_decl_hash_table,
-				       &ob->decl_state->next_var_decl_index, 
-				       expr, &index);
-	  if (new)
-	    VEC_safe_push (tree, heap, ob->decl_state->var_decls, expr);
+	  lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
 	}
       else
 	{
@@ -1082,33 +1048,13 @@ output_expr_operand (struct output_block
       break;
 
     case TYPE_DECL:
-      {
-	unsigned int index;
-	bool new;
-	output_record_start (ob, NULL, NULL, tag);
-	
-	new = lto_output_decl_index (ob->main_stream, 
-				     ob->decl_state->type_decl_hash_table,
-				     &ob->decl_state->next_type_decl_index, 
-				     expr, &index);
-	if (new)
-	  VEC_safe_push (tree, heap, ob->decl_state->type_decls, expr);
-      }
+      output_record_start (ob, NULL, NULL, tag);
+      lto_output_type_decl_index (ob->decl_state, ob->main_stream, expr);
       break;
 
     case NAMESPACE_DECL:
-      {
-	unsigned int index;
-	bool new;
-	output_record_start (ob, NULL, NULL, tag);
-
-	new = lto_output_decl_index (ob->main_stream,
-				     ob->decl_state->namespace_decl_hash_table,
-				     &ob->decl_state->next_namespace_decl_index,
-				     expr, &index);
-	if (new)
-	  VEC_safe_push (tree, heap, ob->decl_state->namespace_decls, expr);
-      }
+      output_record_start (ob, NULL, NULL, tag);
+      lto_output_namespace_decl_index (ob->decl_state, ob->main_stream, expr);
       break;
 
     case PARM_DECL:
@@ -2016,7 +1962,7 @@ output_function (struct cgraph_node* nod
   else if (TYPE_P (context))
     {
       output_record_start (ob, NULL, NULL, LTO_type);
-      output_type_ref_1 (ob, context);
+      lto_output_type_ref_index (ob->decl_state, ob->main_stream, context);
       LTO_DEBUG_UNDENT ();
     }
   else
@@ -2116,7 +2062,7 @@ output_constructors_and_inits (void)
 
 /* Main entry point from the pass manager.  */
 
-static unsigned int
+static void
 lto_output (void)
 {
   struct cgraph_node *node;
@@ -2141,17 +2087,15 @@ lto_output (void)
     switch_to_section (saved_section);
 
   dwarf2_called_from_lto_p = false;
-
-  return 0;
 }
 
-struct simple_ipa_opt_pass pass_ipa_lto_gimple_out =
+struct ipa_opt_pass pass_ipa_lto_gimple_out =
 {
  {
-  SIMPLE_IPA_PASS,
+  IPA_PASS,
   "lto_gimple_out",	                /* name */
   gate_lto_out,			        /* gate */
-  lto_output,		        	/* execute */
+  NULL,		                	/* execute */
   NULL,					/* sub */
   NULL,					/* next */
   0,					/* static_pass_number */
@@ -2161,7 +2105,14 @@ struct simple_ipa_opt_pass pass_ipa_lto_
   0,					/* properties_destroyed */
   0,            			/* todo_flags_start */
   TODO_dump_func                        /* todo_flags_finish */
- }
+ },
+ NULL,		                        /* generate_summary */
+ lto_output,           			/* write_summary */
+ NULL,		         		/* read_summary */
+ NULL,					/* function_read_summary */
+ 0,					/* TODOs */
+ NULL,			                /* function_transform */
+ NULL					/* variable_transform */
 };
 
 
Index: lto-function-in.c
===================================================================
--- lto-function-in.c	(revision 136409)
+++ lto-function-in.c	(working copy)
@@ -149,11 +149,12 @@ input_string_internal (struct data_in *d
 		       unsigned int *rlen)
 {
   struct lto_input_block str_tab;
-  unsigned int len = lto_input_uleb128 (&str_tab);
+  unsigned int len;
   const char * result;
   
   LTO_INIT_INPUT_BLOCK (str_tab, data_in->strings,
 			loc, data_in->strings_len);
+  len = lto_input_uleb128 (&str_tab);
   *rlen = len;
   gcc_assert (str_tab.p + len <= data_in->strings_len);
   
Index: lto-cgraph.c
===================================================================
--- lto-cgraph.c	(revision 0)
+++ lto-cgraph.c	(revision 0)
@@ -0,0 +1,426 @@
+/* Write and read the cgraph to the memory mapped representation of a
+   .o file.
+
+   Copyright 2008 Free Software Foundation, Inc.
+   Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING.  If not, write to
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "toplev.h"
+#include "tree.h"
+#include "expr.h"
+#include "flags.h"
+#include "params.h"
+#include "input.h"
+#include "varray.h"
+#include "hashtab.h"
+#include "langhooks.h"
+#include "basic-block.h"
+#include "tree-pass.h"
+#include "tree-flow.h"
+#include "cgraph.h"
+#include "function.h"
+#include "ggc.h"
+#include "diagnostic.h"
+#include "except.h"
+#include "debug.h"
+#include "vec.h"
+#include "timevar.h"
+#include "dwarf2asm.h"
+#include "dwarf2out.h"
+#include "output.h"
+#include "lto-section-in.h"
+#include "lto-section-out.h"
+#include <ctype.h>
+
+enum LTO_cgraph_tags
+{
+  /* Must leave 0 for the stopper.  */
+  LTO_cgraph_avail_node = 1,
+  LTO_cgraph_overwritable_node,
+  LTO_cgraph_unavail_node,
+  LTO_cgraph_edge,
+  LTO_cgraph_last_tag
+};
+
+#ifdef LTO_STREAM_DEBUGGING
+static const char * LTO_cgraph_tag_names[LTO_cgraph_last_tag] = 
+{"", "avail", "overwrite", "unavail", "edge"};
+#endif
+
+
+/* Output the cgraph EDGE to OB.  */
+
+static void
+output_edge (struct lto_simple_output_block *ob, struct cgraph_edge *edge)
+{
+  lto_output_uleb128_stream (ob->main_stream, LTO_cgraph_edge);
+  LTO_DEBUG_INDENT (LTO_cgraph_edge);
+  lto_output_fn_decl_index (ob->decl_state, ob->main_stream, edge->callee->decl);
+  LTO_DEBUG_FN_NAME (edge->callee->decl);
+
+  LTO_DEBUG_TOKEN ("stmt");
+  lto_output_uleb128_stream (ob->main_stream, gimple_stmt_uid (edge->call_stmt));
+  LTO_DEBUG_TOKEN ("count");
+  lto_output_uleb128_stream (ob->main_stream, edge->count);
+  LTO_DEBUG_TOKEN ("frequency");
+  lto_output_uleb128_stream (ob->main_stream, edge->frequency);
+  LTO_DEBUG_TOKEN ("loop_next");
+  lto_output_uleb128_stream (ob->main_stream, edge->loop_nest);
+  LTO_DEBUG_UNDENT();
+}
+
+
+/* Output the cgraph NODE to OB.  */
+
+static void
+output_node (struct lto_simple_output_block *ob, struct cgraph_node *node)
+{
+  unsigned int tag;
+  unsigned HOST_WIDEST_INT flags = 0;
+  struct cgraph_edge *callees = node->callees;
+
+  switch (cgraph_function_body_availability (node))
+    {
+    case AVAIL_NOT_AVAILABLE:
+      tag = LTO_cgraph_unavail_node;
+      break;
+
+    case AVAIL_AVAILABLE:
+    case AVAIL_LOCAL:
+      tag = LTO_cgraph_avail_node;
+      break;
+    
+    case AVAIL_OVERWRITABLE:
+      tag = LTO_cgraph_overwritable_node;
+      break;
+      
+    default:
+    gcc_unreachable();
+    }
+
+  lto_output_uleb128_stream (ob->main_stream, tag);
+  LTO_DEBUG_INDENT (tag);
+
+  lto_output_fn_decl_index (ob->decl_state, ob->main_stream, node->decl);
+  LTO_DEBUG_FN_NAME (node->decl);
+  lto_set_flag (&flags, node->local.local);
+  lto_set_flag (&flags, node->local.externally_visible);
+  lto_set_flag (&flags, node->local.finalized);
+  lto_set_flag (&flags, node->local.inlinable);
+  lto_set_flag (&flags, node->local.disregard_inline_limits);
+  lto_set_flag (&flags, node->local.redefined_extern_inline);
+  lto_set_flag (&flags, node->local.for_functions_valid);
+  lto_set_flag (&flags, node->local.vtable_method);
+
+  LTO_DEBUG_TOKEN ("flags");
+  lto_output_uleb128_stream (ob->main_stream, flags);
+
+  if (tag != LTO_cgraph_unavail_node)
+    {
+      LTO_DEBUG_TOKEN ("stack_size");
+      lto_output_sleb128_stream (ob->main_stream, 
+				 node->local.inline_summary.estimated_self_stack_size);
+      LTO_DEBUG_TOKEN ("self_insns");
+      lto_output_sleb128_stream (ob->main_stream, 
+				 node->local.inline_summary.self_insns);
+    }
+
+  LTO_DEBUG_UNDENT();
+
+#ifdef LTO_STREAM_DEBUGGING
+  gcc_assert (lto_debug_context.indent == 0);
+#endif
+
+  while (callees)
+    {
+      output_edge (ob, callees);
+      callees = callees->next_callee;
+    }
+
+#ifdef LTO_STREAM_DEBUGGING
+  gcc_assert (lto_debug_context.indent == 0);
+#endif
+}
+
+
+/* Output the cgraph.  */
+
+static void
+output_cgraph (void)
+{
+  struct cgraph_node *node;
+  struct lto_simple_output_block *ob 
+    = lto_create_simple_output_block (LTO_section_cgraph);
+  int i = 0;
+
+#ifdef LTO_STREAM_DEBUGGING
+  lto_debug_context.tag_names = LTO_cgraph_tag_names;
+  lto_debug_context.stream_name = "cgraph";
+#endif
+
+  for (node = cgraph_nodes; node; node = node->next)
+    {
+#ifdef ENABLE_CHECKING
+      /* Just a little sanity check to keep Honza honest.  At the
+	 point where we stream out the functions there must only be
+	 master_clone nodes or nodes that have no function bodies.  */
+
+      switch (cgraph_function_body_availability (node))
+	{
+	case AVAIL_UNSET:
+	  fprintf (stderr, "found unset function\n.");
+	  gcc_assert (0);
+	  break;
+
+	case AVAIL_NOT_AVAILABLE:
+	  break;
+
+	case AVAIL_OVERWRITABLE:
+	case AVAIL_AVAILABLE:
+	case AVAIL_LOCAL:
+	  if  (node != cgraph_master_clone (node, false))
+	    {
+	      fprintf (stderr, "found clone\n.");
+	      gcc_assert (0);
+	    }
+	  break;
+	}
+#endif
+      output_node (ob, node);
+      i++;
+    }
+
+  lto_output_uleb128_stream (ob->main_stream, 0);
+
+  /* Create a section to hold the pickled output the cgraph.  */
+  lto_destroy_simple_output_block (ob);
+}
+
+
+/* Overwrite the information in NODE based on FILE_DATA, TAG, FLAGS,
+   STACK_SIZE and SELF_INSNS.  This is called either to initialize
+   NODE or to replace the values in it, for instance becasue the first
+   time we saw it, the function body was not available but now it
+   is.  */
+static void
+input_overwrite_node (struct lto_file_decl_data* file_data,
+		struct cgraph_node *node,
+		enum LTO_cgraph_tags tag,
+		unsigned HOST_WIDEST_INT flags,
+		unsigned int stack_size,
+		unsigned int self_insns)
+{
+  node->aux = (void *)tag;
+  node->local.inline_summary.estimated_self_stack_size = stack_size;
+  node->local.inline_summary.self_insns = self_insns;
+  node->global.insns = self_insns;
+  node->local.lto_file_data = file_data;
+
+  /* This list must be in the reverse order that they are set in
+     lto-section-out.c:outout_node.  */
+  node->local.vtable_method = lto_get_flag (&flags);
+  node->local.for_functions_valid = lto_get_flag (&flags);
+  node->local.redefined_extern_inline = lto_get_flag (&flags);
+  node->local.disregard_inline_limits = lto_get_flag (&flags);
+  node->local.inlinable = lto_get_flag (&flags);
+  node->local.finalized = lto_get_flag (&flags);
+  node->local.externally_visible = lto_get_flag (&flags);
+  node->local.local = lto_get_flag (&flags);
+  node->analyzed = node->local.finalized;
+    node->lowered = node->local.finalized;
+  if (cgraph_decide_is_function_needed (node))
+    cgraph_mark_needed_node (node);
+}
+
+
+/* Input a cgraph from IB using the info in FILE_DATA.  */
+
+static void
+input_cgraph_1 (struct lto_file_decl_data* file_data,
+		struct lto_input_block *ib)
+{
+  enum LTO_cgraph_tags tag;
+  struct cgraph_node *last_caller = NULL;
+
+  tag = lto_input_uleb128 (ib);
+  while (tag)
+    {
+      LTO_DEBUG_INDENT (tag);
+
+      if (tag == LTO_cgraph_edge)
+	{
+	  tree callee_decl;
+	  struct cgraph_node *callee;
+	  struct cgraph_edge *edge;
+	  unsigned int stmt_id;
+	  unsigned int count;
+	  unsigned int freq;
+	  unsigned int nest;
+
+	  callee_decl = file_data->fn_decls [lto_input_uleb128 (ib)];
+	  LTO_DEBUG_FN_NAME (callee_decl);
+	  callee = cgraph_node (callee_decl);
+	  
+	  LTO_DEBUG_TOKEN ("stmt");
+	  stmt_id = lto_input_uleb128 (ib);
+	  LTO_DEBUG_TOKEN ("count");
+	  count = lto_input_uleb128 (ib);
+	  LTO_DEBUG_TOKEN ("frequency");
+	  freq = lto_input_uleb128 (ib);
+	  LTO_DEBUG_TOKEN ("loop_next");
+	  nest = lto_input_uleb128 (ib);
+	  
+	  edge = cgraph_create_edge (last_caller, callee, NULL, count, freq, nest);
+	  edge->lto_stmt_uid = stmt_id;
+	}
+      else 
+	{
+	  tree fn_decl;
+	  struct cgraph_node *node;
+	  unsigned int flags;
+	  int stack_size = 0;
+	  int self_insns = 0;
+	  
+	  fn_decl = file_data->fn_decls [lto_input_uleb128 (ib)];
+	  LTO_DEBUG_FN_NAME (fn_decl);
+	  LTO_DEBUG_TOKEN ("flags");
+	  flags = lto_input_uleb128 (ib);
+	  
+	  if (tag == LTO_cgraph_avail_node)
+	    {
+	      LTO_DEBUG_TOKEN ("stack_size");
+	      stack_size = lto_input_sleb128 (ib);
+	      LTO_DEBUG_TOKEN ("self_insns");
+	      self_insns = lto_input_sleb128 (ib);
+	    }
+	  
+	  node = cgraph_node (fn_decl);
+	  
+	  switch (tag)
+	    {
+	    case LTO_cgraph_avail_node:
+	      /* We cannot have two avail functions that are the same.  */
+	      gcc_assert (((enum LTO_cgraph_tags)(node->aux)) != LTO_cgraph_avail_node);
+	      input_overwrite_node (file_data, node, tag, 
+				    flags, stack_size, self_insns);
+	      break;
+	      
+	    case LTO_cgraph_unavail_node:
+	      /* We only overwrite the node if this is a brand new node.  */
+	      if (!node->aux)
+		input_overwrite_node (file_data, node, tag, 
+				      flags, stack_size, self_insns);
+	      break;
+	      
+	    case LTO_cgraph_overwritable_node:
+	      /* FIXME!!!!  This code is written to take the last
+		 overwrittable version.  I do not speak linker but if the
+		 linker supposed to take the first one, then we need to
+		 change the test.  */
+	      if (((enum LTO_cgraph_tags)(node->aux)) != LTO_cgraph_avail_node)
+		input_overwrite_node (file_data, node, tag, 
+				      flags, stack_size, self_insns);
+	      break;
+	      
+	    default:
+	      gcc_unreachable ();
+	    }
+	  
+	  /* Set this up so that we can handle the edges which follow and
+	     only have the callee in them.  */
+	  last_caller = node;
+	}
+      LTO_DEBUG_UNDENT();
+      tag = lto_input_uleb128 (ib);
+    }
+}
+
+
+/* Input and merge the cgraph from each of the .o files passed to
+   lto1.  */
+
+static void
+input_cgraph (void)
+{
+  struct lto_file_decl_data ** file_data_vec 
+    = lto_get_file_decl_data ();
+  struct lto_file_decl_data * file_data;
+  unsigned int j = 0;
+  struct cgraph_node *node;
+
+#ifdef LTO_STREAM_DEBUGGING
+  lto_debug_context.tag_names = LTO_cgraph_tag_names;
+  lto_debug_context.stream_name = "cgraph";
+#endif
+
+  while ((file_data = file_data_vec[j++]))
+    {
+      const char *data;
+      size_t len;
+      struct lto_input_block *ib
+	= lto_create_simple_input_block (file_data, 
+					 LTO_section_cgraph, 
+					 &data, &len);
+      input_cgraph_1 (file_data, ib);
+      lto_destroy_simple_input_block (file_data, 
+				      LTO_section_cgraph, 
+				      ib, data, len);
+    } 
+
+  /* Clear out the aux field that was used to store enough state to
+     tell which nodes should be overwritten.  */
+  for (node = cgraph_nodes; node; node = node->next)
+    {
+      gcc_assert (node->local.lto_file_data);
+      node->aux = NULL;
+    }
+}
+
+
+
+struct ipa_opt_pass pass_ipa_lto_cgraph =
+{
+ {
+  IPA_PASS,
+  "lto_cgraph",	                        /* name */
+  gate_lto_out,			        /* gate */
+  NULL,		                        /* execute */
+  NULL,					/* sub */
+  NULL,					/* next */
+  0,					/* static_pass_number */
+  TV_IPA_LTO_OUT,		        /* tv_id */
+  0,	                                /* properties_required */
+  0,					/* properties_provided */
+  0,					/* properties_destroyed */
+  0,            			/* todo_flags_start */
+  TODO_dump_func                        /* todo_flags_finish */
+ },
+ NULL,		                        /* generate_summary */
+ output_cgraph,				/* write_summary */
+ input_cgraph,				/* read_summary */
+ NULL,					/* function_read_summary */
+ 0,					/* TODOs */
+ NULL,			                /* function_transform */
+ NULL					/* variable_transform */
+};
+
Index: lto-cgraph.h
===================================================================
--- lto-cgraph.h	(revision 136409)
+++ lto-cgraph.h	(working copy)
@@ -1,53 +0,0 @@
-/* Declarations and definitions relating to the encoding of the cgraph
-   into the object files.
-
-   Copyright (C) 2008 Free Software Foundation, Inc.
-   Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
-
-   This file is part of GCC.
-
-   GCC is free software; you can redistribute it and/or modify it under
-   the terms of the GNU General Public License as published by the Free
-   Software Foundation; either version 2, or (at your option) any later
-   version.
-
-   GCC is distributed in the hope that it will be useful, but WITHOUT
-   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
-   License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with GCC; see the file COPYING.  If not, write to the Free
-   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.  */
-
-#ifndef GCC_LTO_CGRAPH_H
-#define GCC_LTO_CGRAPH_H
-
-#include "tree.h"
-#include "lto-header.h"
-
-enum LTO_cgraph_tags
-{
-  /* Must leave 0 for the stopper.  */
-  LTO_cgraph_avail_node = 1,
-  LTO_cgraph_overwritable_node,
-  LTO_cgraph_unavail_node,
-  LTO_cgraph_edge,
-  LTO_cgraph_last_tag
-};
-
-/* The is the first part of the cgraph record in the .o file.  */
-struct lto_cgraph_header
-{
-  struct lto_header lto_header;   /* The header for all types of sections. */
-  int32_t main_size;              /* Size of main gimple body of function.  */
-  int32_t debug_main_size;        /* Size of main stream debugging information.  */
-  int32_t compressed_size;
-};
-
-#ifdef LTO_STREAM_DEBUGGING
-extern const char * LTO_cgraph_tag_names[LTO_cgraph_last_tag];
-#endif
-
-#endif /* GCC_LTO_CGRAPH_H */
Index: lto-header.h
===================================================================
--- lto-header.h	(revision 136409)
+++ lto-header.h	(working copy)
@@ -41,7 +41,8 @@ enum lto_section_type
   LTO_section_decls,
   LTO_section_function_body,
   LTO_section_static_initializer,
-  LTO_section_cgraph
+  LTO_section_cgraph,
+  LTO_section_ipa_pure_const
 };
 
 struct lto_header
@@ -51,6 +52,16 @@ struct lto_header
   enum lto_section_type section_type;
 };
 
+/* The is the first part of the record in the .o file for many of the
+   ipa passes.  */
+struct lto_simple_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;
+};
+
 /* In lto-section-out.c.  */
 const char *lto_get_section_name (enum lto_section_type, const char *);
 section *lto_get_section (enum lto_section_type, const char *);
Index: ipa-pure-const.c
===================================================================
--- ipa-pure-const.c	(revision 136409)
+++ ipa-pure-const.c	(working copy)
@@ -1,5 +1,5 @@
 /* Callgraph based analysis of static variables.
-   Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
 
 This file is part of GCC.
@@ -52,6 +52,8 @@ along with GCC; see the file COPYING3.  
 #include "diagnostic.h"
 #include "langhooks.h"
 #include "target.h"
+#include "lto-section-in.h"
+#include "lto-section-out.h"
 
 static struct pointer_set_t *visited_nodes;
 
@@ -65,26 +67,75 @@ enum pure_const_state_e
   IPA_NEITHER
 };
 
-/* Holder inserted into the ipa_dfs_info aux field to hold the
-   const_state.  */
+/* Holder for the const_state.  There is one of these per function
+   decl.  */
 struct funct_state_d 
 {
+  /* See above.  */
   enum pure_const_state_e pure_const_state;
+
+  /* True if the function could possibly infinite loop.  There are a
+     lot of ways that this could be determined.  We are pretty
+     conservative here.  While it is possible to cse pure and const
+     calls, it is not legal to have dce get rid of the call if there
+     is a possibility that the call could infinite loop since this is
+     a behavioral change.  */
   bool looping;
-  bool state_set_in_source;
+
+  /* If the state of the function was set in the source, then assume
+     that it was done properly even if the analysis we do would be
+     more pessimestic.  */
+  bool state_set_in_source; 
 };
 
 typedef struct funct_state_d * funct_state;
 
-/* Return the function state from NODE.  */ 
+
+/* The storage of the funct_state is abstracted because there is the
+   possibility that it may be desirable to move this to the cgraph
+   local info.  */ 
+
+/* Array, indexed by cgraph node uid, of function states.  */
+
+static funct_state *funct_state_vec;
+
+
+/* Init the function state.  */
+
+static void 
+init_state (void)
+{
+  funct_state_vec = XCNEWVEC (funct_state, cgraph_max_uid);
+}
+
+
+/* Init the function state.  */
+
+static void
+finish_state (void)
+{
+  free (funct_state_vec);
+}
+
+
+/* Return the function state from NODE.  */
 
 static inline funct_state
 get_function_state (struct cgraph_node *node)
 {
-  struct ipa_dfs_info * info = (struct ipa_dfs_info *) node->aux;
-  return (funct_state) info->aux;
+  return funct_state_vec[node->uid];
+}
+
+
+/* Set the function state S for NODE.  */
+
+static inline void
+set_function_state (struct cgraph_node *node, funct_state s)
+{
+  funct_state_vec[node->uid] = s;
 }
 
+
 /* Check to see if the use (or definition when CHECHING_WRITE is true) 
    variable T is legal in a function that is either pure or const.  */
 
@@ -286,6 +337,9 @@ get_asm_expr_operands (funct_state local
   const char *constraint;
   bool allows_mem, allows_reg, is_inout;
   
+  if (!memory_identifier_string)
+    memory_identifier_string = build_string(7, "memory");
+
   for (i=0, link = ASM_OUTPUTS (stmt); link; ++i, link = TREE_CHAIN (link))
     {
       oconstraints[i] = constraint
@@ -405,9 +459,7 @@ check_call (funct_state local, tree call
    should be converted to use the operand scanner.  */
 
 static tree
-scan_function (tree *tp, 
-		      int *walk_subtrees, 
-		      void *data)
+scan_stmt (tree *tp, int *walk_subtrees, void *data)
 {
   struct cgraph_node *fn = (struct cgraph_node *) data;
   tree t = *tp;
@@ -417,7 +469,7 @@ scan_function (tree *tp, 
     {
     case VAR_DECL:
       if (DECL_INITIAL (t))
-	walk_tree (&DECL_INITIAL (t), scan_function, fn, visited_nodes);
+	walk_tree (&DECL_INITIAL (t), scan_stmt, fn, visited_nodes);
       *walk_subtrees = 0;
       break;
 
@@ -513,17 +565,17 @@ scan_function (tree *tp, 
   return NULL;
 }
 
+
 /* This is the main routine for finding the reference patterns for
    global variables within a function FN.  */
 
 static void
 analyze_function (struct cgraph_node *fn)
 {
-  funct_state l = XCNEW (struct funct_state_d);
   tree decl = fn->decl;
-  struct ipa_dfs_info * w_info = (struct ipa_dfs_info *) fn->aux;
+  funct_state l = XCNEW (struct funct_state_d);
 
-  w_info->aux = l;
+  set_function_state (fn, l);
 
   l->pure_const_state = IPA_CONST;
   l->state_set_in_source = false;
@@ -570,7 +622,7 @@ analyze_function (struct cgraph_node *fn
 	  block_stmt_iterator bsi;
 	  for (bsi = bsi_start (this_block); !bsi_end_p (bsi); bsi_next (&bsi))
 	    {
-	      walk_tree (bsi_stmt_ptr (bsi), scan_function, 
+	      walk_tree (bsi_stmt_ptr (bsi), scan_stmt, 
 			 fn, visited_nodes);
 	      if (l->pure_const_state == IPA_NEITHER) 
 		goto end;
@@ -611,24 +663,15 @@ end:
 }
 
 
-/* Produce the global information by preforming a transitive closure
-   on the local information that was produced by ipa_analyze_function
-   and ipa_analyze_variable.  */
+/* Analyze each function in the cgraph to see if it is locally PURE or
+   CONST.  */
 
-static unsigned int
-static_execute (void)
+static void 
+generate_summary (void)
 {
   struct cgraph_node *node;
-  struct cgraph_node *w;
-  struct cgraph_node **order =
-    XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
-  int order_pos = ipa_utils_reduced_inorder (order, true, false);
-  int i;
-  struct ipa_dfs_info * w_info;
-
-  if (!memory_identifier_string)
-    memory_identifier_string = build_string(7, "memory");
 
+  init_state ();
   /* There are some shared nodes, in particular the initializers on
      static declarations.  We do not need to scan them more than once
      since all we would be interested in are the addressof
@@ -641,14 +684,109 @@ static_execute (void)
      is a master clone.  However, we do NOT process any
      AVAIL_OVERWRITABLE functions (these are never clones) we cannot
      guarantee that what we learn about the one we see will be true
-     for the one that overriders it.
-  */
+     for the one that overriders it.  */
   for (node = cgraph_nodes; node; node = node->next)
     if (node->analyzed && cgraph_is_master_clone (node, true))
       analyze_function (node);
 
   pointer_set_destroy (visited_nodes);
   visited_nodes = NULL;
+}
+
+
+/* Serialize the info.  */
+
+static void
+write_summary (void)
+{
+  struct cgraph_node *node;
+  struct lto_simple_output_block *ob
+    = lto_create_simple_output_block (LTO_section_ipa_pure_const);
+  unsigned int count = 0;
+
+  for (node = cgraph_nodes; node; node = node->next)
+    if (node->analyzed && cgraph_is_master_clone (node, true))
+      count++;
+  
+  lto_output_uleb128_stream (ob->main_stream, count);
+  
+  /* Process all of the functions.  */
+  for (node = cgraph_nodes; node; node = node->next)
+    if (node->analyzed && cgraph_is_master_clone (node, true))
+      {
+	unsigned HOST_WIDEST_INT flags = 0;
+	funct_state fs = get_function_state (node);
+	
+	lto_output_fn_decl_index (ob->decl_state, ob->main_stream, node->decl);
+	
+	lto_set_flags (&flags, fs->pure_const_state, 2);
+	lto_set_flag (&flags, fs->looping);
+	lto_set_flag (&flags, fs->state_set_in_source);
+	lto_output_uleb128_stream (ob->main_stream, flags);
+      }
+  lto_destroy_simple_output_block (ob);
+}
+
+
+/* Deserialize the info.  */
+
+static void 
+read_summary (void)
+{
+  struct lto_file_decl_data ** file_data_vec 
+    = lto_get_file_decl_data ();
+  struct lto_file_decl_data * file_data;
+  unsigned int j = 0;
+
+  while ((file_data = file_data_vec[j++]))
+    {
+      unsigned int count;
+      unsigned int i;
+      const char *data;
+      size_t len;
+      struct lto_input_block *ib
+	= lto_create_simple_input_block (file_data, 
+					 LTO_section_ipa_pure_const, 
+					 &data, &len);
+      
+      init_state ();
+      
+      count = lto_input_uleb128 (ib);
+      for (i = 0; i < count; i++)
+	{
+	  tree fn_decl = file_data->fn_decls [lto_input_uleb128 (ib)];
+	  unsigned HOST_WIDEST_INT flags = lto_input_uleb128 (ib);
+	  funct_state fs = XCNEW (struct funct_state_d);
+	  
+	  set_function_state (cgraph_node (fn_decl), fs);
+	  fs->state_set_in_source = lto_get_flag (&flags);
+	  fs->looping = lto_get_flag (&flags);
+	  fs->pure_const_state = lto_get_flags (&flags, 2);
+	}
+      
+      lto_destroy_simple_input_block (file_data, 
+				      LTO_section_ipa_pure_const, 
+				      ib, data, len);
+    }
+}
+
+/* Produce the global information by preforming a transitive closure
+   on the local information that was produced by generate_summary.
+   Note that there is no function_transform pass since this only
+   updates the function_decl.  */
+
+static unsigned int
+propagate (void)
+{
+  struct cgraph_node *node;
+  struct cgraph_node *w;
+  struct cgraph_node **order =
+    XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
+  int order_pos;
+  int i;
+  struct ipa_dfs_info * w_info;
+
+  order_pos = ipa_utils_reduced_inorder (order, true, false);
   if (dump_file)
     {
       dump_cgraph (dump_file);
@@ -723,6 +861,8 @@ static_execute (void)
 	  if (!w_l->state_set_in_source)
 	    {
 	      w_l->pure_const_state = pure_const_state;
+	      w_l->looping = looping;
+
 	      switch (pure_const_state)
 		{
 		case IPA_CONST:
@@ -754,17 +894,20 @@ static_execute (void)
 
   /* Cleanup. */
   for (node = cgraph_nodes; node; node = node->next)
-    /* Get rid of the aux information.  */
-    if (node->aux)
-      {
-	w_info = (struct ipa_dfs_info *) node->aux;
-	if (w_info->aux)
-	  free (w_info->aux);
-	free (node->aux);
-	node->aux = NULL;
-      }
-
+    {
+      /* Get rid of the aux information.  */
+      if (node->aux)
+	{
+	  w_info = (struct ipa_dfs_info *) node->aux;
+	  free (node->aux);
+	  node->aux = NULL;
+	}
+      if (node->analyzed && cgraph_is_master_clone (node, true))
+	free (get_function_state (node));
+    }
+  
   free (order);
+  finish_state ();
   return 0;
 }
 
@@ -776,13 +919,13 @@ gate_pure_const (void)
 	  && !(errorcount || sorrycount));
 }
 
-struct simple_ipa_opt_pass pass_ipa_pure_const =
+struct ipa_opt_pass pass_ipa_pure_const =
 {
  {
-  SIMPLE_IPA_PASS,
+  IPA_PASS,
   "pure-const",		                /* name */
   gate_pure_const,			/* gate */
-  static_execute,			/* execute */
+  propagate,			        /* execute */
   NULL,					/* sub */
   NULL,					/* next */
   0,					/* static_pass_number */
@@ -792,7 +935,12 @@ struct simple_ipa_opt_pass pass_ipa_pure
   0,					/* properties_destroyed */
   0,					/* todo_flags_start */
   0                                     /* todo_flags_finish */
- }
+ },
+ generate_summary,		        /* generate_summary */
+ write_summary,				/* write_summary */
+ read_summary,				/* read_summary */
+ NULL,					/* function_read_summary */
+ 0,					/* TODOs */
+ NULL,			                /* function_transform */
+ NULL					/* variable_transform */
 };
-
-
Index: lto-cgraph-in.c
===================================================================
--- lto-cgraph-in.c	(revision 136409)
+++ lto-cgraph-in.c	(working copy)
@@ -1,246 +0,0 @@
-/* Read the cgraph from the memory mapped representation of a a .o file.
-
-   Copyright 2008 Free Software Foundation, Inc.
-   Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GCC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-#include "toplev.h"
-#include "tree.h"
-#include "expr.h"
-#include "flags.h"
-#include "params.h"
-#include "input.h"
-#include "varray.h"
-#include "hashtab.h"
-#include "langhooks.h"
-#include "basic-block.h"
-#include "tree-iterator.h"
-#include "tree-pass.h"
-#include "tree-flow.h"
-#include "cgraph.h"
-#include "function.h"
-#include "ggc.h"
-#include "diagnostic.h"
-#include "except.h"
-#include "debug.h"
-#include "vec.h"
-#include "timevar.h"
-#include "dwarf2asm.h"
-#include "dwarf2out.h"
-#include "output.h"
-#include "lto-cgraph.h"
-#include "lto-section-in.h"
-#include <ctype.h>
-#include "cpplib.h"
-
-struct data_in
-{
-  /* That global decls and types.  */
-  struct lto_file_decl_data* file_data;
-};
-
-
-/* Return 0 or 1 based on the last bit of FLAGS and right shift FLAGS
-   by 1.  */
-
-static unsigned int
-add_flag (unsigned int *flags)
-{
-  unsigned int result = *flags & 1;
-  *flags = *flags >> 1;
-  return result;
-}
-
-/* Overwrite the information in NODE based on DATA_IN, TAG, FLAGS,
-   STACK_SIZE and SELF_INSNS.  This is called either to initialize
-   NODE or to replace the values in it, for instance becasue the first
-   time we saw it, the function body was not available but now it
-   is.  */
-static void
-overwrite_node (struct data_in *data_in,
-		struct cgraph_node *node,
-		enum LTO_cgraph_tags tag,
-		unsigned int flags,
-		unsigned int stack_size,
-		unsigned int self_insns)
-{
-  node->aux = (void *)tag;
-  node->local.inline_summary.estimated_self_stack_size = stack_size;
-  node->local.inline_summary.self_insns = self_insns;
-  node->global.insns = self_insns;
-  if (!node->local.lto_file_data)
-    node->local.lto_file_data = xcalloc (1, sizeof (struct lto_file_decl_data));
-  
-  node->local.lto_file_data = data_in->file_data;
-
-  /* This list must be in the reverse order that they are set in
-     lto-section-out.c:outout_node.  */
-  node->local.vtable_method = add_flag (&flags);
-  node->local.for_functions_valid = add_flag (&flags);
-  node->local.redefined_extern_inline = add_flag (&flags);
-  node->local.disregard_inline_limits = add_flag (&flags);
-  node->local.inlinable = add_flag (&flags);
-  node->local.finalized = add_flag (&flags);
-  node->local.externally_visible = add_flag (&flags);
-  node->local.local = add_flag (&flags);
-  node->analyzed = node->local.finalized;
-    node->lowered = node->local.finalized;
-  if (cgraph_decide_is_function_needed (node))
-    cgraph_mark_needed_node (node);
-}
-
-
-/* Input a cgraph from IB using the info in DATA_IN.  */
-
-static void
-input_cgraph (struct lto_input_block *ib,
-	      struct data_in *data_in)
-{
-  enum LTO_cgraph_tags tag;
-  struct cgraph_node *last_caller = NULL;
-
-  tag = lto_input_uleb128 (ib);
-  while (tag)
-    {
-      LTO_DEBUG_INDENT (tag);
-
-      if (tag == LTO_cgraph_edge)
-	{
-	  tree callee_decl;
-	  struct cgraph_node *callee;
-	  struct cgraph_edge *edge;
-	  unsigned int stmt_id;
-	  unsigned int count;
-	  unsigned int freq;
-	  unsigned int nest;
-
-	  callee_decl = data_in->file_data->fn_decls [lto_input_uleb128 (ib)];
-	  LTO_DEBUG_FN_NAME (callee_decl);
-	  callee = cgraph_node (callee_decl);
-	  
-	  LTO_DEBUG_TOKEN ("stmt");
-	  stmt_id = lto_input_uleb128 (ib);
-	  LTO_DEBUG_TOKEN ("count");
-	  count = lto_input_uleb128 (ib);
-	  LTO_DEBUG_TOKEN ("frequency");
-	  freq = lto_input_uleb128 (ib);
-	  LTO_DEBUG_TOKEN ("loop_next");
-	  nest = lto_input_uleb128 (ib);
-	  
-	  edge = cgraph_create_edge (last_caller, callee, NULL, count, freq, nest);
-	  edge->lto_stmt_uid = stmt_id;
-	}
-      else 
-	{
-	  tree fn_decl;
-	  struct cgraph_node *node;
-	  unsigned int flags;
-	  int stack_size = 0;
-	  int self_insns = 0;
-	  
-	  fn_decl = data_in->file_data->fn_decls [lto_input_uleb128 (ib)];
-	  LTO_DEBUG_FN_NAME (fn_decl);
-	  LTO_DEBUG_TOKEN ("flags");
-	  flags = lto_input_uleb128 (ib);
-	  
-	  if (tag == LTO_cgraph_avail_node)
-	    {
-	      LTO_DEBUG_TOKEN ("stack_size");
-	      stack_size = lto_input_sleb128 (ib);
-	      LTO_DEBUG_TOKEN ("self_insns");
-	      self_insns = lto_input_sleb128 (ib);
-	    }
-	  
-	  node = cgraph_node (fn_decl);
-	  
-	  switch (tag)
-	    {
-	    case LTO_cgraph_avail_node:
-	      /* We cannot have two avail functions that are the same.  */
-	      gcc_assert (((enum LTO_cgraph_tags)(node->aux)) != LTO_cgraph_avail_node);
-	      overwrite_node (data_in, node, tag, flags, stack_size, self_insns);
-	      break;
-	      
-	    case LTO_cgraph_unavail_node:
-	      /* We only overwrite the node if this is a brand new node.  */
-	      if (!node->aux)
-		overwrite_node (data_in, node, tag, flags, stack_size, self_insns);
-	      break;
-	      
-	    case LTO_cgraph_overwritable_node:
-	      /* FIXME!!!!  This code is written to take the last
-		 overwrittable version.  I do not speak linker but if the
-		 linker supposed to take the first one, then we need to
-		 change the test.  */
-	      if (((enum LTO_cgraph_tags)(node->aux)) != LTO_cgraph_avail_node)
-		overwrite_node (data_in, node, tag, flags, stack_size, self_insns);
-	      break;
-	      
-	    default:
-	      gcc_unreachable ();
-	    }
-	  
-	  /* Set this up so that we can handle the edges which follow and
-	     only have the callee in them.  */
-	  last_caller = node;
-	}
-      LTO_DEBUG_UNDENT();
-      tag = lto_input_uleb128 (ib);
-    }
-}
-
-/* Read the body form DATA using the symbols in FILE_DATA to
-   reconstruct the part of the cgraph associated with FILE_DATA.  */
-
-void 
-lto_input_cgraph (struct lto_file_decl_data* file_data, const char *data)
-{
-  const struct lto_cgraph_header * header 
-    = (const struct lto_cgraph_header *) data;
-  struct data_in data_in;
-  struct lto_input_block ib_main;
-  
-  int32_t main_offset = sizeof (struct lto_cgraph_header); 
-#ifdef LTO_STREAM_DEBUGGING
-  int32_t debug_main_offset = main_offset + header->main_size;
-  struct lto_input_block debug_main;
-#endif
-
-  LTO_INIT_INPUT_BLOCK (ib_main, data + main_offset,
-			0, header->main_size);
-  memset (&data_in, 0, sizeof (struct data_in));
-  data_in.file_data          = file_data;
-  
-#ifdef LTO_STREAM_DEBUGGING
-  LTO_INIT_INPUT_BLOCK (debug_main, data + debug_main_offset,
-			0, header->debug_main_size);
-  lto_debug_context.current_data = &debug_main;
-  lto_debug_context.indent = 0;
-  lto_debug_context.stream_name = "cgraph";
-  lto_debug_context.tag_names = LTO_cgraph_tag_names;
-#endif
-  /* Read in the cgraph for this file and merge it into the main
-     one.  */
-  input_cgraph (&ib_main, &data_in);
-}
-
Index: lto-section-in.c
===================================================================
--- lto-section-in.c	(revision 136409)
+++ lto-section-in.c	(working copy)
@@ -53,6 +53,32 @@ Boston, MA 02110-1301, USA.  */
 #include <ctype.h>
 #include "cpplib.h"
 
+
+/* Return 0 or 1 based on the last bit of FLAGS and right shift FLAGS
+   by 1.  */
+
+unsigned int
+lto_get_flag (unsigned HOST_WIDEST_INT *flags)
+{
+  unsigned int result = *flags & 1;
+  *flags = *flags >> 1;
+  return result;
+}
+
+
+/* Return an integer based on the last WIDTH bits of FLAGS and right
+   shift FLAGS by WIDTH.  */
+
+unsigned int
+lto_get_flags (unsigned HOST_WIDEST_INT *flags, unsigned int width)
+{
+  unsigned HOST_WIDEST_INT mask = 1 << (((unsigned HOST_WIDEST_INT)width) - 1);
+  unsigned int result = *flags & mask;
+  *flags = *flags >> width;
+  return result;
+}
+
+
 unsigned char 
 lto_input_1_unsigned (struct lto_input_block *ib)
 {
@@ -185,70 +211,128 @@ 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;
-}    
+/* Hooks so that the ipa passes can call into the lto front end to get
+   sections.  */
+
+static struct lto_file_decl_data ** file_decl_data; 
+static lto_get_section_data_f* get_section_f;
+static lto_free_section_data_f* free_section_f;
+
+
+/* This is called from the lto front end to set up the hooks that are
+   used by the ipa passes to get the data that they will
+   deserialize.  */
+
+void 
+lto_set_in_hooks (struct lto_file_decl_data ** data, 
+		  lto_get_section_data_f* get_f,
+		  lto_free_section_data_f* free_f)
+{
+  file_decl_data = data;
+  get_section_f = get_f;
+  free_section_f = free_f;
+}
 
 
-/* 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.  */
+/* Return an array of file decl datas for all of the files passed to
+   this compilation.  */
 
-char *
+struct lto_file_decl_data **
+lto_get_file_decl_data (void)
+{
+  gcc_assert (file_decl_data);
+  return file_decl_data;
+}
+
+/* Return a char pointer to the start of a data stream for an lto pass
+   or function.  FILE_DATA indicates where to obtain the data.
+   SECTION_TYPE is the type of information to be obtained.  NAME is
+   the name of the function and is only used when finding a function
+   body; otherwise it is NULL.  LEN is the size of the data
+   returned.  */
+
+const char* 
 lto_get_section_data (struct lto_file_decl_data *file_data, 
 		      enum lto_section_type section_type,
-		      const char *name)
+		      const char *name, 
+		      size_t *len)
+{
+  gcc_assert (get_section_f);
+  return (get_section_f) (file_data, section_type, name, len);
+}
+
+
+/* Return the data found from the above call.  The first three
+   parameters are the same as above.  DATA is the data to be freed and
+   LEN is the length of that data. */
+
+void 
+lto_free_section_data (struct lto_file_decl_data *file_data, 
+		       enum lto_section_type section_type,
+		       const char *name,
+		       const char *data,
+		       size_t len)
 {
-  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);
+  gcc_assert (free_section_f);
+  (free_section_f) (file_data, section_type, name, data, len);
+}
+
+
+/* Load a section of type SECTION_TYPE from FILE_DATA, parse the
+   header and then return an input block pointing to the section.  The
+   raw pointer to the section is returned in DATAR and LEN.  These are
+   used to free the section.  */
+
+struct lto_input_block *
+lto_create_simple_input_block (struct lto_file_decl_data *file_data, 
+			       enum lto_section_type section_type,
+			       const char **datar, size_t *len)
+{
+  const char *data = lto_get_section_data (file_data, section_type, NULL, len);
+  const struct lto_simple_header * header 
+    = (const struct lto_simple_header *) data;
+  struct lto_input_block* ib_main = XNEW (struct lto_input_block);
+  int32_t main_offset = sizeof (struct lto_simple_header); 
+#ifdef LTO_STREAM_DEBUGGING
+  int32_t debug_main_offset = main_offset + header->main_size;
+  struct lto_input_block *debug_main = XNEW (struct lto_input_block);
+#endif
 
-  free ((char *)section_name);
-  return data;
+  *datar = data;
+  LTO_INIT_INPUT_BLOCK_PTR (ib_main, data + main_offset,
+			    0, header->main_size);
+#ifdef LTO_STREAM_DEBUGGING
+  lto_debug_context.out = lto_debug_in_fun;
+  LTO_INIT_INPUT_BLOCK_PTR (debug_main, data + debug_main_offset,
+			    0, header->debug_main_size);
+  lto_debug_context.current_data = debug_main;
+  lto_debug_context.indent = 0;
+#endif
+  
+  return ib_main;
 }
 
 
+/* Close the section returned from a call to
+   LTO_CREATE_SIMPLE_INPUT_BLOCK.  IB is the input block returned from
+   that call.  The FILE_DATA and SECTION_TYPE are the same as what was
+   passed to that call and the DATA and LEN are what was returned from
+   that call.  */
+
+void
+lto_destroy_simple_input_block (struct lto_file_decl_data *file_data, 
+				enum lto_section_type section_type,
+				struct lto_input_block *ib,
+				const char *data, size_t len)
+{
+  free (ib);
+#ifdef LTO_STREAM_DEBUGGING
+  free (lto_debug_context.current_data);
+#endif
+  lto_free_section_data (file_data, section_type, NULL, data, len);
+}
+
 /*****************************************************************************/
 /* Stream debugging support code.                                            */
 /*****************************************************************************/
Index: lto-section-in.h
===================================================================
--- lto-section-in.h	(revision 136409)
+++ lto-section-in.h	(working copy)
@@ -21,6 +21,8 @@ along with GCC; see the file COPYING3.  
 #ifndef GCC_LTO_SECTION_IN_H
 #define GCC_LTO_SECTION_IN_H
 
+#include "lto-header.h"
+
 struct lto_input_block 
 {
   const char *data;
@@ -35,15 +37,12 @@ struct lto_input_block 
     BASE.len = L;                          \
   } while (0)
 
-/* 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;
-};
-
+#define LTO_INIT_INPUT_BLOCK_PTR(BASE,D,P,L) \
+  do {                                       \
+    BASE->data = D;                          \
+    BASE->p = P;                             \
+    BASE->len = L;                           \
+  } while (0)
 
 /* One of these is allocated for each object file that being compiled
    by lto.  This structure contains the tables that are needed for the
@@ -70,10 +69,44 @@ struct lto_file_decl_data
   have been archived.  */ 
   const char * file_name;
 
+  /* If the file is open, this is the fd of the mapped section.  This is -1 if
+     the file has not yet been opened.  */
+  int fd;
+
   /* Hash table to contains the location of the lto bodies in file_name. */
   htab_t section_hash_table;
 };
 
+struct lto_file_decl_data;
+
+/* Return a char pointer to the start of a data stream for an lto pass
+   or function.  The first parameter is the file data that contains
+   the information.  The second parameter is the type of information
+   to be obtained.  The third parameter is the name of the function
+   and is only used when finding a function body; otherwise it is 
+   NULL.  The fourth parameter is the length of the data returned.  */
+typedef const char* (lto_get_section_data_f) (struct lto_file_decl_data *, 
+					      enum lto_section_type,
+					      const char *, 
+					      size_t *);
+
+/* Return the data found from the above call.  The first three
+   parameters are the same as above.  The fourth parameter is the data
+   itself and the fifth is the lenght of the data. */
+typedef void (lto_free_section_data_f) (struct lto_file_decl_data *, 
+					enum lto_section_type,
+					const char *,
+					const char *,
+					size_t);
+
+extern struct lto_input_block *
+lto_create_simple_input_block (struct lto_file_decl_data *, 
+			       enum lto_section_type, const char **, size_t *);
+extern void
+lto_destroy_simple_input_block (struct lto_file_decl_data *, 
+				enum lto_section_type,
+				struct lto_input_block *, const char *, size_t);
+
 
 /* lto-function-in.c */
 
@@ -104,13 +137,23 @@ lto_input_constructors_and_inits (struct
 extern void
 lto_input_cgraph (struct lto_file_decl_data* file_data, const char *data);
 
+/* lto-section-in.c */
+
+extern unsigned int lto_get_flag (unsigned HOST_WIDEST_INT *);
+extern unsigned int lto_get_flags (unsigned HOST_WIDEST_INT *, unsigned int);
+extern void lto_set_in_hooks (struct lto_file_decl_data **, 
+			      lto_get_section_data_f*,
+			      lto_free_section_data_f*);
+extern struct lto_file_decl_data **lto_get_file_decl_data (void);
+extern const char* lto_get_section_data (struct lto_file_decl_data *, enum lto_section_type,
+					 const char *, size_t *);
+extern void lto_free_section_data (struct lto_file_decl_data *, enum lto_section_type,
+				   const char *, const char *, size_t);
 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
 extern void lto_debug_in_fun (struct lto_debug_context *, char);
Index: lto/lto.c
===================================================================
--- lto/lto.c	(revision 136409)
+++ lto/lto.c	(working copy)
@@ -19,6 +19,7 @@ along with GCC; see the file COPYING.  I
 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
 Boston, MA 02110-1301, USA.  */
 
+#include <sys/mman.h>
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
@@ -36,6 +37,7 @@ Boston, MA 02110-1301, USA.  */
 #include "langhooks.h"
 #include "lto-section.h"
 #include "lto-section-in.h"
+#include "tree-pass.h"
 
 /* References 
 
@@ -2427,9 +2429,11 @@ lto_get_body (lto_info_fd *fd,
 static void
 lto_materialize_constructors_and_inits (struct lto_file_decl_data * file_data)
 {
-  const char *data = lto_get_section_data (file_data, LTO_section_static_initializer, NULL);
+  size_t len;
+  const char *data = lto_get_section_data (file_data, 
+					   LTO_section_static_initializer, NULL, &len);
   lto_input_constructors_and_inits (file_data, data);
-  free ((char *)data);
+  lto_free_section_data (file_data, LTO_section_static_initializer, NULL, data, len);
 }
 
 /* Read the function body for DECL out of FD if possible.  */
@@ -2440,10 +2444,12 @@ lto_materialize_function (struct cgraph_
   tree decl = node->decl;
   struct lto_file_decl_data *file_data = node->local.lto_file_data;
   const char *data;
+  size_t len;
   tree step;
+  const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); 
 
   data = lto_get_section_data (file_data, LTO_section_function_body,
-			       IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+			       name, &len);
   if (data)
     {
       struct function *fn;
@@ -2455,7 +2461,7 @@ lto_materialize_function (struct cgraph_
       allocate_struct_function (decl, false);
       lto_input_function_body (file_data, decl, data);
       fn = DECL_STRUCT_FUNCTION (decl);
-      free ((char *)data);
+      lto_free_section_data (file_data, LTO_section_function_body, name, data, len);
 
       /* Look for initializers of constant variables and private
 	 statics.  */
@@ -2481,16 +2487,6 @@ lto_materialize_function (struct cgraph_
     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);
-}
-
 /* Load in the global vars and all of the types from the main symbol
    table.  */
 
@@ -2562,6 +2558,9 @@ lto_read_decls (lto_info_fd *fd,
 
   data_in->file_name = lto_get_file_name (fd);
 
+  /* The file is marked as not currently open.  */
+  data_in->fd = -1;
+
   return data_in;
 }
 
@@ -3656,20 +3655,24 @@ lto_set_cu_context (lto_context *context
 
 /* 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.
+   another object file), merge the two entities.  Returns the
+   file_data from the last context.  
+
+   FIXME, this is a bug that will go away with Maddox's streaming
+   merge since there will no longer be contexts.
 
    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
+static struct lto_file_decl_data*
 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;
+  struct lto_file_decl_data* file_data = NULL;
+
   /* Read the abbreviation entries.  */
   lto_abbrev_read (&file->debug_abbrev);
   /* Read the compilation units.  */
@@ -3683,7 +3686,6 @@ lto_file_read (lto_file *file)
       DWARF2_CompUnit *unit = file->debug_info.units[i];
       /* The context information for this compilation unit.  */
       lto_context context;
-      htab_t section_hash_table;
       
       /* Set up the context.  */
       lto_set_cu_context (&context, &file->debug_info, unit);
@@ -3721,16 +3723,10 @@ 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_data);
-
-      lto_materialize_cgraph (file_data);
     }
 
-  return true;
+  return file_data;
 }
 
 tree 
@@ -3899,6 +3895,111 @@ lto_resolve_namespacedecl_ref (lto_info_
   return decl;
 }
 
+/****************************************************************************
+  Input routines for reading sections from .o files.
+
+  FIXME: These routines may need to be generalized.  They assume that
+  the .o file can be read into memory and the secions just mapped.
+  This may not be true if the .o file is in some form of archive.
+****************************************************************************/
+
+/* Page size of machine is used for mmap and munmap calls.  */
+static size_t page_mask;
+
+/* 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 (struct lto_file_decl_data *file_data, 
+		       intptr_t offset, size_t len)
+{
+  char *result;
+  intptr_t computed_len;
+  intptr_t computed_offset;
+  intptr_t diff;
+
+  if (!page_mask)
+    {
+      size_t page_size = sysconf (_SC_PAGE_SIZE);
+      page_mask = ~(page_size - 1);
+    }
+
+  if (file_data->fd == -1)
+    file_data->fd = open (file_data->file_name, O_RDONLY);
+
+  if (file_data->fd == -1)
+    return NULL;
+
+  computed_offset = offset & page_mask;
+  diff = offset - computed_offset;
+  computed_len = len + diff;
+
+  result = mmap (NULL, computed_len, PROT_READ, MAP_PRIVATE, 
+		 file_data->fd, computed_offset);
+  if (result == MAP_FAILED)
+    {
+      close (file_data->fd);
+      return NULL;
+    }
+
+  return result + diff;
+}    
+
+
+/* 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.  */
+
+static const char *
+get_section_data (struct lto_file_decl_data *file_data, 
+		      enum lto_section_type section_type,
+		      const char *name,
+		      size_t *len)
+{
+  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, f_slot->start, f_slot->len);
+      *len = f_slot->len;
+    }
+
+  free ((char *)section_name);
+  return data;
+}
+
+
+/* Free the section data from FILE_DATA of SECTION_TYPE with NAME that
+   starts at OFFSET and has LEN bytes.  */
+
+static void
+free_section_data (struct lto_file_decl_data *file_data, 
+		       enum lto_section_type section_type ATTRIBUTE_UNUSED,
+		       const char *name ATTRIBUTE_UNUSED,
+		       const char *offset, size_t len)
+{
+  intptr_t computed_len;
+  intptr_t computed_offset;
+  intptr_t diff;
+
+  if (file_data->fd == -1)
+    return;
+
+  computed_offset = ((intptr_t)offset) & page_mask;
+  diff = (intptr_t)offset - computed_offset;
+  computed_len = len + diff;
+
+  munmap ((void *)computed_offset, computed_len);
+}
+
+
 /* Needed so the garbage collector knows to root around in functions we
    have not yet materialized and the huge DIE -> tree table we keep
    around.  */
@@ -3907,22 +4008,51 @@ static GTY(()) lto_file *current_lto_fil
 void
 lto_main (int debug_p ATTRIBUTE_UNUSED)
 {
-  unsigned i;
+  unsigned int i;
+  unsigned int j = 0;
   tree decl;
   struct cgraph_node *node; 
+  struct lto_file_decl_data** all_file_decl_data 
+    = XNEWVEC (struct lto_file_decl_data*, num_in_fnames + 1);
+  struct lto_file_decl_data* file_data = NULL;
 
   /* Read all of the object files specified on the command line.  */
   for (i = 0; i < num_in_fnames; ++i)
     {
+      htab_t section_hash_table;
       current_lto_file = lto_elf_file_open (in_fnames[i]);
       if (!current_lto_file)
 	break;
-      if (!lto_file_read (current_lto_file))
+      file_data = lto_file_read (current_lto_file);
+      if (!file_data)
 	break;
+
+      section_hash_table = lto_elf_build_section_table (current_lto_file);
+      file_data->section_hash_table = section_hash_table;
+
+      all_file_decl_data [j++] = file_data;
+
       lto_elf_file_close (current_lto_file);
       current_lto_file = NULL;
     }
 
+  all_file_decl_data [j] = NULL;
+
+  /* Set the hooks so that all of the ipa passes can read in their data.  */
+  lto_set_in_hooks (all_file_decl_data, get_section_data,
+		    free_section_data);
+
+  /* FIXME!!! This loop needs to be changed to use the pass manager to
+     call the ipa passes directly.  */
+  for (i = 0; i < j; i++)
+    {
+      struct lto_file_decl_data* file_data = all_file_decl_data [i];
+      
+      lto_materialize_constructors_and_inits (file_data);
+    }
+
+  ipa_read_summaries ();
+
   /* Now that we have input the cgraph, we need to clear all of the aux
      nodes and read the functions.  
 
@@ -3939,7 +4069,6 @@ lto_main (int debug_p ATTRIBUTE_UNUSED)
      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: lto/Make-lang.in
===================================================================
--- lto/Make-lang.in	(revision 136409)
+++ lto/Make-lang.in	(working copy)
@@ -80,8 +80,9 @@ lto/lto-lang.o: lto/lto-lang.c $(CONFIG_
 	flags.h $(GGC_H) langhooks.h $(LANGHOOKS_DEF_H) $(SYSTEM_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 lto-section.h lto-section-in.h
+	$(GGC_H) opts.h $(SYSTEM_H) toplev.h $(TM_H) $(LTO_H) langhooks.h \
+	lto/lto-tree.h dwarf2out.h tm.h tree-ssa-operands.h \
+	gt-lto-lto.h lto-section.h lto-section-in.h tree-pass.h
 lto/lto-elf.o: lto/lto-elf.c $(CONFIG_H) coretypes.h $(SYSTEM_H) \
 	toplev.h $(LTO_H) $(TM_H)
 lto/lto-symtab.o: lto/lto-symtab.c $(CONFIG_H) coretypes.h \
Index: lto/lto.h
===================================================================
--- lto/lto.h	(revision 136409)
+++ lto/lto.h	(working copy)
@@ -260,4 +260,14 @@ extern tree lto_symtab_merge_var (tree n
 /* Like lto_symtab_merge_var, but for functions.  */
 extern tree lto_symtab_merge_fn (tree new_fn);
 
+/* 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;
+  intptr_t start;
+  size_t len;
+};
+
+
 #endif /* LTO_H */
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 136409)
+++ Makefile.in	(working copy)
@@ -836,6 +836,7 @@ DBGCNT_H = dbgcnt.h dbgcnt.def
 EBIMAP_H = ebitmap.h sbitmap.h
 LTO_TAGS_H = lto-tags.h tree.h sbitmap.h lto-header.h
 LTO_SECTION_H = lto-section.h lto-header.h
+LTO_SECTION_IN_H = lto-section-in.h lto-header.h
 TREE_VECTORIZER_H = tree-vectorizer.h $(TREE_DATA_REF_H)
 
 #
@@ -1088,8 +1089,7 @@ OBJS-common = \
 	loop-unroll.o \
 	loop-unswitch.o \
 	lower-subreg.o \
-	lto-cgraph-in.o \
-	lto-cgraph-out.o \
+	lto-cgraph.o \
 	lto-function-in.o \
 	lto-function-out.o \
 	lto-section-in.o \
@@ -1985,24 +1985,18 @@ double-int.o: double-int.c $(CONFIG_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  $(TREE_H) \
    lto-header.h 
-lto-cgraph-in.o: lto-cgraph-in.c $(CONFIG_H) $(SYSTEM_H) coretypes.h   \
+lto-cgraph.o: lto-cgraph.c $(CONFIG_H) $(SYSTEM_H) coretypes.h   \
    $(TM_H) toplev.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-section-in.h \
-   output.h dwarf2asm.h dwarf2out.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 
+   except.h debug.h $(TIMEVAR_H) $(LTO_TAGS_H) $(LTO_SECTION_IN_H) \
+   lto-section-out.h output.h dwarf2asm.h dwarf2out.h
 lto-function-in.o: lto-function-in.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
    $(TM_H) toplev.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-section-in.h lto-tree-flags.def \
-   lto-tree-tags.def lto-section-in.h output.h dwarf2asm.h dwarf2out.h
+   debug.h $(TIMEVAR_H) $(LTO_TAGS_H) lto-tree-flags.def \
+   lto-tree-tags.def $(LTO_SECTION_IN_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 \
@@ -2013,7 +2007,7 @@ lto-section-in.o: lto-section-in.c $(CON
    toplev.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-section-in.h output.h dwarf2asm.h dwarf2out.h
+   debug.h $(TIMEVAR_H) $(LTO_SECTION_IN_H) output.h dwarf2asm.h dwarf2out.h
 lto-section-out.o : lto-section-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 \
Index: passes.c
===================================================================
--- passes.c	(revision 136409)
+++ passes.c	(working copy)
@@ -569,19 +569,20 @@ init_optimization_passes (void)
 	}
       NEXT_PASS (pass_rebuild_cgraph_edges);
     }
-  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);
-  NEXT_PASS (pass_ipa_inline);
   NEXT_PASS (pass_ipa_reference);
+  /* All regular IPA_PASSes need to be clumped together.  */
+  NEXT_PASS (pass_ipa_lto_gimple_out);
+  NEXT_PASS (pass_ipa_lto_cgraph);
+  NEXT_PASS (pass_ipa_inline);
   NEXT_PASS (pass_ipa_pure_const); 
+  /* This must be the last IPA_PASS.  */
+  NEXT_PASS (pass_ipa_lto_finish_out);
   NEXT_PASS (pass_ipa_type_escape);
   NEXT_PASS (pass_ipa_pta);
   NEXT_PASS (pass_ipa_struct_reorg);
-  /* This must be the last ipa pass.  */
-  NEXT_PASS (pass_ipa_lto_finish_out);
   
   *p = NULL;
 
@@ -1172,7 +1173,8 @@ execute_ipa_summary_passes (struct ipa_o
 
       /* Execute all of the IPA_PASSes in the list.  */
       if (ipa_pass->pass.type == IPA_PASS 
-	  && (!pass->gate || pass->gate ()))
+	  && (!pass->gate || pass->gate ())
+	  && ipa_pass->generate_summary)
 	{
 	  pass_init_dump_file (pass);
 	  ipa_pass->generate_summary ();
@@ -1345,6 +1347,59 @@ execute_pass_list (struct opt_pass *pass
 
 /* Same as execute_pass_list but assume that subpasses of IPA passes
    are local passes.  */
+static void
+ipa_write_summaries_1 (struct opt_pass *pass)
+{
+  do
+    {
+      struct ipa_opt_pass *ipa_pass = (struct ipa_opt_pass *)pass;
+      gcc_assert (!current_function_decl);
+      gcc_assert (!cfun);
+      gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
+      if (pass->type == IPA_PASS && ipa_pass->write_summary && (!pass->gate || pass->gate ()))
+	ipa_pass->write_summary ();
+      if (pass->sub && pass->sub->type != GIMPLE_PASS)
+	ipa_write_summaries_1 (pass->sub);
+      pass = pass->next;
+    }
+  while (pass);
+}
+
+void
+ipa_write_summaries (void)
+{
+  if (flag_generate_lto && !(errorcount || sorrycount))
+    ipa_write_summaries_1 (all_ipa_passes);
+}
+
+/* Same as execute_pass_list but assume that subpasses of IPA passes
+   are local passes.  */
+static void
+ipa_read_summaries_1 (struct opt_pass *pass)
+{
+  do
+    {
+      struct ipa_opt_pass *ipa_pass = (struct ipa_opt_pass *)pass;
+      gcc_assert (!current_function_decl);
+      gcc_assert (!cfun);
+      gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
+      if (pass->type == IPA_PASS && ipa_pass->read_summary)
+	ipa_pass->read_summary ();
+      if (pass->sub && pass->sub->type != GIMPLE_PASS)
+	ipa_read_summaries_1 (pass->sub);
+      pass = pass->next;
+    }
+  while (pass);
+}
+
+void
+ipa_read_summaries (void)
+{
+  ipa_read_summaries_1 (all_ipa_passes);
+}
+
+/* Same as execute_pass_list but assume that subpasses of IPA passes
+   are local passes.  */
 void
 execute_ipa_pass_list (struct opt_pass *pass)
 {
@@ -1361,11 +1416,10 @@ execute_ipa_pass_list (struct opt_pass *
 	      if (!quiet_flag && !cfun)
 		fprintf (stderr, " <summary generate>");
 	      execute_ipa_summary_passes ((struct ipa_opt_pass *) pass);
+              ipa_write_summaries ();
 	    }
 	  summaries_generated = true;
 	}
-      else
-	summaries_generated = false;
       if (execute_one_pass (pass) && pass->sub)
 	{
 	  if (pass->sub->type == GIMPLE_PASS)
Index: lto-cgraph-out.c
===================================================================
--- lto-cgraph-out.c	(revision 136409)
+++ lto-cgraph-out.c	(working copy)
@@ -1,364 +0,0 @@
-/* Write the cgraph to a .o file.
-
-   Copyright 2008 Free Software Foundation, Inc.
-   Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-GCC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-#include "toplev.h"
-#include "tree.h"
-#include "expr.h"
-#include "flags.h"
-#include "params.h"
-#include "input.h"
-#include "varray.h"
-#include "hashtab.h"
-#include "langhooks.h"
-#include "basic-block.h"
-#include "tree-iterator.h"
-#include "tree-pass.h"
-#include "tree-flow.h"
-#include "cgraph.h"
-#include "function.h"
-#include "ggc.h"
-#include "diagnostic.h"
-#include "except.h"
-#include "debug.h"
-#include "vec.h"
-#include "tree-vectorizer.h"
-#include "timevar.h"
-#include "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.inline_summary.estimated_self_stack_size);
-      LTO_DEBUG_TOKEN ("self_insns");
-      output_sleb128 (ob, node->local.inline_summary.self_insns);
-    }
-
-  LTO_DEBUG_UNDENT();
-
-#ifdef LTO_STREAM_DEBUGGING
-  gcc_assert (lto_debug_context.indent == 0);
-#endif
-
-  while (callees)
-    {
-      output_edge (ob, callees);
-      callees = callees->next_callee;
-    }
-
-#ifdef LTO_STREAM_DEBUGGING
-  gcc_assert (lto_debug_context.indent == 0);
-#endif
-}
-
-
-/* Produce the section that holds the cgraph.  */
-
-static void
-produce_asm (struct output_block *ob)
-{
-  struct lto_cgraph_header header;
-  section *section = lto_get_section (LTO_section_cgraph, NULL);
-
-  memset (&header, 0, sizeof (struct lto_cgraph_header)); 
-
-  /* The entire header is stream computed here.  */
-  switch_to_section (section);
-  
-  /* Write the header which says how to decode the pieces of the
-     t.  */
-  header.lto_header.major_version = LTO_major_version;
-  header.lto_header.minor_version = LTO_minor_version;
-  header.lto_header.section_type = LTO_section_cgraph;
-  
-  header.compressed_size = 0;
-  
-  header.main_size = ob->main_stream->total_size;
-#ifdef LTO_STREAM_DEBUGGING
-  header.debug_main_size = ob->debug_main_stream->total_size;
-#else
-  header.debug_main_size = -1;
-#endif
-
-  assemble_string ((const char *)&header, 
-		   sizeof (struct lto_cgraph_header));
-
-  lto_write_stream (ob->main_stream);
-#ifdef LTO_STREAM_DEBUGGING
-  lto_write_stream (ob->debug_main_stream);
-#endif
-}
-
-
-/* Output the cgraph.  */
-
-static unsigned int
-lto_output_cgraph (void)
-{
-  struct cgraph_node *node;
-  section *saved_section = in_section;
-  struct output_block *ob = create_output_block ();
-
-  LTO_SET_DEBUGGING_STREAM (debug_main_stream, main_data);
-
-  /* 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 simple_ipa_opt_pass pass_ipa_lto_cgraph_out =
-{
- {
-  SIMPLE_IPA_PASS,
-  "lto_cgraph_out",	                /* name */
-  gate_lto_out,			        /* gate */
-  lto_output_cgraph,		        /* execute */
-  NULL,					/* sub */
-  NULL,					/* next */
-  0,					/* static_pass_number */
-  TV_IPA_LTO_OUT,		        /* tv_id */
-  0,	                                /* properties_required */
-  0,					/* properties_provided */
-  0,					/* properties_destroyed */
-  0,            			/* todo_flags_start */
-  TODO_dump_func                        /* todo_flags_finish */
- }
-};
-
Index: lto-section-out.c
===================================================================
--- lto-section-out.c	(revision 136409)
+++ lto-section-out.c	(working copy)
@@ -52,6 +52,28 @@ along with GCC; see the file COPYING3.  
 #include <ctype.h>
 
 
+/* Add FLAG onto the end of BASE.  */
+ 
+void
+lto_set_flag (unsigned HOST_WIDEST_INT *base, unsigned int flag)
+{
+  *base = *base << 1;
+  if (flag)
+    *base |= 1;
+}
+
+/* Add FLAGS of WIDTH onto the end of BASE.  */
+ 
+void
+lto_set_flags (unsigned HOST_WIDEST_INT *base, unsigned int flag, unsigned int width)
+{
+  unsigned HOST_WIDEST_INT mask = 1 < (((unsigned HOST_WIDEST_INT)width) - 1);
+
+  *base = *base << width;
+  *base |= (flag & mask);
+}
+
+
 /* Returns a hash code for P.  */
 
 hashval_t
@@ -121,6 +143,9 @@ lto_get_section_name (enum lto_section_t
     case LTO_section_cgraph:
       return concat (LTO_SECTION_NAME_PREFIX, ".cgraph", NULL);
 
+    case LTO_section_ipa_pure_const:
+      return concat (LTO_SECTION_NAME_PREFIX, ".pureconst", NULL);
+
     default:
       gcc_unreachable ();
     }
@@ -140,9 +165,9 @@ lto_get_section (enum lto_section_type s
 }
 
 
-/*****************************************************************************/
-/* Output routines shared by all of the serialization passes.                */
-/*****************************************************************************/
+/*****************************************************************************
+   Output routines shared by all of the serialization passes.
+*****************************************************************************/
 
 
 /* Write all of the chars in OBS to the assembler.  Recycle the blocks
@@ -383,12 +408,190 @@ lto_output_decl_index (struct lto_output
 }
 
 
-/*****************************************************************************/
-/*  This part is used to store all of the global decls and types that are    */
-/*  serialized out in this file so that a table for this file can be built   */
-/*  that allows the decls and types to be reconnected to the code or the     */
-/*  ipa summary information.                                                 */ 
-/*****************************************************************************/
+/* Output a field DECL to OBS.  */
+
+void
+lto_output_field_decl_index (struct lto_out_decl_state *decl_state,
+			     struct lto_output_stream * obs, tree decl)
+{
+  unsigned int index;
+  bool new = lto_output_decl_index (obs, 
+				    decl_state->field_decl_hash_table,
+				    &decl_state->next_field_decl_index, 
+				    decl, &index);
+  if (new)
+    VEC_safe_push (tree, heap, decl_state->field_decls, decl);
+}
+
+
+/* Output a function DECL to OBS.  */
+
+void
+lto_output_fn_decl_index (struct lto_out_decl_state *decl_state, 
+			  struct lto_output_stream * obs, tree decl)
+{
+  unsigned int index;
+  bool new = lto_output_decl_index (obs, 
+				    decl_state->fn_decl_hash_table,
+				    &decl_state->next_fn_decl_index, 
+				    decl, &index);
+  if (new)
+    VEC_safe_push (tree, heap, decl_state->fn_decls, decl);
+}
+
+
+/* Output a namespace DECL to OBS.  */
+
+void
+lto_output_namespace_decl_index (struct lto_out_decl_state *decl_state,
+				 struct lto_output_stream * obs, tree decl)
+{
+  unsigned int index;
+  bool new = lto_output_decl_index (obs,
+				    decl_state->namespace_decl_hash_table,
+				    &decl_state->next_namespace_decl_index,
+				    decl, &index);
+  if (new)
+    VEC_safe_push (tree, heap, decl_state->namespace_decls, decl);
+}
+
+
+/* Output a static or extern var DECL to OBS.  */
+
+void
+lto_output_var_decl_index (struct lto_out_decl_state *decl_state,
+			   struct lto_output_stream * obs, tree decl)
+{
+  unsigned int index;
+  bool new = lto_output_decl_index (obs, 
+				    decl_state->var_decl_hash_table,
+				    &decl_state->next_var_decl_index, 
+				    decl, &index);
+  if (new)
+    VEC_safe_push (tree, heap, decl_state->var_decls, decl);
+}
+
+
+/* Output a type DECL to OBS.  */
+
+void
+lto_output_type_decl_index (struct lto_out_decl_state *decl_state,
+			    struct lto_output_stream * obs, tree decl)
+{
+  unsigned int index;
+  bool new = lto_output_decl_index (obs, 
+				    decl_state->type_decl_hash_table,
+				    &decl_state->next_type_decl_index, 
+				    decl, &index);
+  if (new)
+    VEC_safe_push (tree, heap, decl_state->type_decls, decl);
+}
+
+
+/* Output a type REF to OBS.  */
+
+void
+lto_output_type_ref_index (struct lto_out_decl_state *decl_state,
+			   struct lto_output_stream *obs, tree ref)
+{
+  unsigned int index;
+  bool new = lto_output_decl_index (obs, 
+				    decl_state->type_hash_table,
+				    &decl_state->next_type_index, 
+				    ref, &index);
+  
+  if (new)
+    VEC_safe_push (tree, heap, decl_state->types, ref);
+}
+
+
+/*****************************************************************************
+  Convenience routines used by the ipa passes to serialize their information.
+*****************************************************************************/
+
+/* Create the output block and return it.  */
+
+struct lto_simple_output_block *
+lto_create_simple_output_block (enum lto_section_type section_type)
+{
+  struct lto_simple_output_block *ob 
+    = xcalloc (1, sizeof (struct lto_simple_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));
+
+#ifdef LTO_STREAM_DEBUGGING
+  lto_debug_context.out = lto_debug_out_fun;
+  lto_debug_context.indent = 0;
+#endif
+
+  LTO_SET_DEBUGGING_STREAM (debug_main_stream, main_data);
+
+  /* FIXME MADDOX DELETE THE NEXT LINE.  */
+  dwarf2_called_from_lto_p = true;
+
+  return ob;
+}
+
+
+/* Produce the section that holds the cgraph.  */
+
+void
+lto_destroy_simple_output_block (struct lto_simple_output_block *ob)
+{
+  struct lto_simple_header header;
+  section *saved_section = in_section;
+  section *section = lto_get_section (ob->section_type, NULL);
+
+  memset (&header, 0, sizeof (struct lto_simple_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_simple_header));
+
+  lto_write_stream (ob->main_stream);
+#ifdef LTO_STREAM_DEBUGGING
+  lto_write_stream (ob->debug_main_stream);
+#endif
+
+  /* Put back the assembly section that was there before we started
+     writing lto info.  */
+  if (saved_section)
+    switch_to_section (saved_section);
+
+  /* FIXME MADDOX DELETE THE NEXT LINE.  */
+  dwarf2_called_from_lto_p = false;
+
+  free (ob->main_stream);
+  LTO_CLEAR_DEBUGGING_STREAM (debug_main_stream);
+  free (ob);
+}
+
+
+/*****************************************************************************
+  This part is used to store all of the global decls and types that
+  are serialized out in this file so that a table for this file can be
+  built that allows the decls and types to be reconnected to the code
+  or the ipa summary information.
+*****************************************************************************/
 static struct lto_out_decl_state *out_state;
 
 struct lto_out_decl_state *
@@ -437,12 +640,14 @@ write_references (VEC(tree,heap) *v, sec
     }
 }
 
+
 /* This pass is run after all of the functions are serialized and all
    of the ipa passes have written their serialized forms.  This pass
    cases the vector of all of the global decls and types used from
    this file to be written in to a section that can then be read in to
    recover these on other side.  */
-static unsigned int
+
+static void
 produce_asm_for_decls (void)
 {
   struct lto_decl_header header;
@@ -499,10 +704,6 @@ produce_asm_for_decls (void)
   VEC_free (tree, heap, out_state->type_decls);
   VEC_free (tree, heap, out_state->namespace_decls);
   VEC_free (tree, heap, out_state->types);
-
-  free (out_state);
-
-  return 0;
 }
 
 
@@ -516,13 +717,13 @@ gate_lto_out (void)
 }
 
 
-struct simple_ipa_opt_pass pass_ipa_lto_finish_out =
+struct ipa_opt_pass pass_ipa_lto_finish_out =
 {
  {
-  SIMPLE_IPA_PASS,
+  IPA_PASS,
   "lto_decls_out",	                /* name */
   gate_lto_out,			        /* gate */
-  produce_asm_for_decls,        	/* execute */
+  NULL,        	                        /* execute */
   NULL,					/* sub */
   NULL,					/* next */
   0,					/* static_pass_number */
@@ -532,7 +733,14 @@ struct simple_ipa_opt_pass pass_ipa_lto_
   0,					/* properties_destroyed */
   0,            			/* todo_flags_start */
   0                                     /* todo_flags_finish */
- }
+ },
+ NULL,		                        /* generate_summary */
+ produce_asm_for_decls,			/* write_summary */
+ NULL,		         		/* read_summary */
+ NULL,					/* function_read_summary */
+ 0,					/* TODOs */
+ NULL,			                /* function_transform */
+ NULL					/* variable_transform */
 };
 
 
Index: lto-section-out.h
===================================================================
--- lto-section-out.h	(revision 136409)
+++ lto-section-out.h	(working copy)
@@ -115,12 +115,31 @@ struct lto_out_decl_state
   VEC(tree,heap) *types;
 };
 
+
+/* A simple output block.  This can be used for simple ipa passes that
+   do not need more than one stream.  */
+struct lto_simple_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
+};
+
+
+void lto_set_flag (unsigned HOST_WIDEST_INT *, unsigned int);
+void lto_set_flags (unsigned HOST_WIDEST_INT *, unsigned int, unsigned int);
 hashval_t lto_hash_decl_slot_node (const void *);
 int lto_eq_decl_slot_node (const void *, const void *);
 hashval_t lto_hash_type_slot_node (const void *);
 int lto_eq_type_slot_node (const void *, const void *);
 
-struct lto_out_decl_state *lto_get_out_decl_state (void);
 void lto_write_stream (struct lto_output_stream *);
 void lto_output_1_stream (struct lto_output_stream *, char);
 void lto_output_uleb128_stream (struct lto_output_stream *, unsigned HOST_WIDE_INT);
@@ -128,6 +147,25 @@ void lto_output_widest_uint_uleb128_stre
 					    unsigned HOST_WIDEST_INT);
 void lto_output_sleb128_stream (struct lto_output_stream *, HOST_WIDE_INT);
 void lto_output_integer_stream (struct lto_output_stream *, tree);
-bool lto_output_decl_index (struct lto_output_stream *, htab_t, unsigned int *, tree, unsigned int *);
+bool lto_output_decl_index (struct lto_output_stream *, htab_t, 
+			    unsigned int *, tree, unsigned int *);
+void lto_output_field_decl_index (struct lto_out_decl_state *,
+				  struct lto_output_stream *, tree);
+void lto_output_fn_decl_index (struct lto_out_decl_state *,
+			       struct lto_output_stream *, tree);
+void lto_output_namespace_decl_index (struct lto_out_decl_state *,
+				      struct lto_output_stream *, tree);
+void lto_output_var_decl_index (struct lto_out_decl_state *,
+				struct lto_output_stream *, tree);
+void lto_output_type_decl_index (struct lto_out_decl_state *,
+				 struct lto_output_stream *, tree);
+void lto_output_type_ref_index (struct lto_out_decl_state *,
+				struct lto_output_stream *, tree);
+
+struct lto_simple_output_block *lto_create_simple_output_block (enum lto_section_type);
+void lto_destroy_simple_output_block (struct lto_simple_output_block * ob);
+
+struct lto_out_decl_state *lto_get_out_decl_state (void);
+
 bool gate_lto_out (void);
 #endif  /* GCC_LTO_SECTION_OUT_H  */

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