diff mbox

[pph] Write language specific data (issue4331046)

Message ID 20110330212955.662811DA1B6@topo.tor.corp.google.com
State New
Headers show

Commit Message

Diego Novillo March 30, 2011, 9:29 p.m. UTC
This patch implements the writing of DECL_LANG_SPECIFIC fields.  It's
needed to write global_namespace.  The reading part is still
incomplete, but I wanted to flush this out before it got too big.

The main changes:

- We can now write out references to TEMPLATE_DECLs.  They are stored
  in the same index table as all other DECLs.  To implement this, I
  added a streamer hook that's called from lto_output_tree_ref.  When
  it does not recognize the decl, it calls the hook which tells it
  whether the decl can be added to the index table.

- We stream out everything in DECL_LANG_SPECIFIC, which in C++ is
  quite a bit.  This will cover global_namespace since it goes 
  through all the data stored for NAMESPACE_DECLs.

- Since DECL_LANG_SPECIFIC can contains tokens, we need to save token
  caches.  Since we are inside a streamer callback, we do not have a
  pointer to a PPH stream, so I've added a pretty hacky way of getting
  back to it.  When we initially open the PPH stream and associate
  with it an output_block object, I take an unused field from
  output_block and use it as my pointer back to the PPH stream.  This
  is awful, but it works for now.  I'll clean this up in a future
  patch.

The next patch will add the reader side, which will allow me to
reconstruct global_namespace.  This will uncover what other tree types
we need to handle.

With this I'm down to two failures in pph.exp.  No changes for
pth.exp.


ChangeLog.pph
2011-03-30  Diego Novillo  <dnovillo@google.com>

	* lto-streamer-in.c (lto_input_chain): Make extern.
	* lto-streamer-out.c (lto_output_tree_ref): Call
	streamer_hook->indexable_with_decls_p, if it exists.  If it
	returns true, emit a reference to EXPR in the VAR_DECL index.
	(lto_output_chain): Make extern.
	(lto_output_tree_pointers): Move checks for invalid gimple trees ...
	* lto-streamer.c (lto_is_streamable): ... here.
	* lto-streamer.h (lto_streamer_hooks): Add
	indexable_with_decls_p.
	(lto_output_chain): Declare.
	(lto_input_chain): Declare.


c-family/ChangeLog.pph
2011-03-30  Diego Novillo  <dnovillo@google.com>

	* c-family/c.opt (fpph-fmt): Remove.  Update all users.


cp/ChangeLog.pph
2011-03-30  Diego Novillo  <dnovillo@google.com>

	* cp-tree.h (struct language_function): Add prefix 'x_' to
	fields returns_value, returns_null, returns_abnormally,
	in_function_try_handler, in_base_initializer.  Update all
	users.
	* pph-streamer.c (pph_stream_write_ld_base): New.
	(pph_stream_write_ld_min): New.
	(pph_stream_write_tree_vec): New.
	(pph_stream_write_cxx_binding_1): New.
	(pph_stream_write_cxx_binding): New.
	(pph_stream_write_class_binding): New.
	(pph_stream_write_label_binding): New.
	(pph_stream_write_binding_level): New.
	(pph_stream_write_c_language_function): New.
	(pph_stream_write_language_function): New.
	(pph_stream_write_ld_fn): New.
	(pph_stream_write_ld_ns): New.
	(pph_stream_write_ld_parm): New.
	(pph_stream_write_lang_specific_data): New.
	(pph_indexable_with_decls_p): New.
	(pph_stream_hooks_init): Initialize h->indexable_with_decls_p
	with pph_indexable_with_decls_p.
	(pph_stream_begin_section): Do not free BLOCK.
	* pph-streamer.h (pth_save_token_cache): Declare.
	(pph_get_ob_stream): New.
	(pph_set_ob_stream): New.
	* pph.c (pth_save_token_cache): New.
	(pph_print_macro_defs_before): Remove.
	(pph_print_macro_defs_after): Remove.
	(pph_write_namespace): Remove.
	(pph_write_format): Remove.
	(pph_write_print): Remove.
	(pph_write_dump): Remove.
	(pph_write_symbol): Remove.
	(declvisitor): Remove.
	(pph_write_namespace_1): Remove.
	(pph_write_namespace): Remove.
	(pph_write_file_contents): Rename from pph_write_file_object.
	Output global_namespace.
	(pph_write_file): Call it.
	(pph_write_file_summary): Remove.
	(pph_read_file_contents): Rename from pph_file_read_object.
	(pph_read_file): Rename from pph_file_read.


--
This patch is available for review at http://codereview.appspot.com/4331046
diff mbox

Patch

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 54e7461..12d4f06 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -933,10 +933,6 @@  fpph-decls=
 C++ Joined RejectNegative UInteger Var(flag_pph_decls)
 -fpph-decls=N   Enable declaration identifier output at level N from PPH support
 
