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: lto reading code.


The vast majority of this patch is code to support the reading of the
encoded gimple from the .o file and the debugging of that stream.  In
doing the debugging for this code, many bugs were found in the encoding
of that stream and these were fixed.

We are now able to serialize and deserialize the following function:

extern int foo (int a, int b, int c);
int foo (int a, int b, int c)
{

  b = 0;
  c = 1;
  if (a)
    b = 6 + a;
  else
    c += 1;

  b = 6 * c;
  return b;
}
However, there is still much glue code to be written and tested before
this can be passed properly thru the rest of the compiler.

The stream debugging is described at the top of lto-tags.h.

There are several other issues with this patch:

1) There is no warranty that this code works beyond reading and writing
of the example above.  This is simply an update to allow Mark and Sandra
to move forward with some of their testing. 

2) The "-flto" has been added and is now used in some of the places
where it is necessary.

3) The flag police may want to comment on the fragment in opts.c.  I did
not know where to do this properly. 

4) We may want to consider the changes in tree-pretty-print.c and
print-tree.c for the mainline.  These issues are bugs there. 

5) Some of this patch contains code that Sandra sent me.  That is why
she is listed on this patch.  She may have some issues with some of this. 

6) This code dumps the set of types used in the lto writing and the lto
reading to stderr.  This is to aid mark and sandra to look at the some
places where the types are not matching properly.  That code will go
away later.

I have been testing this code with the following command lines:
../xgcc -B.. -flto -O2 -g small1.c
../xgcc -x lto -B.. -O2 -g small1.o

Kenny

2006-10-09  Kenneth Zadeck <zadeck@naturalbridge.com>
        Sandra Loosemore  <sandra@codesourcery.com>
    * gcc/tree-pretty-print.c: Fixed comment rot.
    * gcc/lto-function-out.c (lto_flags_needed_for): New global.
    (decl_slot): Changed slot_num to signed.
    (output_block.named_label_stream,
    output_block.debug_decl_stream,
    output_block.debug_label_stream,
    output_block.debug_main_stream): New fields.
    (output_zero, output_sleb128_stream, output_string, output_real,
    output_integer, output_tree_flags, output_type_ref,
    output_record_start, output_expr_operand, output_local_vars,
    output_bb, output_function):
    Reordered output to accomodate new stream debugging.
    (output_uleb128_stream): Fixed sign bug and added stream
    debugging.
    (output_decl_index): Fixed precedence problem.
    (output_label_ref, output_named_labels, debug_out_fun): New function.
    (output_eh_must_not_throw, output_bb): Disabled serialization
    of eh regions.
    (output_constructor): Updated protocol to add missing fields.
    (output_expr_operand): Added NULL SET_NAME macro.
    (produce_asm, output_function): Added many more fields to the
    lto header.
    (produce_asm): Added dumping of types used.
    (lto_static_init): Added initialization of
    lto_flags_needed_for and LTO_tag_names.
    Changed initialization for lto_types_needed_for.
    (lto_output): Added checking of flag_generate_lto.
    (pass_ipa_lto_out): Fixed copy rot.
    * gcc/cfg.c (init_flow): Added the_fun parameter and generalized.
    * gcc/dwarf2out.c (dw_die_ref lto_void_type_die): New variable.
    (AT_string_form): Now checks flag_generate_lto to keep from using
    string table.
    (dwarf2out_init): Initialized lto_void_type_die.
    (lto_init_ref): Initialized ref->base_label to the proper
    value and made integers and void types work.
    * gcc/opts.c (common_handle_option): Set debug level when -flto is set.
    * gcc/lto-tree-tags.def (MAP_EXPR_TAGS, SET_NAME): New macros.
    (MODIFY_EXPR, VAR_DECL, WITH_SIZE_EXPR): Changed encoding.
    * gcc/lto-tags.h: Changed version number.  Renumbered many LTO_* tags.
    (num_local_decls, num_named_labels, num_unnamed_labels,
    debug_decl_size, debug_label_size, debug_main_size): New fields of
    lto_function_header.
    (LTO_SECTION_NAME_PREFIX): Changed.
    (LTO_STREAM_DEBUGGING, LTO_DEBUG_INDENT,
    LTO_DEBUG_INDENT_TOKEN(value), LTO_DEBUG_INTEGER,
    LTO_DEBUG_STRING, LTO_DEBUG_TOKEN, LTO_DEBUG_UNDENT,
    LTO_DEBUG_WIDE): New macros for stream debugging.
    (lto_debug_context): New structure.
    (lto_debug_indent, lto_debug_indent_token,
    lto_debug_integer, lto_debug_string,
    lto_debug_token, lto_debug_undent, lto_debug_wide): New stream
    debugging functions.
    * gcc/lto/lto.c (lto_read_form): Added DF_FORM_strp case.
    (lto_read_unspecified_type_DIE): New function.
    (lto_read_DIE): Added lto_read_unspecified_type_DIE to table.
    (lto_resolve_type_ref): Properly initialized new_context.
    * gcc/lto/lto-read.c (tag_to_expr, input_block): New structure.
    (num_flags_for_code): New array.
    (types, local_decls, labels, strings, strings_len,
    int num_named_labels): New fields to fun_in.
    (input_expr_operand, input_1_unsigned, input_uleb128,
    input_sleb128, input_string_internal, input_string,
    input_real, input_integer, input_record_start, input_list,
    init_cfg, finalize_cfg, get_label_decl, get_type_ref,
    process_flags, input_expr_operand, input_labels, input_local_vars,
    input_eh_regions, make_new_block, input_bb, input_function,
    lto_static_init_local, dump_debug_stream, debug_out_fun):
    New function.
    (input_globals): Renamed from load globals.
    (lto_read_function_body): Rewritten.
    * gcc/print_tree.c (print_node): Fixed rot that keeps this from
    being called externally.
    * common.opt (flto): New flag.
    * gcc/lto-stream-debug.c: New file.
    * gcc/Makefile.in (lto-stream-debug): New clause.
    * gcc/basic-block.h (profile_status_for_function,
    SET_BASIC_BLOCK_FOR_FUNCTION): New macros.
    * gcc/tree-cfg.c (init_empty_tree_cfg): Added cfun parameter
    to init_flow call.



Index: tree-pretty-print.c
===================================================================
--- tree-pretty-print.c	(revision 117575)
+++ tree-pretty-print.c	(working copy)
@@ -120,7 +120,7 @@ print_generic_decl (FILE *file, tree dec
 }
 
 /* Print tree T, and its successors, on file FILE.  FLAGS specifies details
-   to show in the dump.  See TDF_* in tree.h.  */
+   to show in the dump.  See TDF_* in tree-pass.h.  */
 
 void
 print_generic_stmt (FILE *file, tree t, int flags)
@@ -131,7 +131,7 @@ print_generic_stmt (FILE *file, tree t, 
 }
 
 /* Print tree T, and its successors, on file FILE.  FLAGS specifies details
-   to show in the dump.  See TDF_* in tree.h.  The output is indented by
+   to show in the dump.  See TDF_* in tree-pass.h.  The output is indented by
    INDENT spaces.  */
 
 void
@@ -148,7 +148,7 @@ print_generic_stmt_indented (FILE *file,
 }
 
 /* Print a single expression T on file FILE.  FLAGS specifies details to show
-   in the dump.  See TDF_* in tree.h.  */
+   in the dump.  See TDF_* in tree-pass.h.  */
 
 void
 print_generic_expr (FILE *file, tree t, int flags)
@@ -402,10 +402,10 @@ dump_omp_clauses (pretty_printer *buffer
 }
 
 
-/* Dump the node NODE on the pretty_printer BUFFER, SPC spaces of indent.
-   FLAGS specifies details to show in the dump (see TDF_* in tree.h).  If
-   IS_STMT is true, the object printed is considered to be a statement
-   and it is terminated by ';' if appropriate.  */
+/* Dump the node NODE on the pretty_printer BUFFER, SPC spaces of
+   indent.  FLAGS specifies details to show in the dump (see TDF_* in
+   tree-pass.h).  If IS_STMT is true, the object printed is considered
+   to be a statement and it is terminated by ';' if appropriate.  */
 
 int
 dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
Index: lto-function-out.c
===================================================================
--- lto-function-out.c	(revision 117575)
+++ lto-function-out.c	(working copy)
@@ -53,8 +53,18 @@ Boston, MA 02110-1301, USA.  */
 #include "lto-tags.h"
 #include <ctype.h>
 
+
+sbitmap lto_flags_needed_for;
 sbitmap lto_types_needed_for;
 
+#ifdef LTO_STREAM_DEBUGGING
+const char *LTO_tag_names[LTO_last_tag];
+
+static struct lto_debug_context lto_debug_context;
+static void debug_out_fun (struct lto_debug_context *, char);
+#endif
+
+
 /* The index of the last eh_region seen for an instruction.  The
    eh_region for an instruction is only emitted if it different from
    the last instruction.  */
@@ -64,10 +74,9 @@ static unsigned int expr_to_tag[NUM_TREE
 
 struct decl_slot {
   tree t;
-  unsigned int slot_num;
+  int slot_num;
 };
 
-
 /* Returns a hash code for P.  */
 
 static hashval_t
@@ -203,13 +212,25 @@ struct output_block
   struct output_stream *main_stream;
   /* The stream that contains the local name table.  */
   struct output_stream *local_decl_stream;
+  /* The stream that contains the names for the named_labels.  */
+  struct output_stream *named_label_stream;
   /* The stream that contains the string table.  */
   struct output_stream *string_stream;
+#ifdef LTO_STREAM_DEBUGGING
+  /* The stream that contains the stream debugging information.  */
+  struct output_stream *debug_decl_stream;
+  /* The stream that contains the stream debugging information.  */
+  struct output_stream *debug_label_stream;
+  /* The stream that contains the stream debugging information.  */
+  struct output_stream *debug_main_stream;
+#endif
 
   /* The hash table that contains the set of labels we have seen so
      far and the indexes assigned to them.  */
   htab_t label_hash_table;
-  unsigned int next_label_index;
+  int next_named_label_index;
+  int next_unnamed_label_index;
+  VEC(tree,heap) *named_labels;
 
   /* The hash table that contains the set of local parm and var decls
      we have seen so far and the indexes assigned to them.  */
@@ -253,6 +274,7 @@ struct output_block
   int last_line;
 };
 
+
 /* The output stream that contains the abbrev table for all of the
    functions in this compilation unit.  */
 static void output_expr_operand (struct output_block *, tree);