-fpph-fmt=
-C++ Joined RejectNegative UInteger Var(flag_pph_fmt)
--fpph-fmt=N   Output format is (0) normal (1) pretty summary (2) dump
-
 fpph-hdr=
 C++ ObjC++ Joined MissingArgError(missing filename after %qs)
 -fpph-hdr=<base-name>   A mapping from <base-name>.h to <base-name>.pph
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 6ef6e6e..aedcab2 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1012,11 +1012,11 @@  struct GTY(()) language_function {
   tree x_vtt_parm;
   tree x_return_value;
 
-  BOOL_BITFIELD returns_value : 1;
-  BOOL_BITFIELD returns_null : 1;
-  BOOL_BITFIELD returns_abnormally : 1;
-  BOOL_BITFIELD in_function_try_handler : 1;
-  BOOL_BITFIELD in_base_initializer : 1;
+  BOOL_BITFIELD x_returns_value : 1;
+  BOOL_BITFIELD x_returns_null : 1;
+  BOOL_BITFIELD x_returns_abnormally : 1;
+  BOOL_BITFIELD x_in_function_try_handler : 1;
+  BOOL_BITFIELD x_in_base_initializer : 1;
 
   /* True if this function can throw an exception.  */
   BOOL_BITFIELD can_throw : 1;
@@ -1067,23 +1067,23 @@  struct GTY(()) language_function {
 /* Set to 0 at beginning of a function definition, set to 1 if
    a return statement that specifies a return value is seen.  */
 
-#define current_function_returns_value cp_function_chain->returns_value
+#define current_function_returns_value cp_function_chain->x_returns_value
 
 /* Set to 0 at beginning of a function definition, set to 1 if
    a return statement with no argument is seen.  */
 
-#define current_function_returns_null cp_function_chain->returns_null
+#define current_function_returns_null cp_function_chain->x_returns_null
 
 /* Set to 0 at beginning of a function definition, set to 1 if
    a call to a noreturn function is seen.  */
 
 #define current_function_returns_abnormally \
-  cp_function_chain->returns_abnormally
+  cp_function_chain->x_returns_abnormally
 
 /* Nonzero if we are processing a base initializer.  Zero elsewhere.  */
-#define in_base_initializer cp_function_chain->in_base_initializer
+#define in_base_initializer cp_function_chain->x_in_base_initializer
 
-#define in_function_try_handler cp_function_chain->in_function_try_handler
+#define in_function_try_handler cp_function_chain->x_in_function_try_handler
 
 /* Expression always returned from function, or error_mark_node
    otherwise, for use by the automatic named return value optimization.  */
diff --git a/gcc/cp/pph-streamer.c b/gcc/cp/pph-streamer.c
index d2790fc..125c4e7 100644
--- a/gcc/cp/pph-streamer.c
+++ b/gcc/cp/pph-streamer.c
@@ -135,6 +135,421 @@  pph_stream_init_write (pph_stream *stream)
   lto_push_out_decl_state (stream->out_state);
   stream->decl_state_stream = XCNEW (struct lto_output_stream);
   stream->ob = create_output_block (LTO_section_decls);
+  pph_set_ob_stream (stream->ob, stream);
+}
+
+
+/* Write all the fields in lang_decl_base instance LDB to OB.  */
+
+static void
+pph_stream_write_ld_base (struct output_block *ob, struct lang_decl_base *ldb)
+{
+  struct bitpack_d bp;
+
+  if (ldb == NULL)
+    {
+      pph_output_uint (pph_get_ob_stream (ob), 0);
+      return;
+    }
+
+  bp = bitpack_create (ob->main_stream);
+  bp_pack_value (&bp, ldb->selector, 16);
+  bp_pack_value (&bp, ldb->language, 4);
+  bp_pack_value (&bp, ldb->use_template, 2);
+  bp_pack_value (&bp, ldb->not_really_extern, 1);
+  bp_pack_value (&bp, ldb->initialized_in_class, 1);
+  bp_pack_value (&bp, ldb->repo_available_p, 1);
+  bp_pack_value (&bp, ldb->threadprivate_or_deleted_p, 1);
+  bp_pack_value (&bp, ldb->anticipated_p, 1);
+  bp_pack_value (&bp, ldb->friend_attr, 1);
+  bp_pack_value (&bp, ldb->template_conv_p, 1);
+  bp_pack_value (&bp, ldb->odr_used, 1);
+  bp_pack_value (&bp, ldb->u2sel, 1);
+  lto_output_bitpack (&bp);
+}
+
+
+/* Write all the fields in lang_decl_min instance LDM to OB.  If REF_P
+   is true, all tree fields should be written as references.  */
+
+static void
+pph_stream_write_ld_min (struct output_block *ob, struct lang_decl_min *ldm,
+		         bool ref_p)
+{
+  if (ldm == 0)
+    {
+      pph_output_uint (pph_get_ob_stream (ob), 0);
+      return;
+    }
+
+  gcc_assert (ldm->base.selector == 0);
+
+  lto_output_tree_or_ref (ob, ldm->template_info, ref_p);
+  if (ldm->base.u2sel == 0)
+    lto_output_tree_or_ref (ob, ldm->u2.access, ref_p);
+  else if (ldm->base.u2sel == 1)
+    lto_output_sleb128_stream (ob->main_stream, ldm->u2.discriminator);
+  else
+    gcc_unreachable ();
+}
+
+
+/* Write all the trees in VEC V to OB.  REF_P is true if the trees should
+   be written as references.  */
+
+static void
+pph_stream_write_tree_vec (struct output_block *ob, VEC(tree,gc) *v, bool ref_p)
+{
+  unsigned i;
+  tree t;
+
+  lto_output_uleb128_stream (ob->main_stream, VEC_length (tree, v));
+  for (i = 0; VEC_iterate (tree, v, i, t); i++)
+    lto_output_tree_or_ref (ob, t, ref_p);
+}
+
+/* Forward declaration to break cyclic dependencies.  */
+static void pph_stream_write_binding_level (struct output_block *,
+					    struct cp_binding_level *, bool);
+
+
+/* Helper for pph_stream_write_cxx_binding.  OB, CB and REF_P are as in
+   pph_stream_write_cxx_binding.  */
+
+static void
+pph_stream_write_cxx_binding_1 (struct output_block *ob, cxx_binding *cb,
+				bool ref_p)
+{
+  struct bitpack_d bp;
+
+  if (cb == NULL)
+    {
+      pph_output_uint (pph_get_ob_stream (ob), 0);
+      return;
+    }
+
+  lto_output_tree_or_ref (ob, cb->value, ref_p);
+  lto_output_tree_or_ref (ob, cb->type, ref_p);
+  pph_stream_write_binding_level (ob, cb->scope, ref_p);
+  bp = bitpack_create (ob->main_stream);
+  bp_pack_value (&bp, cb->value_is_inherited, 1);
+  bp_pack_value (&bp, cb->is_local, 1);
+  lto_output_bitpack (&bp);
+}
+
+
+/* Write all the fields of cxx_binding instance CB to OB.  REF_P is
+   true if the tree fields should be written as references.  */
+
+static void
+pph_stream_write_cxx_binding (struct output_block *ob, cxx_binding *cb,
+			      bool ref_p)
+{
+  unsigned num_bindings;
+  cxx_binding *prev;
+
+  if (cb == NULL)
+    {
+      pph_output_uint (pph_get_ob_stream (ob), 0);
+      return;
+    }
+
+  for (num_bindings = 0, prev = cb->previous; prev; prev = prev->previous)
+    num_bindings++;
+
+  /* Write the list of previous bindings.  */
+  lto_output_sleb128_stream (ob->main_stream, num_bindings);
+  for (prev = cb->previous; prev; prev = prev->previous)
+    pph_stream_write_cxx_binding_1 (ob, prev, ref_p);
+
+  /* Write the current binding at the end.  */
+  pph_stream_write_cxx_binding_1 (ob, cb, ref_p);
+}
+
+
+/* Write all the fields of cp_class_binding instance CB to OB.  REF_P
+   is true if the tree fields should be written as references.  */
+
+static void
+pph_stream_write_class_binding (struct output_block *ob,
+				cp_class_binding *cb, bool ref_p)
+{
+  if (cb == NULL)
+    {
+      pph_output_uint (pph_get_ob_stream (ob), 0);
+      return;
+    }
+
+  pph_stream_write_cxx_binding (ob, &cb->base, ref_p);
+  lto_output_tree_or_ref (ob, cb->identifier, ref_p);
+}
+
+
+/* Write all the fields of cp_label_binding instance LB to OB.  If
+   REF_P is true, tree fields will be written as references.  */
+
+static void
+pph_stream_write_label_binding (struct output_block *ob,
+				cp_label_binding *lb, bool ref_p)
+{
+  if (lb == NULL)
+    {
+      pph_output_uint (pph_get_ob_stream (ob), 0);
+      return;
+    }
+
+  lto_output_tree_or_ref (ob, lb->label, ref_p);
+  lto_output_tree_or_ref (ob, lb->prev_value, ref_p);
+}
+
+
+/* Write all the fields of cp_binding_level instance BL to OB.  If
+   REF_P is true, tree fields will be written as references.  */
+
+static void
+pph_stream_write_binding_level (struct output_block *ob,
+			        struct cp_binding_level *bl, bool ref_p)
+{
+  unsigned i;
+  cp_class_binding *cs;
+  cp_label_binding *sl;
+  struct bitpack_d bp;
+
+  if (bl == NULL)
+    {
+      pph_output_uint (pph_get_ob_stream (ob), 0);
+      return;
+    }
+
+  lto_output_chain (ob, bl->names, ref_p);
+  lto_output_uleb128_stream (ob->main_stream, bl->names_size);
+  lto_output_chain (ob, bl->namespaces, ref_p);
+
+  pph_stream_write_tree_vec (ob, bl->static_decls, ref_p);
+
+  lto_output_chain (ob, bl->usings, ref_p);
+  lto_output_chain (ob, bl->using_directives, ref_p);
+
+  lto_output_uleb128_stream (ob->main_stream, VEC_length (cp_class_binding,
+					                  bl->class_shadowed));
+  for (i = 0; VEC_iterate (cp_class_binding, bl->class_shadowed, i, cs); i++)
+    pph_stream_write_class_binding (ob, cs, ref_p);
+
+  lto_output_tree_or_ref (ob, bl->type_shadowed, ref_p);
+
+  lto_output_uleb128_stream (ob->main_stream, VEC_length (cp_label_binding,
+					                  bl->shadowed_labels));
+  for (i = 0; VEC_iterate (cp_label_binding, bl->shadowed_labels, i, sl); i++)
+    pph_stream_write_label_binding (ob, sl, ref_p);
+
+  lto_output_chain (ob, bl->blocks, ref_p);
+  lto_output_tree_or_ref (ob, bl->this_entity, ref_p);
+  pph_stream_write_binding_level (ob, bl->level_chain, ref_p);
+  pph_stream_write_tree_vec (ob, bl->dead_vars_from_for, ref_p);
+  lto_output_chain (ob, bl->statement_list, ref_p);
+  lto_output_sleb128_stream (ob->main_stream, bl->binding_depth);
+
+  bp = bitpack_create (ob->main_stream);
+  bp_pack_value (&bp, bl->kind, 4);
+  bp_pack_value (&bp, bl->keep, 1);
+  bp_pack_value (&bp, bl->more_cleanups_ok, 1);
+  bp_pack_value (&bp, bl->have_cleanups, 1);
+  lto_output_bitpack (&bp);
+}
+
+
+/* Write all the fields of c_language_function instance CLF to OB.  If
+   REF_P is true, all tree fields should be written as references.  */
+
+static void
+pph_stream_write_c_language_function (struct output_block *ob,
+				      struct c_language_function *clf,
+				      bool ref_p)
+{
+  if (clf == NULL)
+    {
+      pph_output_uint (pph_get_ob_stream (ob), 0);
+      return;
+    }
+
+  lto_output_tree_or_ref (ob, clf->x_stmt_tree.x_cur_stmt_list, ref_p);
+  lto_output_sleb128_stream (ob->main_stream,
+			     clf->x_stmt_tree.stmts_are_full_exprs_p);
+}
+
+
+/* Write all the fields of language_function instance LF to OB.  If
+   REF_P is true, all tree fields should be written as references.  */
+
+static void
+pph_stream_write_language_function (struct output_block *ob,
+				    struct language_function *lf,
+				    bool ref_p)
+{
+  struct bitpack_d bp;
+
+  if (lf == NULL)
+    {
+      pph_output_uint (pph_get_ob_stream (ob), 0);
+      return;
+    }
+
+  pph_stream_write_c_language_function (ob, &lf->base, ref_p);
+  lto_output_tree_or_ref (ob, lf->x_cdtor_label, ref_p);
+  lto_output_tree_or_ref (ob, lf->x_current_class_ptr, ref_p);
+  lto_output_tree_or_ref (ob, lf->x_current_class_ref, ref_p);
+  lto_output_tree_or_ref (ob, lf->x_eh_spec_block, ref_p);
+  lto_output_tree_or_ref (ob, lf->x_in_charge_parm, ref_p);
+  lto_output_tree_or_ref (ob, lf->x_vtt_parm, ref_p);
+  lto_output_tree_or_ref (ob, lf->x_return_value, ref_p);
+  bp = bitpack_create (ob->main_stream);
+  bp_pack_value (&bp, lf->x_returns_value, 1);
+  bp_pack_value (&bp, lf->x_returns_null, 1);
+  bp_pack_value (&bp, lf->x_returns_abnormally, 1);
+  bp_pack_value (&bp, lf->x_in_function_try_handler, 1);
+  bp_pack_value (&bp, lf->x_in_base_initializer, 1);
+  bp_pack_value (&bp, lf->can_throw, 1);
+  lto_output_bitpack (&bp);
+
+  /* FIXME pph.  We are not writing lf->x_named_labels.  */
+
+  pph_stream_write_binding_level (ob, lf->bindings, ref_p);
+  pph_stream_write_tree_vec (ob, lf->x_local_names, ref_p);
+
+  /* FIXME pph.  We are not writing lf->extern_decl_map.  */
+}
+
+
+/* Write all the fields of lang_decl_fn instance LDF to OB.  If REF_P
+   is true, all tree fields should be written as references.  */
+
+static void
+pph_stream_write_ld_fn (struct output_block *ob, struct lang_decl_fn *ldf,
+			bool ref_p)
+{
+  struct bitpack_d bp;
+
+  if (ldf == NULL)
+    {
+      pph_output_uint (pph_get_ob_stream (ob), 0);
+      return;
+    }
+
+  bp = bitpack_create (ob->main_stream);
+  bp_pack_value (&bp, ldf->operator_code, 16);
+  bp_pack_value (&bp, ldf->global_ctor_p, 1);
+  bp_pack_value (&bp, ldf->global_dtor_p, 1);
+  bp_pack_value (&bp, ldf->constructor_attr, 1);
+  bp_pack_value (&bp, ldf->destructor_attr, 1);
+  bp_pack_value (&bp, ldf->assignment_operator_p, 1);
+  bp_pack_value (&bp, ldf->static_function, 1);
+  bp_pack_value (&bp, ldf->pure_virtual, 1);
+  bp_pack_value (&bp, ldf->defaulted_p, 1);
+  bp_pack_value (&bp, ldf->has_in_charge_parm_p, 1);
+  bp_pack_value (&bp, ldf->has_vtt_parm_p, 1);
+  bp_pack_value (&bp, ldf->pending_inline_p, 1);
+  bp_pack_value (&bp, ldf->nonconverting, 1);
+  bp_pack_value (&bp, ldf->thunk_p, 1);
+  bp_pack_value (&bp, ldf->this_thunk_p, 1);
+  bp_pack_value (&bp, ldf->hidden_friend_p, 1);
+  lto_output_bitpack (&bp);
+
+  lto_output_tree_or_ref (ob, ldf->befriending_classes, ref_p);
+  lto_output_tree_or_ref (ob, ldf->context, ref_p);
+
+  if (ldf->thunk_p == 0)
+    lto_output_tree_or_ref (ob, ldf->u5.cloned_function, ref_p);
+  else if (ldf->thunk_p == 1)
+    lto_output_sleb128_stream (ob->main_stream, ldf->u5.fixed_offset);
+  else
+    gcc_unreachable ();
+
+  if (ldf->pending_inline_p == 1)
+    pth_save_token_cache (ldf->u.pending_inline_info, pph_get_ob_stream (ob));
+  else if (ldf->pending_inline_p == 0)
+    pph_stream_write_language_function (ob, ldf->u.saved_language_function,
+					ref_p);
+}
+
+
+/* Write all the fields of lang_decl_ns instance LDNS to OB.  If REF_P
+   is true, all tree fields should be written as references.  */
+
+static void
+pph_stream_write_ld_ns (struct output_block *ob, struct lang_decl_ns *ldns,
+			bool ref_p)
+{
+  struct cp_binding_level *level;
+
+  if (ldns == NULL)
+    {
+      pph_output_uint (pph_get_ob_stream (ob), 0);
+      return;
+    }
+
+  level = ldns->level;
+  pph_stream_write_binding_level (ob, level, ref_p);
+}
+
+
+/* Write all the fields of lang_decl_parm instance LDP to OB.  If REF_P
+   is true, all tree fields should be written as references.  */
+
+static void
+pph_stream_write_ld_parm (struct output_block *ob, struct lang_decl_parm *ldp)
+{
+  if (ldp == NULL)
+    {
+      pph_output_uint (pph_get_ob_stream (ob), 0);
+      return;
+    }
+
+  lto_output_sleb128_stream (ob->main_stream, ldp->level);
+  lto_output_sleb128_stream (ob->main_stream, ldp->index);
+}
+
+
+/* Write all the lang-specific data in DECL to OB.  REF_P is true if
+   the trees referenced in lang-specific fields should be written as
+   references.  */
+
+static void
+pph_stream_write_lang_specific_data (struct output_block *ob,
+				     tree decl, bool ref_p)
+{
+  struct lang_decl *ld;
+  struct lang_decl_base *ldb;
+
+  gcc_assert (DECL_P (decl) && DECL_LANG_SPECIFIC (decl));
+
+  ld = DECL_LANG_SPECIFIC (decl);
+  ldb = &ld->u.base;
+
+  /* Write all the fields in lang_decl_base.  */
+  pph_stream_write_ld_base (ob, ldb);
+  
+  if (ldb->selector == 0)
+    {
+      /* Write all the fields in lang_decl_min.  */
+      pph_stream_write_ld_min (ob, &ld->u.min, ref_p);
+    }
+  else if (ldb->selector == 1)
+    {
+      /* Write all the fields in lang_decl_fn.  */
+      pph_stream_write_ld_fn (ob, &ld->u.fn, ref_p);
+    }
+  else if (ldb->selector == 2)
+    {
+      /* Write all the fields in lang_decl_ns.  */
+      pph_stream_write_ld_ns (ob, &ld->u.ns, ref_p);
+    }
+  else if (ldb->selector == 3)
+    {
+      /* Write all the fields in lang_decl_parm.  */
+      pph_stream_write_ld_parm (ob, &ld->u.parm);
+    }
+  else
+    gcc_unreachable ();
 }
 
 
@@ -145,8 +560,14 @@  pph_stream_init_write (pph_stream *stream)
 static void
 pph_stream_write_tree (struct output_block *ob, tree expr, bool ref_p)
 {
-  if (TREE_CODE (expr) == FUNCTION_DECL)
-    lto_output_tree_or_ref (ob, DECL_SAVED_TREE (expr), ref_p);
+  if (DECL_P (expr))
+    {
+      if (DECL_LANG_SPECIFIC (expr))
+	pph_stream_write_lang_specific_data (ob, expr, ref_p);
+
+      if (TREE_CODE (expr) == FUNCTION_DECL)
+	lto_output_tree_or_ref (ob, DECL_SAVED_TREE (expr), ref_p);
+    }
   else if (TREE_CODE (expr) == STATEMENT_LIST)
     {
       tree_stmt_iterator i;
@@ -222,6 +643,17 @@  pph_stream_unpack_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSED,
 }
 
 
+/* Return true if T can be emitted in the decls table as a reference.
+   This should only handle C++ specific declarations.  All others are
+   handled by the LTO streamer directly.  */
+
+static bool
+pph_indexable_with_decls_p (tree t)
+{
+  return TREE_CODE (t) == TEMPLATE_DECL;
+}
+
+
 /* Initialize all the streamer hooks used for streaming ASTs.  */
 
 static void
@@ -233,6 +665,7 @@  pph_stream_hooks_init (void)
   h->write_tree = pph_stream_write_tree;
   h->read_tree = pph_stream_read_tree;
   h->pack_value_fields = pph_stream_pack_value_fields;
+  h->indexable_with_decls_p = pph_indexable_with_decls_p;
   h->unpack_value_fields = pph_stream_unpack_value_fields;
 }
 
@@ -274,15 +707,13 @@  pph_stream_begin_section (const char *name ATTRIBUTE_UNUSED)
 
 
 /* Callback for lang_hooks.lto.append_data.  Write LEN bytes from DATA
-   into current_pph_file.  BLOCK is currently unused, but this hook is
-   required to free it.  */
+   into current_pph_file.  BLOCK is currently unused.  */
 
 static void
-pph_stream_write (const void *data, size_t len, void *block)
+pph_stream_write (const void *data, size_t len, void *block ATTRIBUTE_UNUSED)
 {
   if (data)
     fwrite (data, len, 1, current_pph_file);
-  free (block);
 }
 
 
diff --git a/gcc/cp/pph-streamer.h b/gcc/cp/pph-streamer.h
index afffe35..5d888b3 100644
--- a/gcc/cp/pph-streamer.h
+++ b/gcc/cp/pph-streamer.h
@@ -92,6 +92,9 @@  void pph_stream_trace_bytes (pph_stream *, const void *, size_t);
 void pph_stream_trace_string (pph_stream *, const char *);
 void pph_stream_trace_string_with_length (pph_stream *, const char *, unsigned);
 
+/* In pph.c.  FIXME move these to pph-streamer.c.  */
+struct cp_token_cache;
+extern void pth_save_token_cache (struct cp_token_cache *, pph_stream *);
 
 /* Inline functions.  */
 
@@ -195,4 +198,22 @@  pph_input_tree (pph_stream *stream ATTRIBUTE_UNUSED)
   return t;
 }
 
+/* Return the PPH stream object associated with output block OB.  */
+
+static inline pph_stream *
+pph_get_ob_stream (struct output_block *ob)
+{
+  /* FIXME pph - Do not overload OB fields this way.  */
+  return ((pph_stream *) ob->cfg_stream);
+}
+
+/* Set the PPH stream object F associated with output block OB.  */
+
+static inline void
+pph_set_ob_stream (struct output_block *ob, pph_stream *f)
+{
+  /* FIXME pph - Do not overload OB fields this way.  */
+  ob->cfg_stream = (struct lto_output_stream *) f;
+}
+
 #endif  /* GCC_CP_PPH_STREAMER_H  */
diff --git a/gcc/cp/pph.c b/gcc/cp/pph.c
index 8c46665..c397751 100644
--- a/gcc/cp/pph.c
+++ b/gcc/cp/pph.c
@@ -427,84 +427,44 @@  pth_save_token (cp_token *token, pph_stream *f)
   pth_save_token_value (f, token);
 }
 
+/* Save all the tokens in CACHE to PPH stream F.  */
 
-/* Write header information for IMAGE to STREAM.  */
-
-static void
-pth_write_header (pth_image *image, pph_stream *stream)
+void
+pth_save_token_cache (cp_token_cache *cache, pph_stream *f)
 {
-  const char *id = pth_id_str ();
+  unsigned i, num;
+  cp_token *tok;
 
-  if (!image->digest_computed_p)
+  if (cache == NULL)
     {
-      pth_get_md5_digest (image->fname, image->digest);
-      image->digest_computed_p = true;
+      pph_output_uint (f, 0);
+      return;
     }
 
-  pph_output_bytes (stream, id, strlen (id));
-  pph_output_bytes (stream, image->digest, DIGEST_LEN);
-}
-
-
-/* Pretty print the previous macro definitions in the table of IDENTIFIERS to
-   the STREAM. */
-
-static void
-pph_print_macro_defs_before (pph_stream *stream, cpp_idents_used *identifiers)
-{
-  unsigned int idx;
-
-  for (idx = 0; idx < identifiers->num_entries; ++idx)
-    {
-      cpp_ident_use *entry = identifiers->entries + idx;
-      const char *ident = entry->ident_str;
-      const char *before = entry->before_str;
+  for (num = 0, tok = cache->first; tok != cache->last; tok++)
+    num++;
 
-      if (before)
-	{
-	  pph_output_string (stream, "#define ");
-	  pph_output_string (stream, ident);
-	  pph_output_string (stream, before);
-	}
-      else
-	{
-	  pph_output_string (stream, "#undef ");
-	  pph_output_string (stream, ident);
-	}
-    }
+  pph_output_uint (f, num);
+  for (i = 0, tok = cache->first; i < num; tok++, i++)
+    pth_save_token (tok, f);
 }
 
 