@@ -345,6 +367,7 @@ output_1_stream (struct output_stream *o
 static void
 output_zero (struct output_block *ob)
 {
+  LTO_DEBUG_WIDE ("U", 0)
   output_1_stream (ob->main_stream, 0);
 }
 
@@ -354,21 +377,19 @@ output_zero (struct output_block *ob)
 static void
 output_uleb128_stream (struct output_stream *obs, unsigned HOST_WIDE_INT work)
 {
-  int bytes = HOST_BITS_PER_WIDE_INT / 8;
-  int count = 0;
+  LTO_DEBUG_WIDE ("U", work)
   do
     {
-      int byte = (work & 0x7f);
+      unsigned int byte = (work & 0x7f);
       work >>= 7;
       if (work != 0)
 	/* More bytes to follow.  */
 	byte |= 0x80;
 
       output_1_stream (obs, byte);
-      gcc_assert (count <= bytes + 1);
-      count++;
     }
   while (work != 0);
+
 }
 
 
@@ -387,6 +408,7 @@ static void
 output_sleb128_stream (struct output_stream *obs, HOST_WIDE_INT work)
 {
   int more, byte;
+  LTO_DEBUG_WIDE ("S", work)
   do
     {
       byte = (work & 0x7f);
@@ -412,11 +434,13 @@ output_sleb128 (struct output_block *ob,
 }
 
 
-/* Output STRING of LEN to the string table in OB and return the
-   offset in the table.  */
+/* Output STRING of LEN to the string table in OB.  Then put the index 
+   onto the INDEX_STREAM.  */
 
-static unsigned int
-output_string (struct output_block *ob, const char *string,
+static void
+output_string (struct output_block *ob, 
+	       struct output_stream *index_stream,
+	       const char *string,
 	       unsigned int len)
 {
   void **slot;
@@ -435,16 +459,25 @@ output_string (struct output_block *ob, 
       new_slot->s = string;
       new_slot->slot_num = start;
       *slot = new_slot;
+      output_uleb128_stream (index_stream, start);
       output_uleb128_stream (string_stream, len);
       for (i=0; i<len; i++)
 	output_1_stream (string_stream, string[i]);
-      return start;
+
     }
   else
     {
       struct decl_slot *old_slot = (struct decl_slot *)*slot;
-      return old_slot->slot_num;
+      output_uleb128_stream (index_stream, old_slot->slot_num);
+
+      /* From the debugging protocol's point of view, the entry needs
+	 to look the same reguardless of whether this is the first
+	 occurence of this string or not.  Thus, we simulate the same
+	 debugging info as would be output as if this was a new
+	 string.  */
+      LTO_DEBUG_WIDE ("U", old_slot->slot_num)
     }
+  LTO_DEBUG_STRING (string, len)
 }
 
 
@@ -455,11 +488,10 @@ output_real (struct output_block *ob, tr
 {
   static char real_buffer[1000];
   const REAL_VALUE_TYPE *r = &TREE_REAL_CST (t);
-  unsigned int index;
 
+  LTO_DEBUG_TOKEN ("real")
   real_to_hexadecimal (real_buffer, r, 1000, 0, 1);
-  index = output_string (ob, real_buffer, strlen (real_buffer));
-  output_uleb128 (ob, index);
+  output_string (ob, ob->main_stream, real_buffer, strlen (real_buffer));
 }
 
 
@@ -485,6 +517,8 @@ output_integer (struct output_block *ob,
       return;
     }
 
+  LTO_DEBUG_INTEGER ("SS", high, low)
+
   /* This is just a copy of the output_sleb128 code with extra
      operations to transfer the low 7 bits of the high value to the
      top 7 bits of the low value, shift the high down by 7 and then do
@@ -528,7 +562,7 @@ output_decl_index (struct output_stream 
   if (*slot == NULL)
     {
       struct decl_slot *new_slot = xmalloc (sizeof (struct decl_slot));
-      int index = *next_index++;
+      int index = (*next_index)++;
 
       new_slot->t = name;
       new_slot->slot_num = index;
@@ -554,8 +588,11 @@ static void
 output_tree_flags (struct output_block *ob, tree expr)
 {
   int flags = 0;
-  int file_to_write = -1;
+  const char *file_to_write = NULL;
   int line_to_write = -1;
+  const char *current_file;
+
+  LTO_DEBUG_TOKEN ("flags")
 
 #define START_CLASS_SWITCH()              \
   {                                       \
@@ -586,7 +623,6 @@ output_tree_flags (struct output_block *
     }                                     \
   }
 
-
 #include "lto-tree-flags.def"
 
 #undef START_CLASS_SWITCH
@@ -610,12 +646,11 @@ output_tree_flags (struct output_block *
       if (EXPR_HAS_LOCATION (expr))
 	{
 	  LOC current_loc = EXPR_LOC (expr);
-	  const char *current_file = LOC_FILE (current_loc);
 	  const int current_line = LOC_LINE (current_loc);
+	  current_file = LOC_FILE (current_loc);
 	  if (ob->last_file != current_file)
 	    {
-	      file_to_write
-		= output_string (ob, current_file, strlen (current_file));
+	      file_to_write = current_file;
 	      ob->last_file = current_file;
 	      flags |= 0x2;
 	    }
@@ -623,16 +658,23 @@ output_tree_flags (struct output_block *
 	    {
 	      line_to_write = current_line;
 	      ob->last_line = current_line;
-	      flags <<= 1;
 	      flags |= 0x1;
 	    }
 	}
     }
+
   output_uleb128 (ob, flags);
-  if (file_to_write != -1)
-    output_uleb128 (ob, file_to_write);
+  if (file_to_write)
+    {
+      LTO_DEBUG_TOKEN ("file")
+      output_string (ob, ob->main_stream, 
+		     file_to_write, strlen (file_to_write));
+    }
   if (line_to_write != -1)
-    output_uleb128 (ob, line_to_write);
+    {
+      LTO_DEBUG_TOKEN ("line")
+      output_uleb128 (ob, line_to_write);
+    }
 }
 
 
@@ -643,8 +685,12 @@ output_tree_flags (struct output_block *
 static void
 output_type_ref (struct output_block *ob, tree node)
 {
-  bool new = output_decl_index (ob->main_stream, ob->type_hash_table,
-				&ob->next_type_index, node);
+  bool new;
+
+  LTO_DEBUG_TOKEN ("type")
+  new = output_decl_index (ob->main_stream, ob->type_hash_table,
+			   &ob->next_type_index, node);
+
   if (new)
     VEC_safe_push (tree, heap, ob->types, node);
 }
@@ -670,8 +716,33 @@ output_local_decl_ref (struct output_blo
 static void
 output_label_ref (struct output_block *ob, tree label)
 {
-  output_decl_index (ob->main_stream, ob->label_hash_table,
-		     &ob->next_label_index, label);
+  void **slot;
+  struct decl_slot d_slot;
+  d_slot.t = label;
+
+  slot = htab_find_slot (ob->label_hash_table, &d_slot, INSERT);
+  if (*slot == NULL)
+    {
+      struct decl_slot *new_slot = xmalloc (sizeof (struct decl_slot));
+
+      /* Named labels are given positive integers and unnamed labels are 
+	 given negative indexes.  */
+      bool named = (DECL_NAME (label) != NULL_TREE);
+      int index = named
+	? ob->next_named_label_index++ : ob->next_unnamed_label_index--;
+
+      new_slot->t = label;
+      new_slot->slot_num = index;
+      *slot = new_slot;
+      output_sleb128 (ob, index);
+      if (named)
+	VEC_safe_push (tree, heap, ob->named_labels, label);
+    }
+  else
+    {
+      struct decl_slot *old_slot = (struct decl_slot *)*slot;
+      output_sleb128 (ob, old_slot->slot_num);
+    }
 }
 
 
@@ -682,7 +753,8 @@ static void
 output_record_start (struct output_block *ob, tree expr,
 		     tree value, unsigned int tag)
 {
-  output_uleb128 (ob, tag);
+  output_1_stream (ob->main_stream, tag);
+  LTO_DEBUG_INDENT (tag)
   if (expr)
     {
       enum tree_code code = TREE_CODE (expr);
@@ -860,7 +932,7 @@ output_eh_must_not_throw (void *obv,
 static void
 output_eh_regions (struct output_block *ob, struct function *cfun)
 {
-  if (cfun->eh)
+  if (0 && cfun->eh)
     {
       output_record_start (ob, NULL, NULL, LTO_eh_table);
       output_eh_records (ob, cfun,
@@ -869,8 +941,10 @@ output_eh_regions (struct output_block *
 			 output_eh_catch,
 			 output_eh_allowed,
 			 output_eh_must_not_throw);
-      output_zero (ob);
     }
+  /* The 0 either terminates the record or indicates that there are no
+     eh_records at all.  */
+  output_zero (ob);
 }
 
 
@@ -883,21 +957,27 @@ output_constructor (struct output_block 
   tree purpose;
   unsigned HOST_WIDE_INT idx;
 
-  output_record_start (ob, ctor, NULL, LTO_constructor);
+  output_record_start (ob, ctor, ctor, LTO_constructor);
+  output_uleb128 (ob, VEC_length (constructor_elt, CONSTRUCTOR_ELTS (ctor)));
 
   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, purpose, value)
     {
       if (TREE_CODE (purpose) == RANGE_EXPR)
 	{
 	  output_record_start (ob, NULL, NULL, LTO_constructor_range);
+	  /* Need the types here to reconstruct the ranges.  */
+	  output_type_ref (ob, TREE_OPERAND (purpose, 0));
 	  output_integer (ob, TREE_OPERAND (purpose, 0));
+	  output_type_ref (ob, TREE_OPERAND (purpose, 1));
 	  output_integer (ob, TREE_OPERAND (purpose, 1));
+	  LTO_DEBUG_UNDENT ()
 	}
 
       switch (TREE_CODE (value))
 	{
 	case CONSTRUCTOR:
 	  output_constructor (ob, value);
+	  LTO_DEBUG_UNDENT ()
 	  break;
 	case INTEGER_CST:
 	case REAL_CST:
@@ -912,7 +992,6 @@ output_constructor (struct output_block 
 	  break;
 	}
     }
-  output_zero (ob);
 }
 
 /* Output EXPR to the main stream in OB.  */
@@ -963,11 +1042,10 @@ output_expr_operand (struct output_block
 
     case STRING_CST:
       {
-	unsigned int index;
 	output_record_start (ob, expr, expr, LTO_string_cst);
-	index = output_string (ob, TREE_STRING_POINTER (expr),
-			       TREE_STRING_LENGTH (expr));
-	output_uleb128 (ob, index);
+	output_string (ob, ob->main_stream, 
+		       TREE_STRING_POINTER (expr),
+		       TREE_STRING_LENGTH (expr));
       }
       break;
 
@@ -1042,8 +1120,8 @@ output_expr_operand (struct output_block
 	bool new;
 	output_record_start (ob, NULL, NULL, tag);
 	
-	output_decl_index (ob->main_stream, ob->field_decl_hash_table,
-			   &ob->next_field_decl_index, expr);
+	new = output_decl_index (ob->main_stream, ob->field_decl_hash_table,
+				 &ob->next_field_decl_index, expr);
 	if (new)
 	  VEC_safe_push (tree, heap, ob->field_decls, expr);
       }
@@ -1054,8 +1132,8 @@ output_expr_operand (struct output_block
 	bool new;
 	output_record_start (ob, NULL, NULL, tag);
 	
-	output_decl_index (ob->main_stream, ob->fn_decl_hash_table,
-			   &ob->next_fn_decl_index, expr);
+	new = output_decl_index (ob->main_stream, ob->fn_decl_hash_table,
+				 &ob->next_fn_decl_index, expr);
 	if (new)
 	  VEC_safe_push (tree, heap, ob->fn_decls, expr);
       }
@@ -1065,22 +1143,22 @@ output_expr_operand (struct output_block
       if (TREE_STATIC (expr) || DECL_EXTERNAL (expr))
 	{
 	  bool new;
-	  output_record_start (ob, NULL, NULL, tag);
+	  output_record_start (ob, NULL, NULL, LTO_var_decl1);
 
-	  output_decl_index (ob->main_stream, ob->var_decl_hash_table,
-			     &ob->next_var_decl_index, expr);
+	  new = output_decl_index (ob->main_stream, ob->var_decl_hash_table,
+				   &ob->next_var_decl_index, expr);
 	  if (new)
 	    VEC_safe_push (tree, heap, ob->var_decls, expr);
 	}
       else
 	{
-	  output_record_start (ob, NULL, NULL, LTO_local_var_decl);
+	  output_record_start (ob, NULL, NULL, LTO_var_decl0);
 	  output_local_decl_ref (ob, expr);
 	}
       break;
 
     case PARM_DECL:
-      output_record_start (ob, expr, expr, tag);
+      output_record_start (ob, NULL, NULL, tag);
       output_local_decl_ref (ob, expr);
       break;
 
@@ -1100,8 +1178,8 @@ output_expr_operand (struct output_block
 
     case COMPONENT_REF:
       output_record_start (ob, expr, expr, tag);
-      output_expr_operand (ob, TREE_OPERAND (expr, 1));
       output_expr_operand (ob, TREE_OPERAND (expr, 0));
+      output_expr_operand (ob, TREE_OPERAND (expr, 1));
       /* Ignore 3 because it can be recomputed.  */
       break;
 
@@ -1109,21 +1187,20 @@ output_expr_operand (struct output_block
       {
 	unsigned int count = TREE_INT_CST_LOW (TREE_OPERAND (expr, 0));
 	unsigned int i;
+	output_uleb128 (ob, count);
 
 	/* Operand 2 is the call chain.  */
 	if (TREE_OPERAND (expr, 2))
-	  output_record_start (ob, expr, expr, LTO_call_expr1);
+	  {
+	    output_record_start (ob, expr, expr, LTO_call_expr1);
+	    output_expr_operand (ob, TREE_OPERAND (expr, 2));
+	  }
 	else
 	  output_record_start (ob, expr, expr, LTO_call_expr0);
 
-	if (TREE_OPERAND (expr, 2))
-	  output_expr_operand (ob, TREE_OPERAND (expr, 2));
-
 	output_expr_operand (ob, TREE_OPERAND (expr, 1));
 	for (i = 3; i < count; i++)
 	  output_expr_operand (ob, TREE_OPERAND (expr, i));
-	output_zero (ob);
-
       }
       break;
 
@@ -1153,15 +1230,8 @@ output_expr_operand (struct output_block
 
     case ARRAY_REF:
     case ARRAY_RANGE_REF:
-      /* Ignore operands 3 and 4 for ARRAY_REF and ARRAY_RANGE REF
+      /* Ignore operands 2 and 3 for ARRAY_REF and ARRAY_RANGE REF
 	 because they can be recomputed.  */
-
-      /* FALLTHROUGH. */
-    case WITH_SIZE_EXPR:
-      /* WITH_SIZE_EXPR is a pass-through reference to its first
-	 argument, and an rvalue reference to its second argument.  */
-
-      /* All of the binary expressions and their friends.  */
       output_record_start (ob, expr, expr, tag);
       output_expr_operand (ob, TREE_OPERAND (expr, 0));
       output_expr_operand (ob, TREE_OPERAND (expr, 1));
@@ -1171,12 +1241,10 @@ output_expr_operand (struct output_block
     case ASM_EXPR:
       {
 	tree string_cst = ASM_STRING (expr);
-	int index;
 	output_record_start (ob, expr, NULL, LTO_asm_expr);
-	index = output_string (ob, TREE_STRING_POINTER (string_cst),
-			       TREE_STRING_LENGTH (string_cst));
-	output_uleb128 (ob, index);
-	output_tree_flags (ob, expr);
+	output_string (ob, ob->main_stream, 
+		       TREE_STRING_POINTER (string_cst),
+		       TREE_STRING_LENGTH (string_cst));
 
 	/* Each of the operand sets is a list of trees terminated by a
 	   zero.  The problem is that the operands are not all
@@ -1190,6 +1258,7 @@ output_expr_operand (struct output_block
 	    for (tl = ASM_INPUTS (expr); tl; tl = TREE_CHAIN (tl))
 	      output_expr_operand (ob, TREE_VALUE (tl));
 	    output_zero (ob);
+	    LTO_DEBUG_UNDENT ()
 	  }
 	if (ASM_OUTPUTS (expr) != NULL_TREE)
 	  {
@@ -1199,6 +1268,7 @@ output_expr_operand (struct output_block
 	    for (tl = ASM_OUTPUTS (expr); tl; tl = TREE_CHAIN (tl))
 	      output_expr_operand (ob, TREE_VALUE (tl));
 	    output_zero (ob);
+	    LTO_DEBUG_UNDENT ()
 	  }
 	if (ASM_CLOBBERS (expr) != NULL_TREE)
 	  {
@@ -1208,16 +1278,11 @@ output_expr_operand (struct output_block
 	    for (tl = ASM_CLOBBERS (expr); tl; tl = TREE_CHAIN (tl))
 	      output_expr_operand (ob, TREE_VALUE (tl));
 	    output_zero (ob);
+	    LTO_DEBUG_UNDENT ()
 	  }
       }
       break;
 
-    case MODIFY_EXPR:
-      output_record_start (ob, expr, NULL, tag);
-      output_expr_operand (ob, TREE_OPERAND (expr, 0));
-      output_expr_operand (ob, TREE_OPERAND (expr, 1));
-      break;
-
     case RESX_EXPR:
       output_record_start (ob, expr, NULL, tag);
       output_uleb128 (ob, TREE_INT_CST_LOW (TREE_OPERAND (expr, 0)));
@@ -1256,12 +1321,12 @@ output_expr_operand (struct output_block
 	size_t len = TREE_VEC_LENGTH (label_vec);
 	size_t i;
 	output_record_start (ob, expr, NULL, tag);
+	output_uleb128 (ob, len);
 	output_expr_operand (ob, TREE_OPERAND (expr, 0));
 	gcc_assert (TREE_OPERAND (expr, 1) == NULL);
 
 	for (i = 0; i < len; ++i)
 	  output_expr_operand (ob, TREE_VEC_ELT (label_vec, i));
-	output_zero (ob);
       }
       break;
 
@@ -1269,14 +1334,15 @@ output_expr_operand (struct output_block
 	 completely mechanically are done here.  */
       {
 	int i;
+#define SET_NAME(a,b)
 #define MAP_EXPR_TAG(expr, tag) case expr:
 #define TREE_SINGLE_MECHANICAL_TRUE
 
 #include "lto-tree-tags.def"
 #undef MAP_EXPR_TAG
 #undef TREE_SINGLE_MECHANICAL_TRUE
+#undef SET_NAME
 	output_record_start (ob, expr, expr, tag);
-	output_tree_flags (ob, expr);
 	for (i = 0; i< TREE_CODE_LENGTH (TREE_CODE (expr)); i++)
 	  output_expr_operand (ob, TREE_OPERAND (expr, i));
 	break;
@@ -1309,6 +1375,8 @@ output_expr_operand (struct output_block
 	 output.  */
       gcc_unreachable ();
     }
+
+  LTO_DEBUG_UNDENT ()
 }
 
 
@@ -1318,6 +1386,11 @@ static void
 output_local_vars (struct output_block *ob)
 {
   unsigned int index = 0;
+
+#ifdef LTO_STREAM_DEBUGGING
+  lto_debug_context.current_data = ob->debug_decl_stream;
+#endif
+
   while (index < VEC_length (tree, ob->local_decls))
     {
       tree decl = VEC_index (tree, ob->local_decls, index++);
@@ -1345,34 +1418,66 @@ output_local_vars (struct output_block *
       /* Put out the name if there is one.  */
       if (DECL_NAME (decl))
 	{
-	  const char * sname = IDENTIFIER_POINTER (DECL_NAME (decl));
-	  int sindex = output_string (ob, sname, strlen (sname));
-	  output_uleb128 (ob, sindex);
+	  tree name = DECL_NAME (decl);
+	  output_string (ob, ob->main_stream, 
+			 IDENTIFIER_POINTER (name), 
+			 IDENTIFIER_LENGTH (name));
 	}
       else
 	output_uleb128 (ob, 0);
 
+      output_type_ref (ob, TREE_TYPE (decl));
+
       if (!is_var)
 	output_type_ref (ob, DECL_ARG_TYPE (decl));
-
-      output_type_ref (ob, TREE_TYPE (decl));
+      
       output_tree_flags (ob, decl);
+      LTO_DEBUG_TOKEN ("align")
       output_uleb128 (ob, DECL_ALIGN (decl));
 
       /* Put out the subtrees.  */
+      LTO_DEBUG_TOKEN ("size")
       output_expr_operand (ob, DECL_SIZE (decl));
       if (DECL_ATTRIBUTES (decl)!= NULL_TREE)
-	output_tree_list (ob, DECL_ATTRIBUTES (decl),
-			  LTO_attribute_list);
+	{
+	  LTO_DEBUG_TOKEN ("attributes")
+	  output_tree_list (ob, DECL_ATTRIBUTES (decl),
+			    LTO_attribute_list);
+	}
       if (DECL_SIZE_UNIT (decl) != NULL_TREE)
 	output_expr_operand (ob, DECL_SIZE_UNIT (decl));
       if (needs_backing_var)
 	output_expr_operand (ob, DECL_DEBUG_EXPR (decl));
       if (DECL_ABSTRACT_ORIGIN (decl) != NULL_TREE)
 	output_expr_operand (ob, DECL_ABSTRACT_ORIGIN (decl));
+
+      LTO_DEBUG_UNDENT()
     }
 }
 
+
+/* Output the names in the named labels to the named_label stream.  */
+
+static void
+output_named_labels (struct output_block *ob)
+{
+  unsigned int index = 0;
+
+#ifdef LTO_STREAM_DEBUGGING
+  lto_debug_context.current_data = ob->debug_label_stream;
+#endif
+
+  while (index < VEC_length (tree, ob->named_labels))
+    {
+      tree decl = VEC_index (tree, ob->named_labels, index++);
+      tree name = DECL_NAME (decl);
+      output_string (ob, ob->named_label_stream, 
+		     IDENTIFIER_POINTER (name), 
+		     IDENTIFIER_LENGTH (name));
+   }
+}
+
+
 /* Output a basic block BB to the main stream in OB for this CFUN.  */
 
 static void
@@ -1383,20 +1488,24 @@ output_bb (struct output_block *ob, basi
   block_stmt_iterator bsi = bsi_start (bb);
 
   output_record_start (ob, NULL, NULL,
-		       bsi_end_p (bsi) ? LTO_bb1 : LTO_bb0);
+		       bsi_end_p (bsi) ? LTO_bb0 : LTO_bb1);
 
   /* The index of the basic block.  */
+  LTO_DEBUG_TOKEN ("bbindex")
   output_uleb128 (ob, bb->index);
 
   /* Output the successors and the edge flags.  */
+  LTO_DEBUG_TOKEN ("edgecount")
   output_uleb128 (ob, EDGE_COUNT (bb->succs));
   FOR_EACH_EDGE (e, ei, bb->succs)
     {
+      LTO_DEBUG_TOKEN ("dest")
       output_uleb128 (ob, e->dest->index);
+      LTO_DEBUG_TOKEN ("eflags")
       output_uleb128 (ob, e->flags);
     }
 
-  if (bsi_end_p (bsi))
+  if (!bsi_end_p (bsi))
     {
       /* Output the statements.  The list of statements is terminated
 	 with a zero.  */
@@ -1405,12 +1514,13 @@ output_bb (struct output_block *ob, basi
 	{
 	  tree stmt = bsi_stmt (bsi);
 	
+	  LTO_DEBUG_INDENT_TOKEN ("stmt")
 	  output_expr_operand (ob, stmt);
 	
 	  /* We only need to set the region number of the tree that
 	     could throw if the region number is different from the
 	     last region number we set.  */
-	  if (tree_could_throw_p (stmt))
+	  if (0 && tree_could_throw_p (stmt))
 	    {
 	      int region = lookup_stmt_eh_region_fn (cfun, stmt);
 	      if (region != last_eh_region_seen)
@@ -1425,8 +1535,10 @@ output_bb (struct output_block *ob, basi
 	    }
 	}
 
+      LTO_DEBUG_INDENT_TOKEN ("stmt")
       output_zero (ob);
     }
+  LTO_DEBUG_UNDENT()
 }
 
 
@@ -1455,11 +1567,24 @@ produce_asm (struct output_block *ob, tr
   function_header.num_fn_decls = VEC_length (tree, ob->fn_decls);
   function_header.num_var_decls = VEC_length (tree, ob->var_decls);
   function_header.num_types = VEC_length (tree, ob->types);
+  function_header.num_local_decls = VEC_length (tree, ob->local_decls);
+  function_header.num_named_labels = ob->next_named_label_index;
+  function_header.num_unnamed_labels = -ob->next_unnamed_label_index;
 
   function_header.compressed_size = 0;
+  function_header.named_label_size = ob->named_label_stream->total_size;
   function_header.local_decls_size = ob->local_decl_stream->total_size;
   function_header.main_size = ob->main_stream->total_size;
   function_header.string_size = ob->string_stream->total_size;
+#ifdef LTO_STREAM_DEBUGGING
+  function_header.debug_decl_size = ob->debug_decl_stream->total_size;
+  function_header.debug_label_size = ob->debug_label_stream->total_size;
+  function_header.debug_main_size = ob->debug_main_stream->total_size;
+#else
+  function_header.debug_decl_size = -1;
+  function_header.debug_label_size = -1;
+  function_header.debug_main_size = -1;
+#endif
 
   assemble_string ((const char *)&function_header, 
 		   sizeof (struct lto_function_header));
@@ -1512,13 +1637,13 @@ produce_asm (struct output_block *ob, tr
   /* Write the global type references.  */
   for (index = 0; VEC_iterate(tree, ob->types, index, type); index++)
     {
-#ifdef GIMPLE_SYMBOL_TABLE_WORKS
+      fprintf (stderr, "type %d = ", index);
+      print_generic_expr (stderr, type, TDF_VOPS|TDF_UID);
+      fprintf (stderr, "\n");
+      print_node (stderr, "", type, 0);
+      fprintf (stderr, "\n\n");
+
       lto_type_ref (type, &out_ref);
-#else
-      out_ref.section = 0;
-      out_ref.base_label = "0";
-      out_ref.label = "0";
-#endif
       dw2_asm_output_data (8, out_ref.section, " ");
       dw2_asm_output_delta (8, out_ref.label,
 			    out_ref.base_label, " ");
@@ -1526,9 +1651,15 @@ produce_asm (struct output_block *ob, tr
 
   /* Put all of the gimple and the string table out the asm file as a
      block of text.  */
+  write_stream (ob->named_label_stream);
   write_stream (ob->local_decl_stream);
   write_stream (ob->main_stream);
   write_stream (ob->string_stream);
+#ifdef LTO_STREAM_DEBUGGING
+  write_stream (ob->debug_decl_stream);
+  write_stream (ob->debug_label_stream);
+  write_stream (ob->debug_main_stream);
+#endif
 }
 
 
@@ -1547,31 +1678,50 @@ lto_static_init (void)
 
   initialized = true;
 
+  lto_flags_needed_for = sbitmap_alloc (NUM_TREE_CODES);
+  sbitmap_ones (lto_flags_needed_for);
+  RESET_BIT (lto_flags_needed_for, FIELD_DECL);
+  RESET_BIT (lto_flags_needed_for, FUNCTION_DECL);
+  RESET_BIT (lto_flags_needed_for, VAR_DECL);
+  RESET_BIT (lto_flags_needed_for, PARM_DECL);
+  RESET_BIT (lto_flags_needed_for, FIELD_DECL);
 
   lto_types_needed_for = sbitmap_alloc (NUM_TREE_CODES);
 
 #if REDUNDANT_TYPE_SYSTEM
+  /* These forms never need types.  */
   sbitmap_ones (lto_types_needed_for);
-  RESET_BIT (lto_types_needed_for, CONSTRUCTOR);
+  RESET_BIT (lto_types_needed_for, ASM_EXPR);
   RESET_BIT (lto_types_needed_for, CASE_LABEL_EXPR);
   RESET_BIT (lto_types_needed_for, LABEL_DECL);
   RESET_BIT (lto_types_needed_for, LABEL_EXPR);
   RESET_BIT (lto_types_needed_for, MODIFY_EXPR);
+  RESET_BIT (lto_types_needed_for, PARM_DECL);
   RESET_BIT (lto_types_needed_for, RESULT_DECL);
   RESET_BIT (lto_types_needed_for, RESX_EXPR);
   RESET_BIT (lto_types_needed_for, RETURN_EXPR);
+  RESET_BIT (lto_types_needed_for, STRING_CST);
   RESET_BIT (lto_types_needed_for, SWITCH_EXPR);
+  RESET_BIT (lto_types_needed_for, VAR_DECL);
 #else
+  /* These forms will need types, even when the type system is fixed.  */
   SET_BIT (lto_types_needed_for, COMPLEX_CST);
+  SET_BIT (lto_types_needed_for, CONSTRUCTOR);
+  SET_BIT (lto_types_needed_for, CONVERT_EXPR);
   SET_BIT (lto_types_needed_for, INTEGER_CST);
+  SET_BIT (lto_types_needed_for, NOP_EXPR);
   SET_BIT (lto_types_needed_for, REAL_CST);
-  SET_BIT (lto_types_needed_for, STRING_CST);
   SET_BIT (lto_types_needed_for, VECTOR_CST );
-  SET_BIT (lto_types_needed_for, CONVERT_EXPR);
-  SET_BIT (lto_types_needed_for, NOP_EXPR);
   SET_BIT (lto_types_needed_for, VIEW_CONVERT_EXPR);
 #endif
 
+#ifdef LTO_STREAM_DEBUGGING
+#define LTO_STREAM_DEBUGGING_INIT_NAMES
+#define SET_NAME(index,value) LTO_tag_names[index] = value;
+#include "lto-tree-tags.def"
+#undef SET_NAME
+#undef LTO_STREAM_DEBUGGING_INIT_NAMES
+#endif
 }
 
 
@@ -1589,7 +1739,6 @@ lto_static_init_local (void)
 #define MAP_EXPR_TAG(expr,tag)   expr_to_tag [expr] = tag;
 #define TREE_SINGLE_MECHANICAL_TRUE
 #define TREE_SINGLE_MECHANICAL_FALSE
-
 #include "lto-tree-tags.def"
 
 #undef MAP_EXPR_TAG
@@ -1618,11 +1767,23 @@ output_function (tree function)
   ob->main_stream = xcalloc (1, sizeof (struct output_stream));
   ob->string_stream = xcalloc (1, sizeof (struct output_stream));
   ob->local_decl_stream = xcalloc (1, sizeof (struct output_stream));
+  ob->named_label_stream = xcalloc (1, sizeof (struct output_stream));
+#ifdef LTO_STREAM_DEBUGGING
+  ob->debug_decl_stream = xcalloc (1, sizeof (struct output_stream));
+  ob->debug_label_stream = xcalloc (1, sizeof (struct output_stream));
+  ob->debug_main_stream = xcalloc (1, sizeof (struct output_stream));
+  
+  lto_debug_context.out = &debug_out_fun;
+  lto_debug_context.decl_data = ob->debug_decl_stream;
+  lto_debug_context.label_data = ob->debug_label_stream;
+  lto_debug_context.main_data = ob->debug_main_stream;
+  lto_debug_context.current_data = ob->debug_main_stream;
+  lto_debug_context.indent = 0;
+#endif
+
   ob->last_file = NULL;
   ob->last_line = -1;
 
-  lto_static_init_local ();
-
   /* This file code is just a hack to get the stuff where it can be
      measured.  The real lto will put the info into the assembly
      stream.  */
@@ -1642,7 +1803,10 @@ output_function (tree function)
   ob->type_hash_table
     = htab_create (37, hash_type_slot_node, eq_type_slot_node, free);
 
-  lto_static_init ();
+  /* The unnamed labels must all be negative.  */
+  ob->next_unnamed_label_index = -1;
+  /* Make string 0 be a NULL string.  */
+  output_1_stream (ob->string_stream, 0);
 
   last_eh_region_seen = 0;
 
@@ -1660,6 +1824,7 @@ output_function (tree function)
 
   /* The terminator for this function.  */
   output_zero (ob);
+  LTO_DEBUG_UNDENT()
 
   /* We have found MOST of the local vars by scanning the function.
      There is always the possibility that there may be some lurking on
@@ -1678,6 +1843,9 @@ output_function (tree function)
   output_local_vars (ob);
   ob->main_stream = tmp_stream;
 
+  /* Output the names in the named labels.  */
+  output_named_labels (ob);
+
   /* Create a file to hold the pickled output of this function.  This
      is a temp standin until we start writing sections.  */
   produce_asm (ob, function);
@@ -1692,6 +1860,7 @@ output_function (tree function)
   VEC_free (tree, heap, ob->local_decls);
   VEC_free (tree, heap, ob->field_decls);
   VEC_free (tree, heap, ob->fn_decls);
+  VEC_free (tree, heap, ob->named_labels);
   VEC_free (tree, heap, ob->var_decls);
   VEC_free (tree, heap, ob->types);
   free (ob);
@@ -1706,7 +1875,7 @@ lto_output (void)
   struct cgraph_node *node;
   section *saved_section = in_section;
 
-  mkdir ("/tmp/ltotest", 0777);
+  lto_static_init_local ();
 
   /* Process only the fuctions with bodies and only process the master
      ones of them.  */
@@ -1725,14 +1894,14 @@ lto_output (void)
 static bool
 gate_lto_out (void)
 {
-  return (flag_unit_at_a_time != 0
+  return (flag_generate_lto
 	  /* Don't bother doing anything if the program has errors.  */
 	  && !(errorcount || sorrycount));
 }
 
 struct tree_opt_pass pass_ipa_lto_out =
 {
-  "pure-const",		                /* name */
+  "lto-function-out",	                /* name */
   gate_lto_out,			        /* gate */
   lto_output,		        	/* execute */
   NULL,					/* sub */
@@ -1746,3 +1915,18 @@ struct tree_opt_pass pass_ipa_lto_out =
   0,                                    /* todo_flags_finish */
   0					/* letter */
 };
+
+
+#ifdef LTO_STREAM_DEBUGGING
+
+/* The low level output routine to print a single character to the
+   debugging stream.  */
+
+static void
+debug_out_fun (struct lto_debug_context *context, char c)
+{
+  struct output_stream * stream 
+    = (struct output_stream *)context->current_data;
+  output_1_stream (stream, c);
+}
+#endif
Index: cfg.c
===================================================================
--- cfg.c	(revision 117575)
+++ cfg.c	(working copy)
@@ -79,17 +79,21 @@ static void free_edge (edge);
 /* Called once at initialization time.  */
 
 void
-init_flow (void)
+init_flow (struct function *the_fun)
 {
-  if (!cfun->cfg)
+  if (!the_fun->cfg)
     cfun->cfg = ggc_alloc_cleared (sizeof (struct control_flow_graph));
   n_edges = 0;
-  ENTRY_BLOCK_PTR = ggc_alloc_cleared (sizeof (struct basic_block_def));
-  ENTRY_BLOCK_PTR->index = ENTRY_BLOCK;
-  EXIT_BLOCK_PTR = ggc_alloc_cleared (sizeof (struct basic_block_def));
-  EXIT_BLOCK_PTR->index = EXIT_BLOCK;
-  ENTRY_BLOCK_PTR->next_bb = EXIT_BLOCK_PTR;
-  EXIT_BLOCK_PTR->prev_bb = ENTRY_BLOCK_PTR;
+  ENTRY_BLOCK_PTR_FOR_FUNCTION (the_fun)
+    = ggc_alloc_cleared (sizeof (struct basic_block_def));
+  ENTRY_BLOCK_PTR_FOR_FUNCTION (the_fun)->index = ENTRY_BLOCK;
+  EXIT_BLOCK_PTR_FOR_FUNCTION (the_fun)
+    = ggc_alloc_cleared (sizeof (struct basic_block_def));
+  EXIT_BLOCK_PTR_FOR_FUNCTION (the_fun)->index = EXIT_BLOCK;
+  ENTRY_BLOCK_PTR_FOR_FUNCTION (the_fun)->next_bb 
+    = EXIT_BLOCK_PTR_FOR_FUNCTION (the_fun);
+  EXIT_BLOCK_PTR_FOR_FUNCTION (the_fun)->prev_bb 
+    = ENTRY_BLOCK_PTR_FOR_FUNCTION (the_fun);
 }
 
 /* Helper function for remove_edge and clear_edges.  Frees edge structure
Index: dwarf2out.c
===================================================================
--- dwarf2out.c	(revision 117575)
+++ dwarf2out.c	(working copy)
@@ -3987,6 +3987,12 @@ static GTY(()) int label_num;
    within the current function.  */
 static HOST_WIDE_INT frame_pointer_fb_offset;
 
+/* Cached DIE used to represent the void type for LTO processing.  Normally
+   the void type is represented as the absence of a type attribute, but LTO
+   needs an explicit cookie.  See lto_type_ref.  */
+
+static GTY(()) dw_die_ref lto_void_type_die;
+
 /* Forward declarations for functions defined in this file.  */
 
 static int is_pseudo_reg (rtx);
@@ -5029,13 +5035,17 @@ AT_string_form (dw_attr_ref a)
   struct indirect_string_node *node;
   unsigned int len;
   char label[32];
-
   gcc_assert (a && AT_class (a) == dw_val_class_str);
 
   node = a->dw_attr_val.v.val_str;
   if (node->form)
     return node->form;
 
+  /* FIXME!!! This is a temp hack to not use the string table because
+     the current lto code does not do this yet.  */
+  if (flag_generate_lto)
+    return node->form = DW_FORM_string;
+
   len = strlen (node->str) + 1;
 
   /* If the string is shorter or equal to the size of the reference, it is
@@ -13845,6 +13855,8 @@ dwarf2out_init (const char *filename ATT
       switch_to_section (unlikely_text_section ());
       ASM_OUTPUT_LABEL (asm_out_file, cold_text_section_label);
     }
+
+  lto_void_type_die = NULL;
 }
 
 /* A helper function for dwarf2out_finish called through
@@ -14331,7 +14343,7 @@ lto_init_ref (tree scope ATTRIBUTE_UNUSE
      multiple sections, SCOPE will be used to figure out the section
      and corresponding BASE_LABEL.  */
   ref->section = 0;
-  ref->base_label = ".debug_info";
+  ref->base_label = debug_info_section_label;
   ref->label = NULL;
 }
 
@@ -14344,24 +14356,39 @@ lto_type_ref (tree type, lto_out_ref *re
 
   gcc_assert (TYPE_P (type));
 
-  /* Check to see if we already have a DIE.  */
-  die = lookup_type_die (type);
-  /* Create the DIE, if it does not already exist.  */
-  if (!die)
+  scope = TYPE_CONTEXT (type);
+  if (scope)
     {
-      scope = TYPE_CONTEXT (type);
-      if (scope)
-	{
-	  /* We do not yet support lexically scoped types.  */
-	  sorry ("nested types are not supported by LTO");
-	  scope_die = NULL;
-	}
-      else
-	scope_die = comp_unit_die;
-      gen_type_die (type, scope_die);
-      die = lookup_type_die (type);
+      /* We do not yet support lexically scoped types.  */
+      sorry ("nested types are not supported by LTO");
+      scope_die = NULL;
     }
+  else
+    scope_die = comp_unit_die;
+  
+  /* The void type is normally treated as the absence of a DWARF
+     type attribute when emitting normal debugging information, but for
+     LTO purposes we need to emit an explicit DIE for it.  The DWARF spec
+     suggests using DW_TAG_unspecified_type for this purpose, so that's
+     what we'll do.  */
+  
+  if (TREE_CODE (type) == VOID_TYPE)
+    {
+      if (!lto_void_type_die)
+  	{
+	  lto_void_type_die =
+	    new_die (DW_TAG_unspecified_type, scope_die, type);
+	  add_name_attribute (lto_void_type_die, "void");
+  	}
+      die = lto_void_type_die;
+    }
+  else
+    die = modified_type_die (type,
+ 			     TYPE_READONLY (type),
+ 			     TYPE_VOLATILE (type),
+ 			     scope_die);
   gcc_assert (die);
+  
   /* Make sure the DIE has a label.  */
   assign_symbol_name (die);
   /* Construct the reference.  */
Index: opts.c
===================================================================
--- opts.c	(revision 117575)
+++ opts.c	(working copy)
@@ -955,6 +955,14 @@ common_handle_option (size_t scode, cons
       flag_unroll_loops_set = true;
       break;
 
+    case OPT_flto:
+      /* FIXME: This is most surely the wrong thing to do because it
+	 will depend on the order of the options on the command line.
+	 However, if you specify -flto, you must have dwarf2 debugging
+	 records.  */  
+      set_debug_level (DWARF2_DEBUG, false, "2");
+      break;
+
     case OPT_g:
       set_debug_level (NO_DEBUG, DEFAULT_GDB_EXTENSIONS, arg);
       break;
Index: lto-tree-tags.def
===================================================================
--- lto-tree-tags.def	(revision 117575)
+++ lto-tree-tags.def	(working copy)
@@ -32,28 +32,34 @@
       are in the block controlled by the preprocessor symbol
       TREE_SINGLE_MECHANICAL_TRUE.
 
-   3) The tree code whose portable form cannot be generated from the 
+   3) The tree codes whose portable form cannot be generated from the 
       tables but still have only a single variation.  These tags are
       in the block controlled by TREE_SINGLE_MECHANICAL_FALSE.
 
-   4) The set of tags where there are multiple lto records for a
+   4) The tree codes where there are multiple lto records for a
       single tree form.  These not only cannot be generated
       mechanically but there is a many to one mapping from the lto
-      record type to the tree code.  
-
-	BIT_FIELD_REF
-	CALL_EXPR
-	CASE_LABEL_EXPR
-	COMPLEX_CST
-	RETURN_EXPR
-	VECTOR_CST
-
+      record type to the tree code.  These tags are
+      in the block controlled by TREE_MULTIPLE.
 
    This file is used to generate case labels for the
    TREE_SINGLE_MECHANICAL_TRUE class and the lto record to tree_code
-   (and the reverse mapping) for TREE_SINGLE_MECHANICAL_TRUE and
+   for TREE_MULTIPLE for TREE_SINGLE_MECHANICAL_TRUE and
    TREE_SINGLE_MECHANICAL_FALSE classes.
-*/
+
+   The tree code to lto record mapping can be generated for
+   TREE_SINGLE_MECHANICAL_TRUE and TREE_SINGLE_MECHANICAL_FALSE
+   classes.  */
+
+#ifdef TREE_MULTIPLE
+  MAP_EXPR_TAGS(BIT_FIELD_REF, LTO_bit_field_ref0, 2)
+  MAP_EXPR_TAGS(CALL_EXPR, LTO_call_expr0, 2)
+  MAP_EXPR_TAGS(CASE_LABEL_EXPR, LTO_case_label_expr0, 4)
+  MAP_EXPR_TAGS(COMPLEX_CST, LTO_complex_cst0, 2)
+  MAP_EXPR_TAGS(RETURN_EXPR, LTO_return_expr0, 3)
+  MAP_EXPR_TAGS(VAR_DECL, LTO_var_decl0, 2)
+  MAP_EXPR_TAGS(VECTOR_CST, LTO_vector_cst0, 2)
+#endif
 
 #ifdef TREE_SINGLE_MECHANICAL_FALSE
   MAP_EXPR_TAG(ARRAY_RANGE_REF, LTO_array_range_ref)
@@ -67,7 +73,6 @@
   MAP_EXPR_TAG(INTEGER_CST, LTO_integer_cst)
   MAP_EXPR_TAG(LABEL_DECL, LTO_label_decl)
   MAP_EXPR_TAG(LABEL_EXPR, LTO_label_expr)
-  MAP_EXPR_TAG(MODIFY_EXPR, LTO_modify_expr)
   MAP_EXPR_TAG(PARM_DECL, LTO_parm_decl)
   MAP_EXPR_TAG(RANGE_EXPR, LTO_range_expr)
   MAP_EXPR_TAG(REAL_CST, LTO_real_cst)
@@ -76,8 +81,6 @@
   MAP_EXPR_TAG(SSA_NAME, LTO_ssa_name)
   MAP_EXPR_TAG(STRING_CST, LTO_string_cst)
   MAP_EXPR_TAG(SWITCH_EXPR, LTO_switch_expr)
-  MAP_EXPR_TAG(VAR_DECL, LTO_var_decl)
-  MAP_EXPR_TAG(WITH_SIZE_EXPR, LTO_with_size_expr)
 #endif /* TREE_SINGLE_MECHANICAL_FALSE */
 
 #ifdef TREE_SINGLE_MECHANICAL_TRUE
@@ -122,6 +125,7 @@
   MAP_EXPR_TAG(MIN_EXPR, LTO_min_expr)
   MAP_EXPR_TAG(MINUS_EXPR, LTO_minus_expr)
   MAP_EXPR_TAG(MISALIGNED_INDIRECT_REF, LTO_misaligned_indirect_ref)
+  MAP_EXPR_TAG(MODIFY_EXPR, LTO_modify_expr)
   MAP_EXPR_TAG(MULT_EXPR, LTO_mult_expr)
   MAP_EXPR_TAG(NE_EXPR, LTO_ne_expr)
   MAP_EXPR_TAG(NEGATE_EXPR, LTO_negate_expr)
@@ -158,5 +162,187 @@
   MAP_EXPR_TAG(VIEW_CONVERT_EXPR, LTO_view_convert_expr)
   MAP_EXPR_TAG(WIDEN_MULT_EXPR, LTO_widen_mult_expr)
   MAP_EXPR_TAG(WIDEN_SUM_EXPR, LTO_widen_sum_expr)
+  MAP_EXPR_TAG(WITH_SIZE_EXPR, LTO_with_size_expr)
 #endif /* TREE_SINGLE_MECHANICAL_TRUE  */
 
+#ifdef LTO_STREAM_DEBUGGING_INIT_NAMES
+  SET_NAME (LTO_bb0, "bb0")
+  SET_NAME (LTO_bb1, "bb1")
+  SET_NAME (LTO_set_eh0, "set_eh0")
+  SET_NAME (LTO_set_eh1, "set_eh1")
+  SET_NAME (LTO_abs_expr, "abs_expr")
+  SET_NAME (LTO_addr_expr, "addr_expr")
+  SET_NAME (LTO_align_indirect_ref, "align_indirect_ref")
+  SET_NAME (LTO_array_range_ref, "array_range_ref")
+  SET_NAME (LTO_array_ref, "array_ref")
+  SET_NAME (LTO_asm_expr, "asm_expr")
+  SET_NAME (LTO_assert_expr, "assert_expr")
+  SET_NAME (LTO_bit_and_expr, "bit_and_expr")
+  SET_NAME (LTO_bit_ior_expr, "bit_ior_expr")
+  SET_NAME (LTO_bit_field_ref0, "bit_field_ref0")
+  SET_NAME (LTO_bit_field_ref1, "bit_field_ref1")
+  SET_NAME (LTO_bit_not_expr, "bit_not_expr")
+  SET_NAME (LTO_bit_xor_expr, "bit_xor_expr")
+  SET_NAME (LTO_call_expr0, "call_expr0")
+  SET_NAME (LTO_call_expr1, "call_expr1")
+  SET_NAME (LTO_case_label_expr0, "case_label_expr0")
+  SET_NAME (LTO_case_label_expr1, "case_label_expr1")
+  SET_NAME (LTO_case_label_expr2, "case_label_expr2")
+  SET_NAME (LTO_case_label_expr3, "case_label_expr3")
+  SET_NAME (LTO_ceil_div_expr, "ceil_div_expr")
+  SET_NAME (LTO_ceil_mod_expr, "ceil_mod_expr")
+  SET_NAME (LTO_complex_cst0, "complex_cst0")
+  SET_NAME (LTO_complex_cst1, "complex_cst1")
+  SET_NAME (LTO_complex_expr, "complex_expr")
+  SET_NAME (LTO_component_ref, "component_ref")
+  SET_NAME (LTO_compound_expr, "compound_expr")
+  SET_NAME (LTO_cond_expr, "cond_expr")
+  SET_NAME (LTO_conj_expr, "conj_expr")
+  SET_NAME (LTO_const_decl, "const_decl")
+  SET_NAME (LTO_constructor, "constructor")
+  SET_NAME (LTO_constructor_range, "constructor_range")
+  SET_NAME (LTO_convert_expr, "convert_expr")
+  SET_NAME (LTO_dot_prod_expr, "dot_prod_expr")
+  SET_NAME (LTO_eq_expr, "eq_expr")
+  SET_NAME (LTO_exact_div_expr, "exact_div_expr")
+  SET_NAME (LTO_exc_ptr_expr, "exc_ptr_expr")
+  SET_NAME (LTO_field_decl, "field_decl")
+  SET_NAME (LTO_filter_expr, "filter_expr")
+  SET_NAME (LTO_fix_ceil_expr, "fix_ceil_expr")
+  SET_NAME (LTO_fix_floor_expr, "fix_floor_expr")
+  SET_NAME (LTO_fix_round_expr, "fix_round_expr")
+  SET_NAME (LTO_fix_trunc_expr, "fix_trunc_expr")
+  SET_NAME (LTO_float_expr, "float_expr")
+  SET_NAME (LTO_floor_div_expr, "floor_div_expr")
+  SET_NAME (LTO_floor_mod_expr, "floor_mod_expr")
+  SET_NAME (LTO_function_decl, "function_decl")
+  SET_NAME (LTO_ge_expr, "ge_expr")
+  SET_NAME (LTO_goto_expr, "goto_expr")
+  SET_NAME (LTO_gt_expr, "gt_expr")
+  SET_NAME (LTO_imagpart_expr, "imagpart_expr")
+  SET_NAME (LTO_indirect_ref, "indirect_ref")
+  SET_NAME (LTO_integer_cst, "integer_cst")
+  SET_NAME (LTO_label_decl, "label_decl")
+  SET_NAME (LTO_label_expr, "label_expr")
+  SET_NAME (LTO_le_expr, "le_expr")
+  SET_NAME (LTO_lrotate_expr, "lrotate_expr")
+  SET_NAME (LTO_lshift_expr, "lshift_expr")
+  SET_NAME (LTO_lt_expr, "lt_expr")
+  SET_NAME (LTO_ltgt_expr, "ltgt_expr")
+  SET_NAME (LTO_max_expr, "max_expr")
+  SET_NAME (LTO_min_expr, "min_expr")
+  SET_NAME (LTO_minus_expr, "minus_expr")
+  SET_NAME (LTO_misaligned_indirect_ref, "misaligned_indirect_ref")
+  SET_NAME (LTO_modify_expr, "modify_expr")
+  SET_NAME (LTO_mult_expr, "mult_expr")
+  SET_NAME (LTO_ne_expr, "ne_expr")
+  SET_NAME (LTO_negate_expr, "negate_expr")
+  SET_NAME (LTO_non_lvalue_expr, "non_lvalue_expr")
+  SET_NAME (LTO_nop_expr, "nop_expr")
+  SET_NAME (LTO_obj_type_ref, "obj_type_ref")
+  SET_NAME (LTO_ordered_expr, "ordered_expr")
+  SET_NAME (LTO_parm_decl, "parm_decl")
+  SET_NAME (LTO_plus_expr, "plus_expr")
+  SET_NAME (LTO_range_expr, "range_expr")
+  SET_NAME (LTO_rdiv_expr, "rdiv_expr")
+  SET_NAME (LTO_real_cst, "real_cst")
+  SET_NAME (LTO_realign_load_expr, "realign_load_expr")
+  SET_NAME (LTO_realpart_expr, "realpart_expr")
+  SET_NAME (LTO_reduc_max_expr, "reduc_max_expr")
+  SET_NAME (LTO_reduc_min_expr, "reduc_min_expr")
+  SET_NAME (LTO_reduc_plus_expr, "reduc_plus_expr")
+  SET_NAME (LTO_result_decl, "result_decl")
+  SET_NAME (LTO_return_expr0, "return_expr0")
+  SET_NAME (LTO_return_expr1, "return_expr1")
+  SET_NAME (LTO_return_expr2, "return_expr2")
+  SET_NAME (LTO_resx_expr, "resx_expr")
+  SET_NAME (LTO_round_div_expr, "round_div_expr")
+  SET_NAME (LTO_round_mod_expr, "round_mod_expr")
+  SET_NAME (LTO_rrotate_expr, "rrotate_expr")
+  SET_NAME (LTO_rshift_expr, "rshift_expr")
+  SET_NAME (LTO_ssa_name, "ssa_name")
+  SET_NAME (LTO_string_cst, "string_cst")
+  SET_NAME (LTO_switch_expr, "switch_expr")
+  SET_NAME (LTO_trunc_div_expr, "trunc_div_expr")
+  SET_NAME (LTO_trunc_mod_expr, "trunc_mod_expr")
+  SET_NAME (LTO_truth_and_expr, "truth_and_expr")
+  SET_NAME (LTO_truth_not_expr, "truth_not_expr")
+  SET_NAME (LTO_truth_or_expr, "truth_or_expr")
+  SET_NAME (LTO_truth_xor_expr, "truth_xor_expr")
+  SET_NAME (LTO_uneq_expr, "uneq_expr")
+  SET_NAME (LTO_unge_expr, "unge_expr")
+  SET_NAME (LTO_ungt_expr, "ungt_expr")
+  SET_NAME (LTO_unle_expr, "unle_expr")
+  SET_NAME (LTO_unlt_expr, "unlt_expr")
+  SET_NAME (LTO_unordered_expr, "unordered_expr")
+  SET_NAME (LTO_var_decl0, "var_decl0")
+  SET_NAME (LTO_var_decl1, "var_decl1")
+  SET_NAME (LTO_vec_cond_expr, "vec_cond_expr")
+  SET_NAME (LTO_vec_lshift_expr, "vec_lshift_expr")
+  SET_NAME (LTO_vec_rshift_expr, "vec_rshift_expr")
+  SET_NAME (LTO_vector_cst0, "vector_cst0")
+  SET_NAME (LTO_vector_cst1, "vector_cst1")
+  SET_NAME (LTO_view_convert_expr, "view_convert_expr")
+  SET_NAME (LTO_widen_mult_expr, "widen_mult_expr")
+  SET_NAME (LTO_widen_sum_expr, "widen_sum_expr")
+  SET_NAME (LTO_with_size_expr, "with_size_expr")
+  SET_NAME (LTO_asm_inputs, "asm_inputs")
+  SET_NAME (LTO_asm_outputs, "asm_outputs")
+  SET_NAME (LTO_asm_clobbers, "asm_clobbers")
+  SET_NAME (LTO_function, "function")
+  SET_NAME (LTO_attribute_list, "attribute_list")
+  SET_NAME (LTO_eh_table, "eh_table")
+  SET_NAME (LTO_eh_table_cleanup0, "eh_table_cleanup0")
+  SET_NAME (LTO_eh_table_cleanup1, "eh_table_cleanup1")
+  SET_NAME (LTO_eh_table_cleanup2, "eh_table_cleanup2")
+  SET_NAME (LTO_eh_table_cleanup3, "eh_table_cleanup3")
+  SET_NAME (LTO_eh_table_try0, "eh_table_try0")
+  SET_NAME (LTO_eh_table_try1, "eh_table_try1")
+  SET_NAME (LTO_eh_table_try2, "eh_table_try2")
+  SET_NAME (LTO_eh_table_try3, "eh_table_try3")
+  SET_NAME (LTO_eh_table_catch0, "eh_table_catch0")
+  SET_NAME (LTO_eh_table_catch1, "eh_table_catch1")
+  SET_NAME (LTO_eh_table_catch2, "eh_table_catch2")
+  SET_NAME (LTO_eh_table_catch3, "eh_table_catch3")
+  SET_NAME (LTO_eh_table_allowed0, "eh_table_allowed0")
+  SET_NAME (LTO_eh_table_allowed1, "eh_table_allowed1")
+  SET_NAME (LTO_eh_table_allowed2, "eh_table_allowed2")
+  SET_NAME (LTO_eh_table_allowed3, "eh_table_allowed3")
+  SET_NAME (LTO_eh_table_must_not_throw0, "eh_table_must_not_throw0")
+  SET_NAME (LTO_eh_table_must_not_throw1, "eh_table_must_not_throw1")
+  SET_NAME (LTO_eh_table_must_not_throw2, "eh_table_must_not_throw2")
+  SET_NAME (LTO_eh_table_must_not_throw3, "eh_table_must_not_throw3")
+  SET_NAME (LTO_local_var_decl_body0+0x0, "local_var_decl_body0")
+  SET_NAME (LTO_local_var_decl_body0+0x1, "local_var_decl_body1")
+  SET_NAME (LTO_local_var_decl_body0+0x2, "local_var_decl_body2")
+  SET_NAME (LTO_local_var_decl_body0+0x3, "local_var_decl_body3")
+  SET_NAME (LTO_local_var_decl_body0+0x4, "local_var_decl_body4")
+  SET_NAME (LTO_local_var_decl_body0+0x5, "local_var_decl_body5")
+  SET_NAME (LTO_local_var_decl_body0+0x6, "local_var_decl_body6")
+  SET_NAME (LTO_local_var_decl_body0+0x7, "local_var_decl_body7")
+  SET_NAME (LTO_local_var_decl_body0+0x8, "local_var_decl_body8")
+  SET_NAME (LTO_local_var_decl_body0+0x9, "local_var_decl_body9")
+  SET_NAME (LTO_local_var_decl_body0+0xa, "local_var_decl_bodya")
+  SET_NAME (LTO_local_var_decl_body0+0xb, "local_var_decl_bodyb")
+  SET_NAME (LTO_local_var_decl_body0+0xc, "local_var_decl_bodyc")
+  SET_NAME (LTO_local_var_decl_body0+0xd, "local_var_decl_bodyd")
+  SET_NAME (LTO_local_var_decl_body0+0xe, "local_var_decl_bodye")
+  SET_NAME (LTO_local_var_decl_body0+0xf, "local_var_decl_bodyf")
+  SET_NAME (LTO_parm_decl_body0+0x0, "parm_decl_body0")
+  SET_NAME (LTO_parm_decl_body0+0x1, "parm_decl_body1")
+  SET_NAME (LTO_parm_decl_body0+0x2, "parm_decl_body2")
+  SET_NAME (LTO_parm_decl_body0+0x3, "parm_decl_body3")
+  SET_NAME (LTO_parm_decl_body0+0x4, "parm_decl_body4")
+  SET_NAME (LTO_parm_decl_body0+0x5, "parm_decl_body5")
+  SET_NAME (LTO_parm_decl_body0+0x6, "parm_decl_body6")
+  SET_NAME (LTO_parm_decl_body0+0x7, "parm_decl_body7")
+  SET_NAME (LTO_parm_decl_body0+0x8, "parm_decl_body8")
+  SET_NAME (LTO_parm_decl_body0+0x9, "parm_decl_body9")
+  SET_NAME (LTO_parm_decl_body0+0xa, "parm_decl_bodya")
+  SET_NAME (LTO_parm_decl_body0+0xb, "parm_decl_bodyb")
+  SET_NAME (LTO_parm_decl_body0+0xc, "parm_decl_bodyc")
+  SET_NAME (LTO_parm_decl_body0+0xd, "parm_decl_bodyd")
+  SET_NAME (LTO_parm_decl_body0+0xe, "parm_decl_bodye")
+  SET_NAME (LTO_parm_decl_body0+0xf, "parm_decl_bodyf")
+#endif
+
Index: lto-tags.h
===================================================================
--- lto-tags.h	(revision 117575)
+++ lto-tags.h	(working copy)
@@ -27,7 +27,7 @@
 #include "sbitmap.h"
 
 #define LTO_major_version 0
-#define LTO_minor_version 2
+#define LTO_minor_version 3
 
 /* This file is one header in a collection of files that write the
    gimple intermediate code for a function into the assembly stream
@@ -44,10 +44,11 @@
    3) FUNCTION_DECLS.
    4) global VAR_DECLS.
    5) types.
-   6) Gimple for local decls.
-   7) Gimple for the function.
-   8) Strings.
-   9) Redundant information to aid in debugging the stream.
+   6) Names for the labels that have names
+   7) Gimple for local decls.
+   8) Gimple for the function.
+   9) Strings.
+   10-12)Redundant information to aid in debugging the stream.
       This is only present if the compiler is built with
       LTO_STREAM_DEBUGGING defined.
 
@@ -60,17 +61,24 @@
 /* The is the first part of the record for a function in the .o file.  */
 struct lto_function_header
 {
-  int16_t major_version;     /* LTO_major_version. */
-  int16_t minor_version;     /* LTO_minor_version. */
-  int32_t num_field_decls;   /* Number of FIELD_DECLS.  */
-  int32_t num_fn_decls;      /* Number of FUNCTION_DECLS.  */
-  int32_t num_var_decls;     /* Number of non local VAR_DECLS.  */
-  int32_t num_types;         /* Number of types.  */
-  int32_t compressed_size;   /* Size compressed or 0 if not compressed.  */
-  int32_t local_decls_size;  /* Size of local par and var decl region. */
-  int32_t main_size;         /* Size of main gimple body of function.  */
-  int32_t string_size;       /* Size of the string table.  */
-}; 
+  int16_t major_version;      /* LTO_major_version. */
+  int16_t minor_version;      /* LTO_minor_version. */
+  int32_t num_field_decls;    /* Number of FIELD_DECLS.  */
+  int32_t num_fn_decls;       /* Number of FUNCTION_DECLS.  */
+  int32_t num_var_decls;      /* Number of non local VAR_DECLS.  */
+  int32_t num_types;          /* Number of types.  */
+  int32_t num_local_decls;    /* Number of local VAR_DECLS and PARM_DECLS.  */
+  int32_t num_named_labels;   /* Number of labels with names.  */
+  int32_t num_unnamed_labels; /* Number of labels without names.  */
+  int32_t compressed_size;    /* Size compressed or 0 if not compressed.  */
+  int32_t named_label_size;   /* Size of names for named labels.  */
+  int32_t local_decls_size;   /* Size of local par and var decl region. */
+  int32_t main_size;          /* Size of main gimple body of function.  */
+  int32_t string_size;        /* Size of the string table.  */
+  int32_t debug_decl_size;   /* Size of local decl debugging information.  */
+  int32_t debug_label_size;   /* Size of label stream debugging information.  */
+  int32_t debug_main_size;    /* Size of main stream debugging information.  */
+};
 
 /* 2-5) THE GLOBAL DECLS AND TYPES.
 
@@ -83,7 +91,16 @@ struct lto_function_header
      a label for the debugging section.  This will cause more work for
      the linker but will make ln -r work properly.
 
-   6-7) GIMPLE FOR THE LOCAL DECLS AND THE FUNCTION BODY.
+   6) THE LABEL NAMES.  
+
+      Since most labels do not have names, this section my be of zero
+      length.  It consists of an array of string table references, one
+      per label.  In the lto code, the labels are given either
+      positive or negative indexes.  the positive ones have names and
+      the negative ones do not.  The positive index can be used to
+      find the name in this array.
+
+   7-8) GIMPLE FOR THE LOCAL DECLS AND THE FUNCTION BODY.
 
      The gimple consists of a set of records.
 
@@ -99,7 +116,7 @@ struct lto_function_header
 	 type         - If the tree code has a bit set in
                         lto_types_needed_for, a reference to the type
 			is generated.  This reference is an index into
-                        (6).  The index is encoded in uleb128 form.
+                        (7).  The index is encoded in uleb128 form.
 
 	 flags        - The set of flags defined for this tree code
 		        packed into a word where the low order 2 bits
@@ -140,7 +157,7 @@ struct lto_function_header
 
      THE FUNCTION
 	
-     At the top level of (7) is the function. It consists of five
+     At the top level of (8) is the function. It consists of five
      pieces:
 
      LTO_function     - The tag.
@@ -194,14 +211,28 @@ struct lto_function_header
 			  to terminate the statements and exception
 			  regions within this block.
 
-   8) STRINGS
+   9) STRINGS
 
      String are represented in the table as pairs, a length in ULEB128
      form followed by the data for the string.
 
-   9) STREAM DEBUGGING
-
-     tbd
+   10) STREAM DEBUGGING
+     
+     If the preprocessor symbol LTO_STREAM_DEBUGGING is defined, the
+     gimple is encoded into .o file as two streams.  The first stream
+     is the normal data stream that is also created when the symbol is
+     undefined.  The second stream is a human readable character
+     string that describes a trace of the operations used to encode
+     the data stream.  This stream is created by calls in the 
+     code to LTO_DEBUG_* functions.
+
+     The lto reader uses the same set of functions when it reads the
+     data stream.  However, it's version of the lowest level compares
+     the debugging stream character by character with the one produced
+     by the writer.  When the reader sees a character that is not the
+     same one as produced by the writer, it dumps the stream to stderr
+     along with a pointer to the offending character.  At this point
+     it is easy to see if the bug is in the encoding or the decoding.
 */
 
 /* When we get a strongly typed gimple, this flag should be set to 0
@@ -334,17 +365,19 @@ struct lto_function_header
 #define LTO_unle_expr                   0x06B
 #define LTO_unlt_expr                   0x06C
 #define LTO_unordered_expr              0x070
-#define LTO_var_decl                    0x071
-#define LTO_vec_cond_expr               0x072
-#define LTO_vec_lshift_expr             0x073
-#define LTO_vec_rshift_expr             0x074
+/* 1 for static or extern and 0 for local.  */
+#define LTO_var_decl0                   0x071
+#define LTO_var_decl1                   0x072
+#define LTO_vec_cond_expr               0x073
+#define LTO_vec_lshift_expr             0x074
+#define LTO_vec_rshift_expr             0x075
 /* 1 if the elements are reals and 0 if the elements are ints.  */
-#define LTO_vector_cst0                 0x075
-#define LTO_vector_cst1                 0x076
-#define LTO_view_convert_expr           0x079
-#define LTO_widen_mult_expr             0x07A
-#define LTO_widen_sum_expr              0x07B
-#define LTO_with_size_expr              0x07C
+#define LTO_vector_cst0                 0x076
+#define LTO_vector_cst1                 0x077
+#define LTO_view_convert_expr           0x078
+#define LTO_widen_mult_expr             0x079
+#define LTO_widen_sum_expr              0x07A
+#define LTO_with_size_expr              0x07B
 
 
 /* All of the statement types that do not also appear as
@@ -355,8 +388,7 @@ struct lto_function_header
 
 #define LTO_function                    0x083
 #define LTO_attribute_list              0x084
-#define LTO_local_var_decl              0x085
-#define LTO_eh_table                    0x086
+#define LTO_eh_table                    0x085
 
 /* Each of these requires 4 variants.  1 and 3 are have_inner and 2
    and 3 are may_contain_throw.  */
@@ -388,20 +420,77 @@ struct lto_function_header
       variant |= DECL_SIZE_UNIT (decl)  != NULL_TREE ? 0x02 : 0;
       variant |= needs_backing_var                   ? 0x04 : 0;
       variant |= ABSTRACT_ORIGIN (decl) != NULL_TREE ? 0x08 : 0;
+
+   These next two tags must have their last hex digit be 0. 
 */
 
 #define LTO_local_var_decl_body0        0x0B0
 #define LTO_parm_decl_body0             0x0C0
-
+#define LTO_last_tag                    0x0CF
 /* The string that is prepended on the DECL_ASSEMBLER_NAME to make the 
    section name for the function.  */
-#define LTO_SECTION_NAME_PREFIX         ".lto_"
+#define LTO_SECTION_NAME_PREFIX         ".gnu.lto_"
 
 /* This bitmap is indexed by gimple type codes and contains a 1 if the 
    tree type needs to have the type written.  */
 extern sbitmap lto_types_needed_for;
 
-
+/* This bitmap is indexed by gimple type codes and contains a 1 if the 
+   tree type needs to have the flags written.  */
+extern sbitmap lto_flags_needed_for;
 
 void lto_static_init (void);
+
+#define LTO_STREAM_DEBUGGING
+
+#ifdef LTO_STREAM_DEBUGGING
+#define LTO_DEBUG_INDENT(tag) \
+  lto_debug_indent (&lto_debug_context, tag);
+#define LTO_DEBUG_INDENT_TOKEN(value) \
+  lto_debug_indent_token (&lto_debug_context, value);
+#define LTO_DEBUG_INTEGER(tag,high,low) \
+  lto_debug_integer (&lto_debug_context, tag, high, low);
+#define LTO_DEBUG_STRING(value,len) \
+  lto_debug_string (&lto_debug_context, value, len);
+#define LTO_DEBUG_TOKEN(value) \
+  lto_debug_token (&lto_debug_context, value);
+#define LTO_DEBUG_UNDENT() \
+  lto_debug_undent (&lto_debug_context);
+#define LTO_DEBUG_WIDE(tag,value) \
+  lto_debug_wide (&lto_debug_context, tag, value);
+
+struct lto_debug_context;
+
+typedef void (*lto_debug_out) (struct lto_debug_context *context, char c);
+
+struct lto_debug_context
+{
+  lto_debug_out out;
+  int indent;
+  void * current_data;
+  void * decl_data;
+  void * label_data;
+  void * main_data;
+};
+
+extern const char * LTO_tag_names[LTO_last_tag];
+
+extern void lto_debug_indent (struct lto_debug_context *, int);
+extern void lto_debug_indent_token (struct lto_debug_context *, const char *);
+extern void lto_debug_integer (struct lto_debug_context *, const char *, HOST_WIDE_INT, HOST_WIDE_INT);
+extern void lto_debug_string (struct lto_debug_context *, const char *, int);
+extern void lto_debug_token (struct lto_debug_context *, const char *);
+extern void lto_debug_undent (struct lto_debug_context *);
+extern void lto_debug_wide (struct lto_debug_context *, const char *, HOST_WIDE_INT);
+
+#else
+#define LTO_DEBUG_INDENT(tag)
+#define LTO_DEBUG_INDENT_TOKEN(value)
+#define LTO_DEBUG_INTEGER(tag,high,low)
+#define LTO_DEBUG_STRING(value,len)
+#define LTO_DEBUG_TOKEN(value)
+#define LTO_DEBUG_UNDENT()
+#define LTO_DEBUG_WIDE(tag,value)
+#endif
+
 #endif /* lto-tags.h */
Index: lto/lto.c
===================================================================
--- lto/lto.c	(revision 117575)
+++ lto/lto.c	(working copy)
@@ -835,6 +835,15 @@ lto_read_form (lto_info_fd *info_fd, 
 	}
       break;
 
+    case DW_FORM_strp:
+      /* Temporary hack:  we don't need the string data, but we do need
+     it not to crash if it sees one.  So just skip past the offset
+     and return an empty string.  */
+      out->cl = DW_cl_string;
+      fd->dwarf64 ? lto_read_uword (fd) : lto_read_udword (fd);
+      out->u.string = "";
+      break;
+
     case DW_FORM_data1:
     case DW_FORM_data2:
     case DW_FORM_data4:
@@ -2666,7 +2675,7 @@ lto_read_base_type_DIE (lto_info_fd *fd,
     case DW_ATE_complex_float:
     case DW_ATE_lo_user:  
     default:
-      sorry ("unsupported base type encoding");
+      sorry ("unsupported base type encoding - 0x%x", encoding);
       break;
     }
   /* If this is a new type, declare it.
@@ -2734,6 +2743,28 @@ lto_read_const_volatile_restrict_type_DI
   return type;
 }
 
+static tree
+lto_read_unspecified_type_DIE (lto_info_fd *fd,
+			       const DWARF2_abbrev *abbrev,
+			       lto_context *context)
+{
+  tree type = NULL_TREE;
+
+  LTO_BEGIN_READ_ATTRS ()
+    {
+    case DW_AT_name:
+      gcc_assert (attr_data.cl == DW_cl_string);
+      if (strcmp (attr_data.u.string, "void") == 0)
+	type = void_type_node;
+      break;
+    }
+  LTO_END_READ_ATTRS ();
+
+  if (!type)
+    sorry ("unsupported use of DW_TAG_unspecified_type");
+  lto_read_child_DIEs (fd, abbrev, context);
+  return type;
+}
 
 /* Read the next DIE from FD.  CONTEXT provides information about the
    current state of the compilation unit.  Returns a (possibly null) TREE
@@ -2808,7 +2839,7 @@ lto_read_DIE (lto_info_fd *fd, lto_conte
       NULL, /* interface_type */
       NULL, /* namespace */
       NULL, /* imported_module */
-      NULL, /* unspecified_type */
+      lto_read_unspecified_type_DIE, 
       NULL, /* partial_unit */
       NULL, /* imported_unit */
       NULL, /* padding */
@@ -3041,7 +3072,7 @@ lto_resolve_type_ref (lto_info_fd *info_
 		      const lto_ref *ref)
 {
   const char *reference;
-  lto_context *new_context;
+  lto_context *new_context = context;
   tree type;
 
   /* At present, we only support a single DWARF section.  */
Index: lto/lto-read.c
===================================================================
--- lto/lto-read.c	(revision 117575)
+++ lto/lto-read.c	(working copy)
@@ -53,19 +53,831 @@ Boston, MA 02110-1301, USA.  */
 #include "lto.h"
 #include <ctype.h>
 
+static enum tree_code tag_to_expr[LTO_last_tag];
+
+/* The number of flags that are defined for each tree code.  */
+static int num_flags_for_code[NUM_TREE_CODES];
+
 struct fun_in
 {
-  tree *field_decls;
-  tree *fn_decls;
-  tree *var_decls;
-  tree *types;
+  tree *field_decls;        /* The field decls.  */
+  tree *fn_decls;           /* The function decls.  */
+  tree *var_decls;          /* The global or static var_decls.  */
+  tree *types;              /* All of the types.  */
+  tree *local_decls;        /* The local var_decls and the parm_decls.  */
+  tree *labels;             /* All of the labels.  */
+  const char * strings;     /* The string table.  */
+  unsigned int strings_len; /* The length of the string table.  */
+  /* Number of named labels.  Used to find the index of unnamed labels
+     since they share space with the named labels.  */
+  unsigned int num_named_labels;  
+};
+
+
+struct input_block 
+{
+  const char *data;
+  unsigned int p;
+  unsigned int len;
 };
 
 
+#ifdef LTO_STREAM_DEBUGGING
+static struct lto_debug_context lto_debug_context;
+static void debug_out_fun (struct lto_debug_context *, char);
+static void dump_debug_stream (struct input_block *, char, char);
+#endif
+
+static tree
+input_expr_operand (struct input_block *, struct fun_in *, unsigned int);
+
+
+/* Return the next character of input from IB.  Abort if you
+   overrun.  */
+
+static unsigned char 
+input_1_unsigned (struct input_block *ib)
+{
+  gcc_assert (ib->p < ib->len);
+  return (ib->data[ib->p++]);
+}
+
+
+/* Read an ULEB128 Number of IB.  */
+
+static unsigned HOST_WIDE_INT 
+input_uleb128 (struct input_block *ib)
+{
+  unsigned HOST_WIDE_INT result = 0;
+  int shift = 0;
+  unsigned int byte;
+
+  while (true)
+    {
+      byte = input_1_unsigned (ib);
+      result |= (byte & 0x7f) << shift;
+      shift += 7;
+      if ((byte & 0x80) == 0)
+	{
+	  LTO_DEBUG_WIDE ("U", result)
+	  return result;
+	}
+    }
+}
+
+
+/* Read an SLEB128 Number of IB.  */
+
+static HOST_WIDE_INT 
+input_sleb128 (struct input_block *ib)
+{
+  HOST_WIDE_INT result = 0;
+  int shift = 0;
+  unsigned HOST_WIDE_INT byte;
+
+  while (true)
+    {
+      byte = input_1_unsigned (ib);
+      result |= (byte & 0x7f) << shift;
+      shift += 7;
+      if ((byte & 0x80) == 0)
+	{
+	  if ((shift < HOST_BITS_PER_INT) && (byte & 0x40))
+	    result |= - (1 << shift);
+
+	  LTO_DEBUG_WIDE ("S", result)
+	  return result;
+	}
+    }
+}
+
+
+/* Read the string at LOC from the string table in FUN_IN.  */
+
+static const char * 
+input_string_internal (struct fun_in *fun_in, unsigned int loc, 
+		       unsigned int *rlen)
+{
+  struct input_block str_tab 
+    = {fun_in->strings, loc, fun_in->strings_len};
+  unsigned int len = input_uleb128 (&str_tab);
+  const char * result;
+
+  *rlen = len;
+  gcc_assert (str_tab.p + len <= fun_in->strings_len);
+
+  result = (const char *)(fun_in->strings + str_tab.p);
+  LTO_DEBUG_STRING (result, len)
+  return result;
+}
+
+
+/* Read a STRING_CST at LOC from the string table in FUN_IN.  */
+
+static tree
+input_string (struct fun_in *fun_in, unsigned int loc)
+{
+  unsigned int len;
+  const char * ptr = input_string_internal (fun_in, loc, &len);
+  return build_string (len, ptr);
+}
+
+
+/* Input a real constant of TYPE at LOC.  */
+
+static tree
+input_real (struct fun_in *fun_in, unsigned int loc, tree type)
+{
+  unsigned int len;
+  const char * str = input_string_internal (fun_in, loc, &len); 
+  REAL_VALUE_TYPE value;
+
+  LTO_DEBUG_TOKEN ("real")
+
+  real_from_string (&value, str);
+  return build_real (type, value);
+}
+
+
+/* Input the next integer constant of TYPE in IB.  */
+
+static tree
+input_integer (struct input_block *ib, tree type)
+{
+  HOST_WIDE_INT low = 0;
+  HOST_WIDE_INT high = 0;
+  int shift = 0;
+  unsigned int byte;
+
+  while (true)
+    {
+      byte = input_1_unsigned (ib);
+      if (shift < HOST_BITS_PER_INT - 7)
+	/* Working on the low part.  */
+	low |= (byte & 0x7f) << shift;
+      else if (shift >= HOST_BITS_PER_INT)
+	/* Working on the high part.  */
+	high |= (byte & 0x7f) << (shift - HOST_BITS_PER_INT);
+      else
+	{
+	  /* Working on the transition between the low and high parts.  */
+	  low |= (byte & 0x7f) << shift;
+	  high |= (byte & 0x7f) >> (HOST_BITS_PER_INT - shift);
+	}
+
+      shift += 7;
+      if ((byte & 0x80) == 0)
+	{
+	  if (byte & 0x40)
+	    {
+	      /* The number is negative.  */
+	      if (shift < HOST_BITS_PER_INT)
+		{
+		  low |= - (1 << shift);
+		  high = -1;
+		}
+	      else if (shift < (2 * HOST_BITS_PER_INT))
+		high |= - (1 << shift);
+	    }
+
+#ifdef LTO_STREAM_DEBUGGING
+	  /* Have to match the quick out in the lto writer.  */
+	  if (((high == -1) && (low < 0))
+	      || ((high == 0) && (low >= 0)))
+	    LTO_DEBUG_WIDE ("S", low)
+	  else 
+	    LTO_DEBUG_INTEGER ("SS", high, low)
+#endif	  
+	  return build_int_cst_wide (type, low, high);
+	}
+    }
+}
+
+
+/* Return the next tag in the input block IB.  */
+
+static unsigned int
+input_record_start (struct input_block *ib)
+{
+  unsigned int tag = input_1_unsigned (ib);
+
+#ifdef LTO_STREAM_DEBUGGING
+  if (tag)
+    LTO_DEBUG_INDENT (tag)
+  else
+    LTO_DEBUG_WIDE ("U", 0)
+#endif    
+  return tag;
+} 
+
+
+/* Build a tree list stopping when the tag is 0.  */
+
+static tree 
+input_list (struct input_block *ib, struct fun_in *fun_in)
+{
+  unsigned int tag = input_record_start (ib);
+  tree first = NULL_TREE;
+  if (tag)
+    {
+      first = build_tree_list (NULL_TREE, input_expr_operand (ib, fun_in, tag));
+      tree next = first;
+      tag = input_record_start (ib);
+      while (tag)
+	{
+	  TREE_CHAIN (next) 
+	    = build_tree_list (NULL_TREE, input_expr_operand (ib, fun_in, tag));
+	  next = TREE_CHAIN (next);
+	  tag = input_record_start (ib);
+	}
+    }
+
+  LTO_DEBUG_UNDENT()
+  return first;
+}
+
+/* Set up an empty cfg for THIS_FUN with BB_COUNT slots available.  */
+
+static void 
+init_cfg (struct function *this_fun, unsigned int bb_count)
+{
+  init_flow (this_fun);
+  profile_status_for_function (this_fun) = PROFILE_ABSENT;
+  n_basic_blocks_for_function (this_fun) = NUM_FIXED_BLOCKS;
+  last_basic_block_for_function (this_fun) = bb_count;
+  basic_block_info_for_function (this_fun)
+    = VEC_alloc (basic_block, gc, bb_count);
+  VEC_safe_grow (basic_block, gc, basic_block_info, bb_count);
+  memset (VEC_address (basic_block, 
+		       basic_block_info_for_function (this_fun)), 
+	  0, sizeof (basic_block) * bb_count);
+
+  /* Build a mapping of labels to their associated blocks.  */
+  label_to_block_map_for_function (this_fun)
+    = VEC_alloc (basic_block, gc, bb_count);
+  VEC_safe_grow (basic_block, gc, 
+		 label_to_block_map_for_function (this_fun), bb_count);
+  memset (VEC_address (basic_block, 
+		       label_to_block_map_for_function (this_fun)),
+	  0, sizeof (basic_block) * bb_count);
+
+  SET_BASIC_BLOCK_FOR_FUNCTION (this_fun, ENTRY_BLOCK, 
+				ENTRY_BLOCK_PTR_FOR_FUNCTION (this_fun));
+  SET_BASIC_BLOCK_FOR_FUNCTION (this_fun, EXIT_BLOCK, 
+		   EXIT_BLOCK_PTR_FOR_FUNCTION (this_fun));
+}
+
+
+/* Link up the prev_bb and next_bb fields in the cfg.  */
+
+static void 
+finalize_cfg (struct function *this_fun, unsigned int bb_count)
+{
+  unsigned int i;
+  basic_block p_bb = ENTRY_BLOCK_PTR_FOR_FUNCTION(this_fun);
+
+  for (i=NUM_FIXED_BLOCKS; i<bb_count; i++)
+    {
+      basic_block bb = BASIC_BLOCK_FOR_FUNCTION (this_fun, i);
+      if (bb)
+	{
+	  bb->prev_bb = p_bb;
+	  p_bb->next_bb = bb;
+	  p_bb = bb;
+	}
+    }
+
+  p_bb->next_bb = EXIT_BLOCK_PTR_FOR_FUNCTION(this_fun);
+  EXIT_BLOCK_PTR_FOR_FUNCTION(this_fun)->prev_bb = p_bb;
+}
+
+
+/* Get the label referenced by the next token in IB.  */
+
+static tree 
+get_label_decl (struct fun_in *fun_in, struct input_block *ib)
+{
+  int index = input_sleb128 (ib);
+  if (index >= 0)
+    return fun_in->labels[index];
+  else
+    return fun_in->labels[fun_in->num_named_labels - index];
+}
+
+
+/* Get the type referenced by the next token in IB.  */
+
+static tree
+get_type_ref (struct fun_in *fun_in, struct input_block *ib)
+{
+  int index;
+
+  LTO_DEBUG_TOKEN ("type")
+  index = input_uleb128 (ib);
+  return fun_in->types[index];
+}
+
+/* Set all of the FLAGS for NODE.  */
+#define CLEAROUT (HOST_BITS_PER_INT - 1)
+
+
+/* Set all of the flag bits inside EXPR by unpacking FLAGS.  */
+
+static void
+process_flags (tree expr, unsigned HOST_WIDE_INT flags)
+{
+  enum tree_code code = TREE_CODE (expr);
+  /* Shift the flags up so that the first flag is at the top of the
+     flag word.  */
+  flags <<= HOST_BITS_PER_INT - num_flags_for_code[code];
+
+#define START_CLASS_SWITCH()              \
+  {                                       \
+                                          \
+    switch (TREE_CODE_CLASS (code))       \
+    {
+
+#define START_CLASS_CASE(class)    case class:
+#define ADD_CLASS_FLAG(flag_name) { expr->common. flag_name = flags >> CLEAROUT;  flags <<= 1; }
+#define END_CLASS_CASE(class)      break;
+#define END_CLASS_SWITCH()                \
+    default:                              \
+      gcc_unreachable ();                 \
+    }
+
+
+#define START_EXPR_SWITCH()               \
+    switch (code)			  \
+    {
+#define START_EXPR_CASE(code)    case code:
+#define ADD_EXPR_FLAG(flag_name) { expr->common. flag_name = (flags >> CLEAROUT);  flags <<= 1; }
+#define ADD_DECL_FLAG(flag_name) { expr->decl_common. flag_name = flags >> CLEAROUT; flags <<= 1; }
+#define END_EXPR_CASE(class)      break;
+#define END_EXPR_SWITCH()                 \
+    default:                              \
+      gcc_unreachable ();                 \
+    }                                     \
+  }
+
+#include "lto-tree-flags.def"
+
+#undef START_CLASS_SWITCH
+#undef START_CLASS_CASE
+#undef ADD_CLASS_FLAG
+#undef END_CLASS_CASE
+#undef END_CLASS_SWITCH
+#undef START_EXPR_SWITCH
+#undef START_EXPR_CASE
+#undef ADD_EXPR_FLAG
+#undef ADD_DECL_FLAG
+#undef END_EXPR_CASE
+#undef END_EXPR_SWITCH
+}
+
+
+/* Read a node in the gimple tree from IB.  The TAG has already been
+   read.  */
+
+static tree
+input_expr_operand (struct input_block *ib, struct fun_in *fun_in, 
+		    unsigned int tag)
+{
+  enum tree_code code = tag_to_expr[tag];
+  tree type = NULL_TREE;
+  unsigned HOST_WIDE_INT flags;
+  const char *new_file = NULL;
+  int new_line = -1;
+  gcc_assert (code);
+  tree result = NULL_TREE;
+  
+  if (TEST_BIT (lto_types_needed_for, code))
+    type = get_type_ref (fun_in, ib);
+
+  if (TEST_BIT (lto_flags_needed_for, code))
+    {
+      LTO_DEBUG_TOKEN ("flags")
+      flags = input_uleb128 (ib);
+    }
+  else
+    flags = 0;
+
+  /* FIXME! need to figure out how to set the file and line number.  */
+  if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))
+    {
+      if (flags & 0x2)
+	{
+	  unsigned int len;
+	  LTO_DEBUG_TOKEN ("file")
+	  new_file = input_string_internal (fun_in, input_uleb128 (ib), &len);
+	}
+      if (flags & 0x1)
+	{
+	  LTO_DEBUG_TOKEN ("line")
+	  new_line = input_uleb128 (ib);
+	}
+    }
+
+  switch (code)
+    {
+    case COMPLEX_CST:
+      result = build0 (code, type);
+      if (tag == LTO_complex_cst1)
+	{
+	  TREE_REALPART (result) 
+	    = input_real (fun_in, input_uleb128 (ib), type);
+	  TREE_IMAGPART (result) 
+	    = input_real (fun_in, input_uleb128 (ib), type);
+	}
+      else
+	{
+	  TREE_REALPART (result) = input_integer (ib, type);
+	  TREE_IMAGPART (result) = input_integer (ib, type);
+	}
+      break;
+
+    case INTEGER_CST:
+      result = input_integer (ib, type);
+      break;
+
+    case REAL_CST:
+      result = input_real (fun_in, input_uleb128 (ib), type);
+      break;
+
+    case STRING_CST:
+      result = input_string (fun_in, input_uleb128 (ib));
+      break;
+
+    case VECTOR_CST:
+      {
+	tree chain = NULL_TREE;
+	int len = input_uleb128 (ib);
+
+	if (len && tag == LTO_vector_cst1)
+	  {
+	    int i;
+	    tree last 
+	      = build_tree_list (NULL_TREE, 
+				 input_real (fun_in, 
+					     input_uleb128 (ib), 
+					     type));
+	    chain = last; 
+	    for (i = 1; i < len; i++)
+	      {
+		tree t 
+		  = build_tree_list (NULL_TREE, 
+				     input_real (fun_in, 
+						 input_uleb128 (ib), 
+						 type));
+		TREE_CHAIN (last) = t;
+		last = t;
+	      }
+	  }
+	else
+	  {
+	    int i;
+	    tree last = build_tree_list (NULL_TREE, input_integer (ib, type));
+	    chain = last; 
+	    for (i = 1; i < len; i++)
+	      {
+		tree t 
+		  = build_tree_list (NULL_TREE, input_integer (ib, type));
+		TREE_CHAIN (last) = t;
+		last = t;
+	      }
+	  }
+	result = build_vector (type, chain);
+      }
+      break;
+
+    case CASE_LABEL_EXPR:
+      {
+	int variant = tag - LTO_case_label_expr0;
+	tree op0 = NULL_TREE;
+	tree op1 = NULL_TREE;
+	
+	if (variant & 0x1)
+	  op0 = input_expr_operand (ib, fun_in, 
+				    input_record_start (ib));
+
+	if (variant & 0x2)
+	  op1 = input_expr_operand (ib, fun_in, 
+				    input_record_start (ib));
+
+	result = build3 (code, void_type_node, 
+			 op0, op1, get_label_decl (fun_in, ib));
+      }
+      break;
+
+    case CONSTRUCTOR:
+      {
+	VEC(constructor_elt,gc) *vec = NULL;
+	unsigned int len = input_uleb128 (ib);
+	
+	if (len)
+	  {
+	    tree purpose = NULL_TREE;
+	    unsigned int i = 0;
+	    vec = VEC_alloc (constructor_elt, gc, len);
+	    while (i < len)
+	      {
+		unsigned int ctag = input_record_start (ib);
+		if (ctag == LTO_constructor_range)
+		  {
+		    tree op0 = input_integer (ib, get_type_ref (fun_in, ib));
+		    tree op1 = input_integer (ib, get_type_ref (fun_in, ib));
+		    purpose = build2 (RANGE_EXPR, sizetype, op0, op1);
+		  }
+		else
+		  {
+		    tree value = 
+		      input_expr_operand (ib, fun_in, ctag);
+		    constructor_elt *elt 
+		      = VEC_quick_push (constructor_elt, vec, NULL);
+		    elt->index = purpose;
+		    elt->value = value;
+		    
+		    /* Only use the range once.  */
+		    purpose = NULL_TREE;
+		    i++;
+		  }
+		LTO_DEBUG_UNDENT()
+	      }
+	  }
+	result = build_constructor (type, vec);
+      }
+      break;
+
+    case CONST_DECL:
+      /* Just ignore these, Mark will make them disappear.  */
+      break;
+
+    case FIELD_DECL:
+      result = fun_in->field_decls [input_uleb128 (ib)];
+      break;
+
+    case FUNCTION_DECL:
+      result = fun_in->fn_decls [input_uleb128 (ib)];
+      break;
+
+    case VAR_DECL:
+      if (tag == LTO_var_decl1)
+	/* Static or externs are here.  */
+	result = fun_in->var_decls [input_uleb128 (ib)];
+      else 
+	{
+	  /* Locals are here.  */
+	  int lv_index = input_uleb128 (ib);
+	  result = fun_in->local_decls [lv_index];
+	  /* There is a rare case where the local var decl in the
+	     table will be NULL.  This is caused if the subtrees of
+	     var_decls reference other local var decls.  Create an
+	     empty one now and the local decl reading code will fill
+	     in the fields later rather than creating its own.  */
+	  if (result == NULL)
+	    {
+	      result = build_decl (VAR_DECL, NULL_TREE, NULL_TREE);
+	      fun_in->local_decls [lv_index] = result;
+	    }
+	}
+      break;
+
+    case PARM_DECL:
+      result = fun_in->local_decls [input_uleb128 (ib)];
+      break;
+
+    case LABEL_DECL:
+      result = get_label_decl (fun_in, ib);
+      break;
+
+    case LABEL_EXPR:
+      result = build1 (code, void_type_node, get_label_decl (fun_in, ib));
+      break;
+
+    case RESULT_DECL:
+      result = build0 (code, NULL_TREE);
+      break;
+
+    case COMPONENT_REF:
+      {
+	tree op0;
+	tree op1;
+	op0 = input_expr_operand (ib, fun_in, 
+				  input_record_start (ib));
+	op1 = input_expr_operand (ib, fun_in, 
+				  input_record_start (ib));
+  
+	/* Ignore 3 because it can be recomputed.  */
+	result = build3 (code, type, op0, op1, NULL_TREE);
+      }
+      break;
+
+    case CALL_EXPR:
+      {
+	unsigned int i;
+	unsigned int count = input_uleb128 (ib);
+	tree op1;
+	tree op2 = NULL_TREE;
+
+	/* The call chain.  */
+	if (tag == LTO_call_expr1)
+	  op2 = input_expr_operand (ib, fun_in, 
+				    input_record_start (ib));
+
+	/* The callee.  */
+	op1 = input_expr_operand (ib, fun_in, 
+				  input_record_start (ib));
+
+	result = build_vl_exp (code, count);
+	CALL_EXPR_FN (result) = op1;
+	CALL_EXPR_STATIC_CHAIN (result) = op2;
+	for (i = 3; i < count; i++)
+	  TREE_OPERAND (result, i) 
+	    = input_expr_operand (ib, fun_in, 
+				  input_record_start (ib));
+      }
+      break;
+
+    case BIT_FIELD_REF:
+      {
+	tree op0;
+	tree op1;
+	tree op2;
+	if (tag == LTO_bit_field_ref1)
+	  {
+	    op1 = input_integer (ib, SIZETYPE);
+	    op2 = input_integer (ib, SIZETYPE);
+	    op0 = input_expr_operand (ib, fun_in, 
+				      input_record_start (ib));
+	  }
+	else
+	  {
+	    op0 = input_expr_operand (ib, fun_in, 
+				      input_record_start (ib));
+	    op1 = input_expr_operand (ib, fun_in, 
+				      input_record_start (ib));
+	    op2 = input_expr_operand (ib, fun_in, 
+				      input_record_start (ib));
+	  }
+	result = build3 (code, type, op0, op1, op2);
+      }
+      break;
+
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+      /* Ignore operands 2 and 3 for ARRAY_REF and ARRAY_RANGE REF
+	 because they can be recomputed.  */
+      {
+	tree op0 = input_expr_operand (ib, fun_in, 
+				       input_record_start (ib));
+	tree op1 = input_expr_operand (ib, fun_in, 
+				       input_record_start (ib));
+	result = build4 (code, type, op0, op1, NULL_TREE, NULL_TREE);
+      }
+      break;
+
+    case ASM_EXPR:
+      {
+	tree str = input_string (fun_in, input_uleb128 (ib));
+	tree ins = input_list (ib, fun_in); 
+	tree outs = input_list (ib, fun_in); 
+	tree clobbers = input_list (ib, fun_in);
+	result = build4 (code, void_type_node, str, outs, ins, clobbers);
+      }
+      break;
+
+    case RESX_EXPR:
+      result = build1 (code, void_type_node, input_integer (ib, NULL_TREE));
+      break;
+
+    case RETURN_EXPR:
+      switch (tag) 
+	{
+	case LTO_return_expr0:
+	  result = build1 (code, NULL_TREE, NULL_TREE);
+	  break;
+	  
+	case LTO_return_expr1:
+	  result = build1 (code, NULL_TREE, 
+			   input_expr_operand (ib, fun_in, 
+					       input_record_start (ib)));
+	  break;
+	  
+	case LTO_return_expr2:
+	  {
+	    tree op0 = input_expr_operand (ib, fun_in, 
+					   input_record_start (ib));
+	    tree op1 = input_expr_operand (ib, fun_in, 
+					   input_record_start (ib));
+	    result = build1 (code, NULL_TREE, 
+			     build2 (MODIFY_EXPR, NULL_TREE, op0, op1));
+	  }
+	  break;
+	}
+      break;
+
+    case SWITCH_EXPR:
+      {
+	unsigned int len = input_uleb128 (ib);
+	unsigned int i;
+	tree op0 = input_expr_operand (ib, fun_in, 
+				       input_record_start (ib));
+	tree op2 = make_tree_vec (len);
+	
+	for (i = 0; i < len; ++i)
+	  TREE_VEC_ELT (op2, i) 
+	    = input_expr_operand (ib, fun_in, 
+				  input_record_start (ib));
+	result = build3 (code, NULL_TREE, op0, NULL_TREE, op2);
+      }
+      break;
+
+      /* This is the default case. All of the cases that can be done
+	 completely mechanically are done here.  */
+#define SET_NAME(a,b)
+#define TREE_SINGLE_MECHANICAL_TRUE
+#define MAP_EXPR_TAG(expr,tag) case expr:
+#include "lto-tree-tags.def"
+#undef MAP_EXPR_TAG
+#undef TREE_SINGLE_MECHANICAL_TRUE
+#undef SET_NAME
+      {
+	tree ops[7];
+	int len = TREE_CODE_LENGTH (code);
+	int i;
+	for (i = 0; i<len; i++)
+	  ops[i] = input_expr_operand (ib, fun_in, 
+				       input_record_start (ib));
+	switch (len)
+	  {
+	  case 0:
+	    result = build0 (code, type);
+	    break;
+	  case 1:
+	    result = build1 (code, type, ops[0]);
+	    break;
+	  case 2:
+	    result = build2 (code, type, ops[0], ops[1]);
+	    break;
+	  case 3:
+	    result = build3 (code, type, ops[0], ops[1], ops[2]);
+	    break;
+	  case 4:
+	    result = build4 (code, type, ops[0], ops[1], ops[2], ops[3]);
+	    break;
+	  case 5:
+	    result = build5 (code, type, ops[0], ops[1], ops[2], ops[3], 
+			     ops[4]);
+	    break;
+	  case 7:
+	    result = build7 (code, type, ops[0], ops[1], ops[2], ops[3], 
+			     ops[4], ops[5], ops[6]);
+	    break;
+	  default:
+	    gcc_unreachable ();
+	  }
+      }
+      break;
+      /* This is the error case, these are type codes that will either
+	 never happen or that we have not gotten around to dealing
+	 with are here.  */
+    case BIND_EXPR:
+    case BLOCK:
+    case CATCH_EXPR:
+    case EH_FILTER_EXPR:
+    case NAME_MEMORY_TAG:
+    case OMP_CONTINUE:
+    case OMP_CRITICAL:
+    case OMP_FOR:
+    case OMP_MASTER:
+    case OMP_ORDERED:
+    case OMP_PARALLEL:
+    case OMP_RETURN:
+    case OMP_SECTIONS:
+    case OMP_SINGLE:
+    case SSA_NAME:
+    case STRUCT_FIELD_TAG:
+    case SYMBOL_MEMORY_TAG:
+    case TARGET_MEM_REF:
+    case TRY_CATCH_EXPR:
+    case TRY_FINALLY_EXPR:
+    default:
+      /* We cannot have forms that are not explicity handled.  So when
+	 this is triggered, there is some form that is not being
+	 output.  */
+      gcc_unreachable ();
+    }
+
+  LTO_DEBUG_UNDENT()
+  process_flags (result, flags);
+  return result;
+}
+
+
 /* Load in the global vars and all of the types from the main symbol
    table.  */
+
 static void
-load_globals (struct lto_function_header * header,
+input_globals (struct lto_function_header * header,
 	      lto_info_fd *fd,
 	      lto_context *context,	
 	      struct fun_in *fun_in, 
@@ -100,16 +912,359 @@ load_globals (struct lto_function_header
 	= lto_resolve_var_ref (fd, context, &in_var_decls[i]);
 
   for (i=0; i<header->num_types; i++)
-    if (in_types[i].section)
+    {
       fun_in->types[i]
 	= lto_resolve_type_ref (fd, context, &in_types[i]);
+      
+      fprintf (stderr, "type %d = ", i);
+      print_generic_expr (stderr, fun_in->types[i], TDF_VOPS|TDF_UID);
+      fprintf (stderr, "\n");
+      print_node (stderr, "", fun_in->types[i], 0);
+      fprintf (stderr, "\n\n");
+    }
+}
+
+
+/* Load NAMED_COUNT named labels and constuct UNNAMED_COUNT unnamed
+   labels from DATA segment SIZE bytes long using FUN_IN.  */
+
+static void 
+input_labels (struct fun_in *fun_in, const char *data, 
+	      unsigned int size, unsigned int named_count, 
+	      unsigned int unnamed_count)
+{
+  struct input_block ib = {data, 0, size};
+  unsigned int i;
+
+  /* The named and unnamed labels share the same array.  In the lto
+     code, the unnamed labels have a negative index.  Their position
+     in the array can be found by subtracting that index from the
+     number of named labels.  */
+  fun_in->labels = xcalloc (named_count + unnamed_count, sizeof (tree*));
+  for (i = 0; i < named_count; i++)
+    {
+      unsigned int name_index = input_uleb128 (&ib);
+      unsigned int len;
+      const char *s = input_string_internal (fun_in, name_index, &len);
+      tree name = get_identifier_with_length (s, len);
+      fun_in->labels[i] = build_decl (LABEL_DECL, name, void_type_node);
+    }
+
+  for (i = 0; i < unnamed_count; i++)
+    fun_in->labels[i + named_count] 
+      = build_decl (LABEL_DECL, NULL_TREE, void_type_node);
+ }
+
+/* Load COUNT local var_decls and parm_decls from a DATA segment SIZE
+   bytes long using FUN_IN.  */
+
+static void 
+input_local_vars (struct fun_in *fun_in, const char *data, 
+	     unsigned int size, unsigned int count)
+{
+  struct input_block ib = {data, 0, size};
+  unsigned int i;
+
+  fun_in->local_decls = xcalloc (count, sizeof (tree*));
+  for (i = 0; i < count; i++)
+    {
+      unsigned int tag = input_record_start (&ib);
+      unsigned int variant = tag & 0xF;
+      bool is_var = ((tag & 0xFFF0) == LTO_local_var_decl_body0);
+
+      unsigned int name_index;
+      tree name;
+      tree type;
+      unsigned HOST_WIDE_INT flags;
+      const char *new_file = NULL;
+      int new_line = -1;
+      tree result = fun_in->local_decls[i];
+
+      name_index = input_uleb128 (&ib);
+      if (name_index)
+	{
+	  unsigned int len;
+	  const char *s = input_string_internal (fun_in, name_index, &len);
+	  name = get_identifier_with_length (s, len);
+	}
+      else 
+	name = NULL_TREE;
+
+      type = get_type_ref (fun_in, &ib);
+
+      /* The result may not be NULL here because if any of the
+	 subtrees of some prior local var_decl referenced this local
+	 decl, a blank var decl would have been created and inserted
+	 here.  However, the normal case is that it will be NULL.  */ 
+      if (result == NULL)
+	{
+	  if (is_var)
+	    result = build_decl (VAR_DECL, name, type);
+	  else
+	    result = build_decl (PARM_DECL, name, type);
+	}
+      fun_in->local_decls[i] = result;
+
+      if (!is_var)
+	DECL_ARG_TYPE (result) = get_type_ref (fun_in, &ib);
+
+      LTO_DEBUG_TOKEN ("flags")
+      flags = input_uleb128 (&ib);
+
+      /* FIXME: Need to figure out how to set the line number.  */
+      if (flags & 0x2)
+	{
+	  unsigned int len;
+	  LTO_DEBUG_TOKEN ("file")
+	  new_file = input_string_internal (fun_in, input_uleb128 (&ib), &len);
+	}
+      if (flags & 0x1)
+	{
+	  LTO_DEBUG_TOKEN ("line")
+	  new_line = input_uleb128 (&ib);
+	}
+
+      LTO_DEBUG_TOKEN ("align")
+      DECL_ALIGN (result) = input_uleb128 (&ib);
+      LTO_DEBUG_TOKEN ("size")
+      DECL_SIZE (result) 
+	= input_expr_operand (&ib, fun_in, input_record_start (&ib));
+
+      if (variant & 0x1)
+	{
+	  LTO_DEBUG_TOKEN ("attributes")
+          DECL_ATTRIBUTES (result) 
+	    = input_expr_operand (&ib, fun_in, input_record_start (&ib));
+	}
+      if (variant & 0x2)
+	DECL_SIZE_UNIT (result) 
+	  = input_expr_operand (&ib, fun_in, input_record_start (&ib));
+      if (variant & 0x4)
+	SET_DECL_DEBUG_EXPR (result, 
+			     input_expr_operand (&ib, fun_in, 
+						 input_record_start (&ib)));
+      if (variant & 0x8)
+        DECL_ABSTRACT_ORIGIN (result) 
+	  = input_expr_operand (&ib, fun_in, input_record_start (&ib));
+
+      process_flags (result, flags);
+      LTO_DEBUG_UNDENT()
+    }
+}
+
+
+/* Read the exception table.  */
+
+static void
+input_eh_regions (struct input_block *ib, 
+		  struct function *fn ATTRIBUTE_UNUSED, 
+		  struct fun_in *fun_in ATTRIBUTE_UNUSED)
+{
+  /* Not ready to read exception records yet.  */
+  input_uleb128 (ib);
+}
+
+
+/* Make a new basic block at INDEX in FN.  */
+
+static basic_block
+make_new_block (struct function *fn, unsigned int index)
+{
+  basic_block bb = alloc_block ();
+  bb->index = index;
+  SET_BASIC_BLOCK_FOR_FUNCTION (fn, index, bb);
+  bb->stmt_list = alloc_stmt_list ();
+  bb->flags = 0;
+  return bb;
+}
+
+
+/* Read in the next basic block.  */
+
+static void
+input_bb (struct input_block *ib, unsigned int tag, 
+	  struct function *fn, struct fun_in *fun_in)
+{
+  unsigned int index;
+  unsigned int edge_count;
+  basic_block bb;
+  unsigned int i;
+  block_stmt_iterator bsi;
+
+  LTO_DEBUG_TOKEN ("bbindex")
+  index = input_uleb128 (ib);
+  LTO_DEBUG_TOKEN ("edgecount")
+  edge_count = input_uleb128 (ib);
+  bb = BASIC_BLOCK_FOR_FUNCTION (fn, index);
+  /* There are several reasons why the slot may already have a block.
+     Either it is the entry or exit block or else it was the
+     destination of a block that was created earlier.  */ 
+  if (bb == NULL)
+    make_new_block (fn, index);
+
+  /* Connect up the cfg.  */
+  for (i=0; i<edge_count; i++)
+    {
+      LTO_DEBUG_TOKEN ("dest")
+      unsigned int dest_index = input_uleb128 (ib);
+      LTO_DEBUG_TOKEN ("eflags")
+      unsigned int edge_flags = input_uleb128 (ib);
+      basic_block dest = BASIC_BLOCK_FOR_FUNCTION (fn, dest_index);
+      if (dest == NULL) 
+	dest = make_new_block (fn, dest_index);
+      make_edge (bb, dest, edge_flags);
+    }
+
+  /* LTO_bb1 has stmts, LTO_bb0 does not.  */
+  if (tag == LTO_bb0)
+    {
+      LTO_DEBUG_UNDENT()
+      return;
+    }
+
+  bsi = bsi_start (bb);
+  LTO_DEBUG_INDENT_TOKEN ("stmt")
+  tag = input_record_start (ib);
+  while (tag)
+    {
+      tree stmt = input_expr_operand (ib, fun_in, tag);
+      bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
+      LTO_DEBUG_INDENT_TOKEN ("stmt")
+      tag = input_record_start (ib);
+      /* FIXME, add code to handle the exception.  */
+    }
+  LTO_DEBUG_UNDENT()
+}
+
+
+/* Fill in the body of FN.  */
+
+static void
+input_function (tree fn_decl, struct fun_in *fun_in, 
+		const char *data, unsigned int size)
+{
+  struct function *fn = DECL_STRUCT_FUNCTION (fn_decl);
+  struct input_block ib = {data, 0, size};
+  unsigned int tag = input_record_start (&ib);
+  unsigned int last_bb_index;
+
+  tree_register_cfg_hooks ();
+  gcc_assert (tag == LTO_function);
+
+  input_eh_regions (&ib, fn, fun_in);
+
+  last_bb_index = input_uleb128 (&ib);
+  init_cfg (fn, last_bb_index);
+  tag = input_record_start (&ib);
+  while (tag)
+    {
+      input_bb (&ib, tag, fn, fun_in);
+      tag = input_record_start (&ib);
+    }
+
+  finalize_cfg (fn, last_bb_index);
+  LTO_DEBUG_UNDENT()
+}
+
+
+static bool initialized_local = false;
+
+/* Static initialization for the lto writer.  */
+
+static void
+lto_static_init_local (void)
+{
+  if (initialized_local)
+    return;
+
+  initialized_local = true;
+
+  /* Initialize the expression to tag mapping.  */
+#define MAP_EXPR_TAG(expr,tag)   tag_to_expr [tag] = expr;
+#define MAP_EXPR_TAGS(expr,tag,count) \
+  {                                   \
+    int i;                            \
+    for (i=0; i<count; i++)           \
+      tag_to_expr [tag + i] = expr;   \
+  }
+#define TREE_MULTIPLE
+#define TREE_SINGLE_MECHANICAL_TRUE
+#define TREE_SINGLE_MECHANICAL_FALSE
+#define SET_NAME(a,b)
+#include "lto-tree-tags.def"
+
+#undef MAP_EXPR_TAG
+#undef MAP_EXPR_TAGS
+#undef TREE_MULTIPLE
+#undef TREE_SINGLE_MECHANICAL_TRUE
+#undef TREE_SINGLE_MECHANICAL_FALSE
+#undef SET_NAME
+  /* Initialize num_flags_for_code.  */
+
+
+#define START_CLASS_SWITCH()                  \
+  {                                           \
+    int code;				      \
+    for (code=0; code<NUM_TREE_CODES; code++) \
+      {                                       \
+	/* The 2 leaves room for file and line number for exprs.  */ \
+	if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (code)))  \
+          num_flags_for_code[code] = 2;	      \
+	else                                  \
+          num_flags_for_code[code] = 0;	      \
+                                              \
+        switch (TREE_CODE_CLASS (code))       \
+          {
+
+#define START_CLASS_CASE(class)    case class:
+#define ADD_CLASS_FLAG(flag_name)    num_flags_for_code[code]++;
+#define END_CLASS_CASE(class)      break;
+#define END_CLASS_SWITCH()                    \
+          default:                            \
+            gcc_unreachable ();               \
+          }
+
+
+#define START_EXPR_SWITCH()                   \
+        switch (code)			      \
+          {
+#define START_EXPR_CASE(code)    case code:
+#define ADD_EXPR_FLAG(flag_name)    num_flags_for_code[code]++;
+#define ADD_DECL_FLAG(flag_name)    num_flags_for_code[code]++;
+#define END_EXPR_CASE(class)      break;
+#define END_EXPR_SWITCH()                     \
+          default:                            \
+            gcc_unreachable ();               \
+          }                                   \
+      }					      \
+  }
+
+#include "lto-tree-flags.def"
+
+#undef START_CLASS_SWITCH
+#undef START_CLASS_CASE
+#undef ADD_CLASS_FLAG
+#undef END_CLASS_CASE
+#undef END_CLASS_SWITCH
+#undef START_EXPR_SWITCH
+#undef START_EXPR_CASE
+#undef ADD_EXPR_FLAG
+#undef ADD_DECL_FLAG
+#undef END_EXPR_CASE
+#undef END_EXPR_SWITCH
+
+  lto_static_init ();
 }
 
 
+/* Read the body form DATA for function FN and fill it in.  FD and
+   CONTEXT are magic cookies used to resolve global decls and
+   types.  */
+ 
 void 
 lto_read_function_body (lto_info_fd *fd,
 			lto_context *context,
-			tree fn ATTRIBUTE_UNUSED,
+			tree fn_decl,
 			const void *data)
 {
   struct lto_function_header * header 
@@ -125,13 +1280,24 @@ lto_read_function_body (lto_info_fd *fd,
   int32_t types_offset 
     = vars_offset + 
     (header->num_var_decls * sizeof (lto_ref));
-
-#if 0
-  int32_t locals_offset 
+  int32_t named_labels_offset 
     = types_offset + 
     (header->num_types * sizeof (lto_ref));
+  int32_t locals_offset = named_labels_offset + header->named_label_size;
   int32_t main_offset = locals_offset + header->local_decls_size;
   int32_t string_offset = main_offset + header->main_size;
+
+#ifdef LTO_STREAM_DEBUGGING
+  int32_t debug_decl_offset = string_offset + header->string_size;
+  int32_t debug_label_offset = debug_decl_offset + header->debug_decl_size;
+  int32_t debug_main_offset = debug_label_offset + header->debug_label_size;
+
+  struct input_block debug_decl 
+    = {data + debug_decl_offset, 0, header->debug_decl_size};
+  struct input_block debug_label 
+    = {data + debug_label_offset, 0, header->debug_label_size};
+  struct input_block debug_main 
+    = {data + debug_main_offset, 0, header->debug_main_size};
 #endif
 
   lto_ref *in_field_decls = (lto_ref*)(data + fields_offset);
@@ -139,42 +1305,128 @@ lto_read_function_body (lto_info_fd *fd,
   lto_ref *in_var_decls   = (lto_ref*)(data + vars_offset);
   lto_ref *in_types       = (lto_ref*)(data + types_offset);
 
-#if 0
-  const char * local_decls = data + locals_offset;
-  const char * main_gimple = data + main_offset;
-  const char * strings     = data + string_offset;
+  const char * named_labels = data + named_labels_offset;
+  const char * local_decls  = data + locals_offset;
+  const char * main_gimple  = data + main_offset;
+
+#ifdef LTO_STREAM_DEBUGGING
+  lto_debug_context.out = debug_out_fun;
+  lto_debug_context.indent = 0;
+  lto_debug_context.current_data = &debug_label;
 #endif
 
+  fun_in.strings            = data + string_offset;
+  fun_in.strings_len        = header->string_size;
+
+  lto_static_init_local ();
+
   /* No upward compatibility here.  */
   gcc_assert (header->major_version == LTO_major_version);
   gcc_assert (header->minor_version == LTO_minor_version);
 
-  load_globals (header, fd, context, &fun_in, 
+  input_globals (header, fd, context, &fun_in, 
 		in_field_decls, in_fn_decls, 
 		in_var_decls, in_types);
-}
 
+  fun_in.num_named_labels = header->num_named_labels;
+  input_labels (&fun_in, named_labels, 
+		header->named_label_size, 
+		header->num_named_labels, header->num_unnamed_labels);
+
+#ifdef LTO_STREAM_DEBUGGING
+  lto_debug_context.current_data = &debug_decl;
+#endif
+  input_local_vars (&fun_in, local_decls, 
+		    header->local_decls_size, header->num_local_decls);
+
+#ifdef LTO_STREAM_DEBUGGING
+  lto_debug_context.current_data = &debug_main;
 #if 0
-void
-lto_read_function_body (lto_info_fd *fd ATTRIBUTE_UNUSED,
-			lto_context *context ATTRIBUTE_UNUSED,
-			tree fn,
-			const void *data ATTRIBUTE_UNUSED)
-{
-  tree return_expr;
-  tree stmt_list;
-  tree_stmt_iterator i;
-  tree body;
-
-  /* ??? For now, just pretend the function returns immediately.  */
-  return_expr = build1 (RETURN_EXPR, void_type_node, NULL_TREE);
-  stmt_list = alloc_stmt_list ();
-  i = tsi_start (stmt_list);
-  tsi_link_after (&i, return_expr, TSI_NEW_STMT);
-  body = build3 (BIND_EXPR, NULL_TREE, NULL_TREE, stmt_list, NULL_TREE);
-  DECL_SAVED_TREE (fn) = body;
-  DECL_INITIAL (fn) = make_node (BLOCK);
+  dump_debug_stream ((struct input_block *)lto_debug_context.current_data, 
+		     ' ', ' ');
+#endif
+#endif
+
+  /* Set up the struct function.  */
+  input_function (fn_decl, &fun_in, main_gimple, header->main_size);
+}
+
+
+/* Dump the debug STREAM, and two characters B and C.  */
+
+static void 
+dump_debug_stream (struct input_block *stream, char b, char c)
+{
+  unsigned int i = 0;
+  bool new_line = true;
+  int chars = 0;
+  int hit_pos = -1;
+  fprintf (stderr, 
+	   "stream failure: looking for '%c' found '%c' at stream->%d\n\n",
+	   c, b, stream->p);
+  
+  while (i < stream->len)
+    {
+      char x;
+      
+      if (new_line)
+	{
+	  if (hit_pos >= 0)
+	    {
+	      int j;
+	      fprintf (stderr, "             ");
+	      for (j=0; j<hit_pos; j++)
+		fputc (' ', stderr);
+	      fprintf (stderr, "^\n             ");
+	      for (j=0; j<hit_pos; j++)
+		fputc (' ', stderr);
+	      fprintf (stderr, "|\n");
+	      hit_pos = -1;
+	    }
+	  
+	  fprintf (stderr, "%6d   -->>", i);
+	  new_line = false;
+	  chars = 0;
+	}
+      
+      x = stream->data[i++];
+      if (x == '\n')
+	{
+	  fprintf (stderr, "<<--\n");
+	  new_line = true;
+	}
+      else 
+	fputc (x, stderr);
+      
+      if (i == stream->p)
+	hit_pos = chars;
+      chars++;
+    }
+}
+
+
+#ifdef LTO_STREAM_DEBUGGING
+
+/* The low level output routine to for a single character.  Unlike the
+   version on the writing side, this does interesting processing.
+
+   This call checks that the debugging information generated by
+   lto-function-out matches the debugging information generated by the
+   reader. Each character is checked and a call to abort is generated
+   when the first mismatch is found.  
+  */
+
+static void
+debug_out_fun (struct lto_debug_context *context, char c)
+{
+  struct input_block *stream = (struct input_block *)context->current_data;
+  unsigned char b = input_1_unsigned (stream);
 
-  return;
+  if (b != c)
+    {
+      dump_debug_stream (stream, b, c);
+      gcc_unreachable ();
+    }
 }
+    
 #endif
Index: print-tree.c
===================================================================
--- print-tree.c	(revision 117575)
+++ print-tree.c	(working copy)
@@ -198,21 +198,25 @@ print_node (FILE *file, const char *pref
       return;
     }
 
-  hash = ((unsigned long) node) % HASH_SIZE;
-
-  /* If node is in the table, just mention its address.  */
-  for (b = table[hash]; b; b = b->next)
-    if (b->node == node)
-      {
-	print_node_brief (file, prefix, node, indent);
-	return;
-      }
-
-  /* Add this node to the table.  */
-  b = XNEW (struct bucket);
-  b->node = node;
-  b->next = table[hash];
-  table[hash] = b;
+  /* Allow this function to be called if the table is not there.  */
+  if (table)
+    {
+      hash = ((unsigned long) node) % HASH_SIZE;
+      
+      /* If node is in the table, just mention its address.  */
+      for (b = table[hash]; b; b = b->next)
+	if (b->node == node)
+	  {
+	    print_node_brief (file, prefix, node, indent);
+	    return;
+	  }
+      
+      /* Add this node to the table.  */
+      b = XNEW (struct bucket);
+      b->node = node;
+      b->next = table[hash];
+      table[hash] = b;
+    }
 
   /* Indent to the specified column, since this is the long form.  */
   indent_to (file, indent);
Index: common.opt
===================================================================
--- common.opt	(revision 117575)
+++ common.opt	(working copy)
@@ -573,6 +573,10 @@ floop-optimize
 Common
 Does nothing.  Preserved for backward compatibility.
 
+flto
+Common Var(flag_generate_lto)
+Causes Link Time Optimization to be written into the object file. 
+
 fmath-errno
 Common Report Var(flag_errno_math) Init(1)
 Set errno after built-in math functions
Index: lto-stream-debug.c
===================================================================
--- lto-stream-debug.c	(revision 0)
+++ lto-stream-debug.c	(revision 0)
@@ -0,0 +1,150 @@
+/* LTO stream debugging.
+
+   Copyright 2006 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 "toplev.h"
+#include "flags.h"
+#include "params.h"
+#include "input.h"
+#include "debug.h"
+#include "lto-tags.h"
+#include <ctype.h>
+
+#ifdef LTO_STREAM_DEBUGGING
+
+
+/* Print VALUE to CONTEXT.  */
+
+static void
+lto_debug_string_internal (struct lto_debug_context *context, 
+		  const char *value, int len)
+{
+  int i;
+  for (i=0; i<len; i++)
+    context->out (context, value[i]);
+}
+
+
+/* Print VALUE in hex to CONTEXT.  */
+
+static void 
+lto_debug_wide_internal (struct lto_debug_context *context,
+			 HOST_WIDE_INT value)
+{
+  char buffer[100];
+  sprintf (buffer, HOST_WIDE_INT_PRINT_HEX, value);
+  lto_debug_string_internal (context, buffer, strlen (buffer));
+}
+
+
+/* Write TAG to CONTEXT and increment indent.  */
+
+void 
+lto_debug_indent (struct lto_debug_context *context, 
+		  int tag)
+{
+  int i;
+  const char *tag_name = LTO_tag_names[tag];
+  context->out (context, '\n');
+  for (i=0; i<context->indent; i++)
+    context->out (context, ' ');
+  context->out (context, '(');
+
+  lto_debug_string_internal (context, tag_name, strlen (tag_name));
+  lto_debug_string_internal (context, ":", 1);
+  context->indent++;
+}
+
+
+/* Write indented TAG to CONTEXT.  */
+
+void 
+lto_debug_indent_token (struct lto_debug_context *context, 
+			const char * value)
+{
+  int i;
+  context->out (context, '\n');
+  for (i=0; i<context->indent; i++)
+    context->out (context, ' ');
+  lto_debug_string_internal (context, value, strlen (value));
+}
+
+
+/* Write TAG, HIGH, and LOW to CONTEXT.  */
+
+void
+lto_debug_integer (struct lto_debug_context *context, 
+		   const char *tag, HOST_WIDE_INT high, 
+		   HOST_WIDE_INT low)
+{
+  lto_debug_string_internal (context, tag, strlen (tag));
+  lto_debug_wide_internal (context, high);
+  lto_debug_wide_internal (context, low);
+}
+
+
+/* Write the string VALUE surronded by quotes to CONTEXT.  */
+
+void
+lto_debug_string (struct lto_debug_context *context, 
+		  const char *value, int len)
+{
+  context->out (context, '"');
+  lto_debug_string_internal (context, value, len);
+  context->out (context, '"');
+}
+
+
+/* Write the string VALUE to CONTEXT.  */
+
+void
+lto_debug_token (struct lto_debug_context *context, 
+		 const char *value)
+{
+  lto_debug_string_internal (context, value, strlen (value));
+}
+
+
+/* Write ")\n" to CONTEXT and decrement indent.  */
+
+void
+lto_debug_undent (struct lto_debug_context *context)
+{
+  context->out (context, ')');
+  context->out (context, '\n');
+  context->indent--;
+}
+
+
+/* Write TAG and VALUE to CONTEXT.  */
+
+void
+lto_debug_wide (struct lto_debug_context *context, 
+		const char *tag, HOST_WIDE_INT value)
+{
+  lto_debug_string_internal (context, tag, strlen (tag));
+  lto_debug_wide_internal (context, value);
+}
+
+#endif
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 117575)
+++ Makefile.in	(working copy)
@@ -967,7 +967,7 @@ C_OBJS = c-lang.o stub-objc.o $(C_AND_OB
 
 # Language-independent object files.
 OBJS-common = \
- lto-function-out.o                                                                 \
+ lto-function-out.o lto-stream-debug.o                                     \
  double-int.o tree-chrec.o tree-scalar-evolution.o tree-data-ref.o	   \
  tree-cfg.o tree-dfa.o tree-eh.o tree-ssa.o tree-optimize.o tree-gimple.o  \
  gimplify.o tree-pretty-print.o tree-into-ssa.o				   \
@@ -1804,6 +1804,9 @@ convert.o: convert.c $(CONFIG_H) $(SYSTE
 
 double-int.o: double-int.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H)
 
+lto-stream-debug.o : lto-stream-debug.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
+   toplev.h $(FLAGS_H) $(PARAMS_H) input.h debug.h $(LTO_TAGS_H) \
+   lto-tree-flags.def lto-tree-tags.def 
 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 \
Index: basic-block.h
===================================================================
--- basic-block.h	(revision 117575)
+++ basic-block.h	(working copy)
@@ -397,9 +397,12 @@ struct control_flow_graph GTY(())
 #define n_edges_for_function(FN)	     ((FN)->cfg->x_n_edges)
 #define last_basic_block_for_function(FN)    ((FN)->cfg->x_last_basic_block)
 #define label_to_block_map_for_function(FN)  ((FN)->cfg->x_label_to_block_map)
+#define profile_status_for_function(FN)	     ((FN)->cfg->x_profile_status)
 
 #define BASIC_BLOCK_FOR_FUNCTION(FN,N) \
   (VEC_index (basic_block, basic_block_info_for_function(FN), (N)))
+#define SET_BASIC_BLOCK_FOR_FUNCTION(FN,N,BB) \
+  (VEC_replace (basic_block, basic_block_info_for_function(FN), (N), (BB)))
 
 /* Defines for textual backward source compatibility.  */
 #define ENTRY_BLOCK_PTR		(cfun->cfg->x_entry_block_ptr)
@@ -882,7 +885,7 @@ extern void guess_outgoing_edge_probabil
 extern void remove_predictions_associated_with_edge (edge);
 
 /* In flow.c */
-extern void init_flow (void);
+extern void init_flow (struct function *);
 extern void debug_bb (basic_block);
 extern basic_block debug_bb_n (int);
 extern void dump_regset (regset, FILE *);
Index: tree-cfg.c
===================================================================
--- tree-cfg.c	(revision 117575)
+++ tree-cfg.c	(working copy)
@@ -126,7 +126,7 @@ void
 init_empty_tree_cfg (void)
 {
   /* Initialize the basic block array.  */
-  init_flow ();
+  init_flow (cfun);
   profile_status = PROFILE_ABSENT;
   n_basic_blocks = NUM_FIXED_BLOCKS;
   last_basic_block = NUM_FIXED_BLOCKS;

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