-/* Pretty print the subsequent macro definitions in the table of IDENTIFIERS to
-   the STREAM. */
+/* Write header information for IMAGE to STREAM.  */
 
 static void
-pph_print_macro_defs_after (pph_stream *stream, cpp_idents_used *identifiers)
+pth_write_header (pth_image *image, pph_stream *stream)
 {
-  unsigned int idx;
+  const char *id = pth_id_str ();
 
-  for (idx = 0; idx < identifiers->num_entries; ++idx)
+  if (!image->digest_computed_p)
     {
-      cpp_ident_use *entry = identifiers->entries + idx;
-      const char *ident = entry->ident_str;
-      const char *before = entry->before_str;
-      const char *after = entry->after_str;
-
-      if (before != after)
-        {
-          if (after && (!before || strcmp (after, before) != 0))
-	    {
-	      pph_output_string (stream, "#define ");
-	      pph_output_string (stream, ident);
-	      pph_output_string (stream, after);
-	    }
-          else if (before)
-	    {
-	      pph_output_string (stream, "#undef ");
-	      pph_output_string (stream, ident);
-	    }
-        }
+      pth_get_md5_digest (image->fname, image->digest);
+      image->digest_computed_p = true;
     }
+
+  pph_output_bytes (stream, id, strlen (id));
+  pph_output_bytes (stream, image->digest, DIGEST_LEN);
 }
 
 
@@ -1841,105 +1801,13 @@  pth_file_change (cpp_reader *reader, const struct line_map *map)
 }
 
 
-/* Write PPH output file.  */
-
-typedef void (*pph_write_format)(pph_stream *stream, tree decl, int flags);
-
-/* Forward declarations to break cyclic references.  */
-static void
-pph_write_namespace (pph_stream *, tree, pph_write_format, int);
-
-
-/* Write symbol to PPH output file like C.  */
-
-static void
-pph_write_print (pph_stream *stream, tree decl, int flags ATTRIBUTE_UNUSED)
-{
-  pph_output_tree (stream, decl);
-}
-
-
-/* Write symbol to PPH output file as a dump.  */
-
-static void
-pph_write_dump (pph_stream *stream, tree decl, int flags)
-{
-  dump_node (decl, flags, stream->file);
-}
-
-
-/* Write symbol to PPH output file.  */
-
-static void
-pph_write_symbol (pph_stream *stream, tree decl, pph_write_format fmt,
-		  int flags)
-{
-  if (TREE_CODE (decl) == NAMESPACE_DECL)
-    pph_write_namespace (stream, decl, fmt, flags);
-  else if (!DECL_IS_BUILTIN (decl))
-    fmt (stream, decl, flags);
-}
-
-
-/* Write namespace to PPH output file.  */
-
-typedef void (*declvisitor)(pph_stream *, tree, pph_write_format, int);
-
-static void
-pph_write_namespace_1 (declvisitor vtor, pph_stream *stream, tree decl,
-                       pph_write_format fmt, int flags)
-{
-  tree prior = TREE_CHAIN (decl);
-  if (prior)
-    pph_write_namespace_1 (vtor, stream, prior, fmt, flags);
-  vtor (stream, decl, fmt, flags);
-}
-
-static void
-pph_write_namespace (pph_stream *stream, tree decl, pph_write_format fmt,
-		     int flags)
-{
-  struct cp_binding_level *level = NAMESPACE_LEVEL (decl);
-  decl = level->namespaces;
-  if (decl)
-    pph_write_namespace_1 (pph_write_namespace, stream, decl, fmt, flags);
-  decl = level->names;
-  if (decl)
-    pph_write_namespace_1 (pph_write_symbol, stream, decl, fmt, flags);
-}
-
-
 /* Write PPH output symbols and IDENTS_USED to STREAM as an object.  */
 
 static void
-pph_write_file_object (pph_stream *stream, cpp_idents_used *idents_used)
+pph_write_file_contents (pph_stream *stream, cpp_idents_used *idents_used)
 { 
-  int flags = 0;
   pth_save_identifiers (idents_used, stream);
-  pph_write_namespace (stream, global_namespace, pph_write_print, flags);
-}
-
-
-/* Write PPH output symbols and IDENTS_USED to STREAM as a pretty summary.  */
-
-static void
-pph_write_file_summary (pph_stream *stream, cpp_idents_used *idents_used)
-{ 
-  int flags = 0;
-  pph_print_macro_defs_before (stream, idents_used);
-  pph_write_namespace (stream, global_namespace, pph_write_print, flags);
-  pph_print_macro_defs_after (stream, idents_used);
-}
-
-
-/* Write PPH output symbols and IDENTS_USED to STREAM as a textual dump.  */
-
-static void
-pph_write_file_dump (pph_stream *stream, cpp_idents_used *idents_used)
-{ 
-  int flags = TDF_UID | TDF_LINENO;
-  pth_dump_identifiers (stream->file, idents_used);
-  pph_write_namespace (stream, global_namespace, pph_write_dump, flags);
+  pph_output_tree (stream, global_namespace);
 }
 
 
@@ -1959,17 +1827,8 @@  pph_write_file (void)
     fatal_error ("Cannot open PPH file for writing: %s: %m", pph_out_file);
 
   idents_used = cpp_lt_capture (parse_in);
+  pph_write_file_contents (stream, &idents_used);
 
-  if (flag_pph_fmt == 0)
-    pph_write_file_object (stream, &idents_used);
-  else if (flag_pph_fmt == 1)
-    pph_write_file_summary (stream, &idents_used);
-  else if (flag_pph_fmt == 2)
-    pph_write_file_dump (stream, &idents_used);
-  else
-    error ("unrecognized -fpph-fmt value: %d", flag_pph_fmt);
-
-  /*FIX pph: double free or corruption: cpp_lt_idents_destroy (&idents_used); */
   pph_stream_close (stream);
 }
 
@@ -2016,10 +1875,10 @@  report_validation_error (const char *filename,
 }
 
 
-/* Read PPH FILENAME from STREAM as an object.  */
+/* Read contents of PPH file in STREAM.  */
 
 static void
-pph_file_read_object (const char *filename, pph_stream *stream)
+pph_read_file_contents (pph_stream *stream)
 {
   bool verified;
   cpp_ident_use *bad_use;
@@ -2027,24 +1886,26 @@  pph_file_read_object (const char *filename, pph_stream *stream)
   cpp_idents_used idents_used;
 
   pth_load_identifiers (&idents_used, stream);
+
   /*FIXME pph: This validation is weak.  */
   verified = cpp_lt_verify_1 (parse_in, &idents_used, &bad_use, &cur_def, true);
   if (!verified)
-    report_validation_error (filename, bad_use->ident_str, cur_def,
+    report_validation_error (stream->name, bad_use->ident_str, cur_def,
                              bad_use->before_str, bad_use->after_str);
-  /* FIX pph: We cannot replay the macro definitions
+
+  /* FIXME pph: We cannot replay the macro definitions
      as long as we are still reading the actual file.
   cpp_lt_replay (parse_in, &idents_used);
   */
 
-  /* FIX pph: Also read decls.  */
+  /* FIXME pph: Also read decls.  */
 }
 
 
 /* Read PPH file.  */
 
 static void
-pph_file_read (const char *filename)
+pph_read_file (const char *filename)
 {
   pph_stream *stream;
 
@@ -2055,8 +1916,7 @@  pph_file_read (const char *filename)
   if (!stream)
     fatal_error ("Cannot open PPH file for reading: %s: %m", filename);
 
-  if (flag_pph_fmt == 0)
-    pph_file_read_object (filename, stream);
+  pph_read_file_contents (stream);
 
   pph_stream_close (stream);
 }
@@ -2113,7 +1973,7 @@  pph_include_handler (cpp_reader *reader,
 
   pph_file = query_pph_include_map (name);
   if (pph_file != NULL && !cpp_included_before (reader, name, input_location))
-    pph_file_read (pph_file);
+    pph_read_file (pph_file);
 }
 
 
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index 2347ffa..f982329 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -1889,7 +1889,7 @@  lto_materialize_tree (struct lto_input_block *ib, struct data_in *data_in,
 /* Read a chain of tree nodes from input block IB. DATA_IN contains
    tables and descriptors for the file being read.  */
 
-static tree
+tree
 lto_input_chain (struct lto_input_block *ib, struct data_in *data_in)
 {
   int i, count;
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index f41cf0c..24543b2 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -718,9 +718,20 @@  lto_output_tree_ref (struct output_block *ob, tree expr)
       break;
 
     default:
-      /* No other node is indexable, so it should have been handled
-	 by lto_output_tree.  */
-      gcc_unreachable ();
+      /* See if streamer hooks allows this node to be indexable with
+	 VAR_DECLs.  */
+      if (streamer_hooks ()->indexable_with_decls_p
+	  && streamer_hooks ()->indexable_with_decls_p (expr))
+	{
+	  output_record_start (ob, LTO_global_decl_ref);
+	  lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
+	}
+      else
+	{
+	  /* No other node is indexable, so it should have been
+	     handled by lto_output_tree.  */
+	  gcc_unreachable ();
+	}
     }
 }
 
@@ -742,7 +753,7 @@  lto_output_tree_or_ref (struct output_block *ob, tree expr, bool ref_p)
    to write to.  REF_P is true if chain elements should be emitted
    as references.  */
 
-static void
+void
 lto_output_chain (struct output_block *ob, tree t, bool ref_p)
 {
   int i, count;
@@ -1166,12 +1177,6 @@  lto_output_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
   if (CODE_CONTAINS_STRUCT (code, TS_EXP))
     lto_output_ts_exp_tree_pointers (ob, expr, ref_p);
 
-  if (CODE_CONTAINS_STRUCT (code, TS_SSA_NAME))
-    {
-      /* We only stream the version number of SSA names.  */
-      gcc_unreachable ();
-    }
-
   if (CODE_CONTAINS_STRUCT (code, TS_BLOCK))
     lto_output_ts_block_tree_pointers (ob, expr, ref_p);
 
@@ -1181,21 +1186,6 @@  lto_output_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
   if (CODE_CONTAINS_STRUCT (code, TS_CONSTRUCTOR))
     lto_output_ts_constructor_tree_pointers (ob, expr, ref_p);
 
-  if (CODE_CONTAINS_STRUCT (code, TS_STATEMENT_LIST))
-    {
-      /* This should only appear in GENERIC.  */
-      gcc_unreachable ();
-    }
-
-  if (CODE_CONTAINS_STRUCT (code, TS_OMP_CLAUSE))
-    {
-      /* This should only appear in High GIMPLE.  */
-      gcc_unreachable ();
-    }
-
-  if (CODE_CONTAINS_STRUCT (code, TS_OPTIMIZATION))
-    sorry ("gimple bytecode streams do not support the optimization attribute");
-
   if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION))
     lto_output_ts_target_option (ob, expr);
 
diff --git a/gcc/lto-streamer.c b/gcc/lto-streamer.c
index 7b51763..be8d36d 100644
--- a/gcc/lto-streamer.c
+++ b/gcc/lto-streamer.c
@@ -823,6 +823,8 @@  lto_is_streamable (tree expr)
 	 && code != BIND_EXPR
 	 && code != WITH_CLEANUP_EXPR
 	 && code != STATEMENT_LIST
+	 && code != OMP_CLAUSE
+	 && code != OPTIMIZATION_NODE
 	 && (code == CASE_LABEL_EXPR
 	     || code == DECL_EXPR
 	     || TREE_CODE_CLASS (code) != tcc_statement);
diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h
index 242850f..8e49a55 100644
--- a/gcc/lto-streamer.h
+++ b/gcc/lto-streamer.h
@@ -86,6 +86,11 @@  typedef struct lto_streamer_hooks {
      are as in lto_read_tree.  */
   void (*read_tree) (struct lto_input_block *, struct data_in *, tree);
 
+  /* Called by lto_output_tree_ref to determine if the given tree node
+     should be emitted as a reference to the table of declarations
+     (the same table that holds VAR_DECLs).  */
+  bool (*indexable_with_decls_p) (tree);
+
   /* Called by pack_value_fields to store any non-pointer fields
      in the tree structure.  The arguments are as in pack_value_fields.  */
   void (*pack_value_fields) (struct bitpack_d *, tree);
@@ -913,6 +918,7 @@  extern lto_streamer_hooks *streamer_hooks_init (void);
 extern void lto_input_cgraph (struct lto_file_decl_data *, const char *);
 extern void lto_reader_init (void);
 extern tree lto_input_tree (struct lto_input_block *, struct data_in *);
+extern tree lto_input_chain (struct lto_input_block *, struct data_in *);
 extern void lto_input_function_body (struct lto_file_decl_data *, tree,
 				     const char *);
 extern void lto_input_constructors_and_inits (struct lto_file_decl_data *,
@@ -934,6 +940,7 @@  extern struct output_block *create_output_block (enum lto_section_type);
 extern void destroy_output_block (struct output_block *);
 extern void lto_output_tree (struct output_block *, tree, bool);
 extern void lto_output_tree_or_ref (struct output_block *, tree, bool);
+extern void lto_output_chain (struct output_block *, tree, bool);
 extern void produce_asm (struct output_block *ob, tree fn);
 extern void lto_output_string (struct output_block *,
 			       struct lto_output_stream *,