diff mbox

[pph] Re-write streamer to use new generic tree streaming (issue4868041)

Message ID 20110811032334.394631DA19F@topo.tor.corp.google.com
State New
Headers show

Commit Message

Diego Novillo Aug. 11, 2011, 3:23 a.m. UTC
This patch applies on top of http://codereview.appspot.com/4863041/
It re-implements the PPH streamer to use the new tree streaming API.
This allows us to handle the pickle cache directly in PPH, on top of
which I am implementing the external referencing for decls.

The big changes are in pph_write_tree and pph_read_tree.  Instead of
being callbacks to handle parts of a tree node, they are in charge of
handling the whole tree.

Both pph_write_tree and pph_read_tree use pph_*_start_record() to put
every tree node in the pickle cache.  All the previous callbacks are
now embedded inside the routines dealing with the header and the body
of the tree.

The changes in the testsuite are needed because the ICEs in some
template test cases are now in a different location.

Tested on x86_64.  Committed to branch.


Diego.

 	* pph-streamer-in.c (pph_unpack_value_fields): Make static.
 	Move down in the file.
 	(pph_alloc_tree): Remove.
 	(pph_read_tree_body): Factor out of pph_read_tree.
 	Call lto_input_tree_pointers.
 	(pph_read_tree_header): New.
 	(pph_read_tree): Call pph_read_tree_header and
 	pph_read_tree_body.
 	* pph-streamer-out.c (pph_pack_value_fields): Make static.
 	Move down in the file.
 	(pph_out_tree_header): Remove.
 	(pph_write_tree_body): Factor out of pph_write_tree.
 	Call lto_output_tree_pointers.
 	(pph_write_tree_header): New.
 	(pph_write_tree): Call lto_output_builtin_tree,
 	pph_write_tree_header and pph_write_tree_body.
 	* pph-streamer.c (pph_is_streamable): Remove.
 	(pph_indexable_with_decls_p): Remove.
 	(pph_cache_preload): Rename from pph_preload_common_nodes.
 	Re-implement using pickle cache in struct pph_stream.
 	(pph_hooks_init): Remove setting for all removed hooks.
 	(pph_stream_open): Call pph_cache_preload.
 	(pph_cache_insert_at): Allow the same pointer to be at two
 	different cache locations.
 	(pph_cache_add): If IX_P is NULL, do not try to set it.
 	* pph-streamer.h (pph_pack_value_fields): Remove.
 	(pph_out_tree_header): Remove.
 	(pph_unpack_value_fields): Remove.
 	(pph_alloc_tree): Remove.
 	(pph_read_tree): Update prototype.
 	(pph_out_tree): Call pph_write_tree instead of lto_output_tree.
 	(pph_out_tree_array): Likewise.
 	(pph_out_tree_or_ref_1): Likewise.
 	(pph_out_tree_VEC): Likewise.
 	(pph_in_tree): Call pph_read_tree instead of lto_input_tree.
 	(pph_in_tree_array): Likewise.
 	(pph_in_tree_VEC): Likewise.

testsuite/ChangeLog.pph
	* g++.dg/pph/x1tmplclass2.cc: Update expected ICE message.
	* g++.dg/pph/x4tmplclass2.cc: Likewise.
	* g++.dg/pph/z4tmplclass2.cc: Likewise.
---
 gcc/cp/pph-streamer-in.c                 |  205 ++++++++++++++++++++----------
 gcc/cp/pph-streamer-out.c                |  175 +++++++++++++++++---------
 gcc/cp/pph-streamer.c                    |   81 ++++--------
 gcc/cp/pph-streamer.h                    |   21 +--
 gcc/testsuite/g++.dg/pph/x1tmplclass2.cc |    2 +-
 gcc/testsuite/g++.dg/pph/x4tmplclass2.cc |    2 +-
 gcc/testsuite/g++.dg/pph/z4tmplclass2.cc |    2 +-
 9 files changed, 336 insertions(+), 198 deletions(-)
diff mbox

Patch

diff --git a/gcc/cp/pph-streamer-in.c b/gcc/cp/pph-streamer-in.c
index fcf1c12..92bfac0 100644
--- a/gcc/cp/pph-streamer-in.c
+++ b/gcc/cp/pph-streamer-in.c
@@ -72,44 +72,6 @@  static VEC(char_p,heap) *string_tables = NULL;
    which every streamed in token must add to it's serialized source_location. */
 static int pph_loc_offset;
 
-/* Callback for unpacking value fields in ASTs.  BP is the bitpack 
-   we are unpacking from.  EXPR is the tree to unpack.  */
-
-void
-pph_unpack_value_fields (struct bitpack_d *bp, tree expr)
-{
-  if (TYPE_P (expr))
-    {
-      TYPE_LANG_FLAG_0 (expr) = bp_unpack_value (bp, 1);
-      TYPE_LANG_FLAG_1 (expr) = bp_unpack_value (bp, 1);
-      TYPE_LANG_FLAG_2 (expr) = bp_unpack_value (bp, 1);
-      TYPE_LANG_FLAG_3 (expr) = bp_unpack_value (bp, 1);
-      TYPE_LANG_FLAG_4 (expr) = bp_unpack_value (bp, 1);
-      TYPE_LANG_FLAG_5 (expr) = bp_unpack_value (bp, 1);
-      TYPE_LANG_FLAG_6 (expr) = bp_unpack_value (bp, 1);
-    }
-  else if (DECL_P (expr))
-    {
-      DECL_LANG_FLAG_0 (expr) = bp_unpack_value (bp, 1);
-      DECL_LANG_FLAG_1 (expr) = bp_unpack_value (bp, 1);
-      DECL_LANG_FLAG_2 (expr) = bp_unpack_value (bp, 1);
-      DECL_LANG_FLAG_3 (expr) = bp_unpack_value (bp, 1);
-      DECL_LANG_FLAG_4 (expr) = bp_unpack_value (bp, 1);
-      DECL_LANG_FLAG_5 (expr) = bp_unpack_value (bp, 1);
-      DECL_LANG_FLAG_6 (expr) = bp_unpack_value (bp, 1);
-      DECL_LANG_FLAG_7 (expr) = bp_unpack_value (bp, 1);
-      DECL_LANG_FLAG_8 (expr) = bp_unpack_value (bp, 1);
-    }
-
-  TREE_LANG_FLAG_0 (expr) = bp_unpack_value (bp, 1);
-  TREE_LANG_FLAG_1 (expr) = bp_unpack_value (bp, 1);
-  TREE_LANG_FLAG_2 (expr) = bp_unpack_value (bp, 1);
-  TREE_LANG_FLAG_3 (expr) = bp_unpack_value (bp, 1);
-  TREE_LANG_FLAG_4 (expr) = bp_unpack_value (bp, 1);
-  TREE_LANG_FLAG_5 (expr) = bp_unpack_value (bp, 1);
-  TREE_LANG_FLAG_6 (expr) = bp_unpack_value (bp, 1);
-}
-
 
 /* Read into memory the contents of the file in STREAM.  Initialize
    internal tables and data structures needed to re-construct the
@@ -978,28 +940,6 @@  pph_in_lang_specific (pph_stream *stream, tree decl)
 }
 
 
-/* Allocate a tree node with code CODE.  IB and DATA_IN are used to
-   read more data from the stream, if needed to build this node.
-   Return NULL if we did not want to handle this node.  In that case,
-   the caller will call make_node to allocate this tree.  */
-
-tree
-pph_alloc_tree (enum tree_code code,
-	               struct lto_input_block *ib ATTRIBUTE_UNUSED,
-		       struct data_in *data_in)
-{
-  pph_stream *stream = (pph_stream *) data_in->sdata;
-
-  if (code == CALL_EXPR)
-    {
-      unsigned nargs = pph_in_uint (stream);
-      return build_vl_exp (CALL_EXPR, nargs + 3);
-    }
-
-  return NULL_TREE;
-}
-
-
 /* Read all the fields in lang_type_header instance LTH from STREAM.  */
 
 static void
@@ -1640,17 +1580,19 @@  pph_in_function_decl (pph_stream *stream, tree fndecl)
 }
 
 
-/* Callback for reading ASTs from a stream.  This reads all the fields
-   that are not processed by default by the common tree pickler.
-   IB, DATA_IN are as in lto_read_tree.  EXPR is the partially materialized
-   tree.  */
 
-void
-pph_read_tree (struct lto_input_block *ib ATTRIBUTE_UNUSED,
-	       struct data_in *data_in, tree expr)
+/* Read the body fields of EXPR from STREAM.  */
+
+static void
+pph_read_tree_body (pph_stream *stream, tree expr)
 {
-  pph_stream *stream = (pph_stream *) data_in->sdata;
+  struct lto_input_block *ib = stream->encoder.r.ib;
+  struct data_in *data_in = stream->encoder.r.data_in;
 
+  /* Read the language-independent parts of EXPR's body.  */
+  lto_input_tree_pointers (ib, data_in, expr);
+
+  /* Read all the language-dependent fields.  */
   switch (TREE_CODE (expr))
     {
     /* TREES NEEDING EXTRA WORK */
@@ -1959,3 +1901,130 @@  pph_read_tree (struct lto_input_block *ib ATTRIBUTE_UNUSED,
                  tree_code_name[TREE_CODE (expr)]);
     }
 }
+
+
+/* Unpack language-dependent bitfields from BP into EXPR.  */
+
+static void
+pph_unpack_value_fields (struct bitpack_d *bp, tree expr)
+{
+  if (TYPE_P (expr))
+    {
+      TYPE_LANG_FLAG_0 (expr) = bp_unpack_value (bp, 1);
+      TYPE_LANG_FLAG_1 (expr) = bp_unpack_value (bp, 1);
+      TYPE_LANG_FLAG_2 (expr) = bp_unpack_value (bp, 1);
+      TYPE_LANG_FLAG_3 (expr) = bp_unpack_value (bp, 1);
+      TYPE_LANG_FLAG_4 (expr) = bp_unpack_value (bp, 1);
+      TYPE_LANG_FLAG_5 (expr) = bp_unpack_value (bp, 1);
+      TYPE_LANG_FLAG_6 (expr) = bp_unpack_value (bp, 1);
+    }
+  else if (DECL_P (expr))
+    {
+      DECL_LANG_FLAG_0 (expr) = bp_unpack_value (bp, 1);
+      DECL_LANG_FLAG_1 (expr) = bp_unpack_value (bp, 1);
+      DECL_LANG_FLAG_2 (expr) = bp_unpack_value (bp, 1);
+      DECL_LANG_FLAG_3 (expr) = bp_unpack_value (bp, 1);
+      DECL_LANG_FLAG_4 (expr) = bp_unpack_value (bp, 1);
+      DECL_LANG_FLAG_5 (expr) = bp_unpack_value (bp, 1);
+      DECL_LANG_FLAG_6 (expr) = bp_unpack_value (bp, 1);
+      DECL_LANG_FLAG_7 (expr) = bp_unpack_value (bp, 1);
+      DECL_LANG_FLAG_8 (expr) = bp_unpack_value (bp, 1);
+    }
+
+  TREE_LANG_FLAG_0 (expr) = bp_unpack_value (bp, 1);
+  TREE_LANG_FLAG_1 (expr) = bp_unpack_value (bp, 1);
+  TREE_LANG_FLAG_2 (expr) = bp_unpack_value (bp, 1);
+  TREE_LANG_FLAG_3 (expr) = bp_unpack_value (bp, 1);
+  TREE_LANG_FLAG_4 (expr) = bp_unpack_value (bp, 1);
+  TREE_LANG_FLAG_5 (expr) = bp_unpack_value (bp, 1);
+  TREE_LANG_FLAG_6 (expr) = bp_unpack_value (bp, 1);
+}
+
+
+/* Read a tree header from STREAM and allocate a memory instance for it.
+   Store the new tree in *EXPR_P and write it into the pickle cache at
+   slot IX.
+
+   The return code will indicate whether the caller needs to keep
+   reading the body for *EXPR_P.  Some trees are simple enough that
+   they are completely contained in the header.  In these cases, no
+   more reading is necessary, so we return true.  Otherwise, return
+   false to indicate that the caller should read the body of the tree.  */
+
+static bool
+pph_read_tree_header (pph_stream *stream, tree *expr_p, unsigned ix)
+{
+  enum LTO_tags tag;
+  bool fully_read_p;
+  struct lto_input_block *ib = stream->encoder.r.ib;
+  struct data_in *data_in = stream->encoder.r.data_in;
+
+  tag = input_record_start (ib);
+  gcc_assert ((unsigned) tag < (unsigned) LTO_NUM_TAGS);
+
+  if (tag == LTO_builtin_decl)
+    {
+      /* If we are going to read a built-in function, all we need is
+	 the code and class.  */
+      *expr_p = lto_get_builtin_tree (ib, data_in);
+      fully_read_p = true;
+    }
+  else if (tag == lto_tree_code_to_tag (INTEGER_CST))
+    {
+      /* For integer constants we only need the type and its hi/low
+	 words.  */
+      *expr_p = lto_input_integer_cst (ib, data_in);
+      fully_read_p = true;
+    }
+  else
+    {
+      struct bitpack_d bp;
+
+      /* Otherwise, materialize a new node from IB.  This will also read
+	 all the language-independent bitfields for the new tree.  */
+      *expr_p = lto_materialize_tree (ib, data_in, tag);
+
+      /* Read the language-independent bitfields for *EXPR_P.  */
+      bp = tree_read_bitfields (ib, *expr_p);
+
+      /* Unpack all language-dependent bitfields.  */
+      pph_unpack_value_fields (&bp, *expr_p);
+
+      fully_read_p = false;
+    }
+
+  /* Add *EXPR_P to the pickle cache at slot IX.  */
+  pph_register_shared_data (stream, *expr_p, ix);
+
+  return fully_read_p;
+}
+
+
+/* Callback for reading ASTs from a stream.  Instantiate and return a
+   new tree from the PPH stream in DATA_IN.  */
+
+tree
+pph_read_tree (struct lto_input_block *ib ATTRIBUTE_UNUSED,
+	       struct data_in *data_in)
+{
+  pph_stream *stream = (pph_stream *) data_in->sdata;
+  tree expr;
+  bool fully_read_p;
+  enum pph_record_marker marker;
+  unsigned ix;
+
+  marker = pph_in_start_record (stream, &ix);
+  if (marker == PPH_RECORD_END)
+    return NULL;
+  else if (marker == PPH_RECORD_SHARED)
+    return (tree) pph_in_shared_data (stream, ix);
+
+  /* We did not find the tree in the pickle cache, allocate the tree by
+     reading the header fields (different tree nodes need to be
+     allocated in different ways).  */
+  fully_read_p = pph_read_tree_header (stream, &expr, ix);
+  if (!fully_read_p)
+    pph_read_tree_body (stream, expr);
+
+  return expr;
+}
diff --git a/gcc/cp/pph-streamer-out.c b/gcc/cp/pph-streamer-out.c
index a79efab..faa7211 100644
--- a/gcc/cp/pph-streamer-out.c
+++ b/gcc/cp/pph-streamer-out.c
@@ -39,44 +39,6 @@  along with GCC; see the file COPYING3.  If not see
    cp_rest_of_decl_compilation).  */
 static pph_stream *pph_out_stream = NULL;
 
-/* Callback for packing value fields in ASTs.  BP is the bitpack 
-   we are packing into.  EXPR is the tree to pack.  */
-
-void
-pph_pack_value_fields (struct bitpack_d *bp, tree expr)
-{
-  if (TYPE_P (expr))
-    {
-      bp_pack_value (bp, TYPE_LANG_FLAG_0 (expr), 1);
-      bp_pack_value (bp, TYPE_LANG_FLAG_1 (expr), 1);
-      bp_pack_value (bp, TYPE_LANG_FLAG_2 (expr), 1);
-      bp_pack_value (bp, TYPE_LANG_FLAG_3 (expr), 1);
-      bp_pack_value (bp, TYPE_LANG_FLAG_4 (expr), 1);
-      bp_pack_value (bp, TYPE_LANG_FLAG_5 (expr), 1);
-      bp_pack_value (bp, TYPE_LANG_FLAG_6 (expr), 1);
-    }
-  else if (DECL_P (expr))
-    {
-      bp_pack_value (bp, DECL_LANG_FLAG_0 (expr), 1);
-      bp_pack_value (bp, DECL_LANG_FLAG_1 (expr), 1);
-      bp_pack_value (bp, DECL_LANG_FLAG_2 (expr), 1);
-      bp_pack_value (bp, DECL_LANG_FLAG_3 (expr), 1);
-      bp_pack_value (bp, DECL_LANG_FLAG_4 (expr), 1);
-      bp_pack_value (bp, DECL_LANG_FLAG_5 (expr), 1);
-      bp_pack_value (bp, DECL_LANG_FLAG_6 (expr), 1);
-      bp_pack_value (bp, DECL_LANG_FLAG_7 (expr), 1);
-      bp_pack_value (bp, DECL_LANG_FLAG_8 (expr), 1);
-    }
-
-  bp_pack_value (bp, TREE_LANG_FLAG_0 (expr), 1);
-  bp_pack_value (bp, TREE_LANG_FLAG_1 (expr), 1);
-  bp_pack_value (bp, TREE_LANG_FLAG_2 (expr), 1);
-  bp_pack_value (bp, TREE_LANG_FLAG_3 (expr), 1);
-  bp_pack_value (bp, TREE_LANG_FLAG_4 (expr), 1);
-  bp_pack_value (bp, TREE_LANG_FLAG_5 (expr), 1);
-  bp_pack_value (bp, TREE_LANG_FLAG_6 (expr), 1);
-}
-
 
 /* Initialize buffers and tables in STREAM for writing.  */
 
@@ -1378,20 +1340,6 @@  pph_write_file (pph_stream *stream)
 }
 
 
-/* Write header information for some AST nodes not handled by the
-   common streamer code.  EXPR is the tree to write to output block
-   OB.  If EXPR does not need to be handled specially, do nothing.  */
-
-void
-pph_out_tree_header (struct output_block *ob, tree expr)
-{
-  pph_stream *stream = (pph_stream *) ob->sdata;
-
-  if (TREE_CODE (expr) == CALL_EXPR)
-    pph_out_uint (stream, call_expr_nargs (expr));
-}
-
-
 /* Emit the fields of FUNCTION_DECL FNDECL to STREAM.  */
 
 static void
@@ -1410,16 +1358,23 @@  pph_out_function_decl (pph_stream *stream, tree fndecl)
 }
 
 
-/* Callback for writing ASTs to a stream.  This writes all the fields
-   that are not processed by default by the common tree pickler.
-   OB is as in lto_write_tree.  EXPR is the tree to write.  */
+/* Write the body of EXPR to STREAM.  This writes out all fields not
+   written by the generic tree streaming routines.  */
 
-void
-pph_write_tree (struct output_block *ob, tree expr,
-		bool ref_p ATTRIBUTE_UNUSED)
+static void
+pph_write_tree_body (pph_stream *stream, tree expr)
 {
-  pph_stream *stream = (pph_stream *) ob->sdata;
+  /* Write the language-independent parts of EXPR's body.  */
+  lto_output_tree_pointers (stream->encoder.w.ob, expr, false);
 
+  /* The following trees have language-dependent information that is
+     not written by the generic tree streaming routines.  Handle them
+     here.
+
+     FIXME pph.  This could be handled using TS_* markers in
+     treestruct.def but those markers are not complete.  To fix this,
+     embed the TS_* directly in the tree node definitions in tree.def
+     and cp/cp-tree.def.  */
   switch (TREE_CODE (expr))
     {
     /* TREES NEEDING EXTRA WORK */
@@ -1733,6 +1688,108 @@  pph_write_tree (struct output_block *ob, tree expr,
 }
 
 
+/* Pack all the bitfields of EXPR into BP.  */
+
+static void
+pph_pack_value_fields (struct bitpack_d *bp, tree expr)
+{
+  /* First pack all the language-independent bitfields.  */
+  pack_value_fields (bp, expr);
+
+  /* Now pack all the bitfields not handled by the generic packer.  */
+  if (TYPE_P (expr))
+    {
+      bp_pack_value (bp, TYPE_LANG_FLAG_0 (expr), 1);
+      bp_pack_value (bp, TYPE_LANG_FLAG_1 (expr), 1);
+      bp_pack_value (bp, TYPE_LANG_FLAG_2 (expr), 1);
+      bp_pack_value (bp, TYPE_LANG_FLAG_3 (expr), 1);
+      bp_pack_value (bp, TYPE_LANG_FLAG_4 (expr), 1);
+      bp_pack_value (bp, TYPE_LANG_FLAG_5 (expr), 1);
+      bp_pack_value (bp, TYPE_LANG_FLAG_6 (expr), 1);
+    }
+  else if (DECL_P (expr))
+    {
+      bp_pack_value (bp, DECL_LANG_FLAG_0 (expr), 1);
+      bp_pack_value (bp, DECL_LANG_FLAG_1 (expr), 1);
+      bp_pack_value (bp, DECL_LANG_FLAG_2 (expr), 1);
+      bp_pack_value (bp, DECL_LANG_FLAG_3 (expr), 1);
+      bp_pack_value (bp, DECL_LANG_FLAG_4 (expr), 1);
+      bp_pack_value (bp, DECL_LANG_FLAG_5 (expr), 1);
+      bp_pack_value (bp, DECL_LANG_FLAG_6 (expr), 1);
+      bp_pack_value (bp, DECL_LANG_FLAG_7 (expr), 1);
+      bp_pack_value (bp, DECL_LANG_FLAG_8 (expr), 1);
+    }
+
+  bp_pack_value (bp, TREE_LANG_FLAG_0 (expr), 1);
+  bp_pack_value (bp, TREE_LANG_FLAG_1 (expr), 1);
+  bp_pack_value (bp, TREE_LANG_FLAG_2 (expr), 1);
+  bp_pack_value (bp, TREE_LANG_FLAG_3 (expr), 1);
+  bp_pack_value (bp, TREE_LANG_FLAG_4 (expr), 1);
+  bp_pack_value (bp, TREE_LANG_FLAG_5 (expr), 1);
+  bp_pack_value (bp, TREE_LANG_FLAG_6 (expr), 1);
+}
+
+
+/* Write the header fields for EXPR to STREAM.  This header contains
+   all the data needed to rematerialize EXPR on the reader side and
+   a bitpack with all the bitfield values in EXPR.  */
+
+static void
+pph_write_tree_header (pph_stream *stream, tree expr)
+{
+  struct bitpack_d bp;
+  struct output_block *ob = stream->encoder.w.ob;
+
+  /* Write the header, containing everything needed to materialize EXPR
+     on the reading side.  */
+  lto_output_tree_header (ob, expr);
+
+  /* Pack all the non-pointer fields in EXPR into a bitpack and write
+     the resulting bitpack.  */
+  bp = bitpack_create (ob->main_stream);
+  pph_pack_value_fields (&bp, expr);
+  pph_out_bitpack (stream, &bp);
+}
+
+
+/* Callback for writing ASTs to a stream.  Write EXPR to the PPH stream
+   in OB.  */
+
+void
+pph_write_tree (struct output_block *ob, tree expr, bool ref_p ATTRIBUTE_UNUSED)
+{
+  pph_stream *stream = (pph_stream *) ob->sdata;
+
+  /* If EXPR is NULL or it already existed in the pickle cache,
+     nothing else needs to be done.  */
+  if (!pph_out_start_record (stream, expr))
+    return;
+
+  if (lto_stream_as_builtin_p (expr))
+    {
+      /* MD and NORMAL builtins do not need to be written out
+	 completely as they are always instantiated by the
+	 compiler on startup.  The only builtins that need to
+	 be written out are BUILT_IN_FRONTEND.  For all other
+	 builtins, we simply write the class and code.  */
+      lto_output_builtin_tree (ob, expr);
+    }
+  else if (TREE_CODE (expr) == INTEGER_CST)
+    {
+      /* INTEGER_CST nodes are special because they need their
+	 original type to be materialized by the reader (to implement
+	 TYPE_CACHED_VALUES).  */
+      lto_output_integer_cst (ob, expr, ref_p);
+    }
+  else
+    {
+      /* This is the first time we see EXPR, write it out.  */
+      pph_write_tree_header (stream, expr);
+      pph_write_tree_body (stream, expr);
+    }
+}
+
+
 /* Add DECL to the symbol table for pph_out_stream.  */
 
 void
diff --git a/gcc/cp/pph-streamer.c b/gcc/cp/pph-streamer.c
index 01f7a41..afabeb5 100644
--- a/gcc/cp/pph-streamer.c
+++ b/gcc/cp/pph-streamer.c
@@ -33,52 +33,35 @@  along with GCC; see the file COPYING3.  If not see
 #include "cppbuiltin.h"
 #include "streamer-hooks.h"
 
-/* Return true if the given tree T is streamable.  */
+/* Pre-load common tree nodes into the pickle cache in STREAM.  These
+   nodes are always built by the front end, so there is no need to
+   pickle them.
 
-static bool
-pph_is_streamable (tree t ATTRIBUTE_UNUSED)
-{
-  /* We accept most trees.  */
-  return TREE_CODE (t) != SSA_NAME
-	 && (TREE_CODE (t) < OMP_PARALLEL
-	     || TREE_CODE (t) > OMP_CRITICAL);
-}
-
-
-/* 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;
-}
-
-
-/* Pre-load common tree nodes into CACHE.  These nodes are always built by
-   the front end, so there is no need to pickle them.  */
+   FIXME pph - Every stream will have its own pickle cache.  Many
+   entries in all those caches will be the same.  Implement a common
+   cache for everything we preload here so that we do not have to
+   preload every cache we instantiate.  */
 
 static void
-pph_preload_common_nodes (struct lto_streamer_cache_d *cache)
+pph_cache_preload (pph_stream *stream)
 {
   unsigned i;
 
   for (i = itk_char; i < itk_none; i++)
-    lto_streamer_cache_append (cache, integer_types[i]);
+    pph_cache_add (stream, integer_types[i], NULL);
 
   for (i = 0; i < TYPE_KIND_LAST; i++)
-    lto_streamer_cache_append (cache, sizetype_tab[i]);
+    pph_cache_add (stream, sizetype_tab[i], NULL);
 
   /* global_trees[] can have NULL entries in it.  Skip them.  */
   for (i = 0; i < TI_MAX; i++)
     if (global_trees[i])
-      lto_streamer_cache_append (cache, global_trees[i]);
+      pph_cache_add (stream, global_trees[i], NULL);
 
   /* c_global_trees[] can have NULL entries in it.  Skip them.  */
   for (i = 0; i < CTI_MAX; i++)
     if (c_global_trees[i])
-      lto_streamer_cache_append (cache, c_global_trees[i]);
+      pph_cache_add (stream, c_global_trees[i], NULL);
 
   /* cp_global_trees[] can have NULL entries in it.  Skip them.  */
   for (i = 0; i < CPTI_MAX; i++)
@@ -88,12 +71,13 @@  pph_preload_common_nodes (struct lto_streamer_cache_d *cache)
 	continue;
 
       if (cp_global_trees[i])
-	lto_streamer_cache_append (cache, cp_global_trees[i]);
+	pph_cache_add (stream, cp_global_trees[i], NULL);
     }
 
-  lto_streamer_cache_append (cache, global_namespace);
-
-  lto_streamer_cache_append (cache, DECL_CONTEXT (global_namespace));
+  /* Add other well-known nodes that should always be taken from the
+     current compilation context.  */
+  pph_cache_add (stream, global_namespace, NULL);
+  pph_cache_add (stream, DECL_CONTEXT (global_namespace), NULL);
 }
 
 
@@ -103,19 +87,10 @@  static void
 pph_hooks_init (void)
 {
   streamer_hooks_init ();
-  streamer_hooks.name = "C++ AST";
-  streamer_hooks.preload_common_nodes = pph_preload_common_nodes;
-  streamer_hooks.is_streamable = pph_is_streamable;
   streamer_hooks.write_tree = pph_write_tree;
   streamer_hooks.read_tree = pph_read_tree;
-  streamer_hooks.pack_value_fields = pph_pack_value_fields;
-  streamer_hooks.indexable_with_decls_p = pph_indexable_with_decls_p;
-  streamer_hooks.unpack_value_fields = pph_unpack_value_fields;
-  streamer_hooks.alloc_tree = pph_alloc_tree;
-  streamer_hooks.output_tree_header = pph_out_tree_header;
   streamer_hooks.input_location = pph_read_location;
   streamer_hooks.output_location = pph_write_location;
-  streamer_hooks.has_unique_integer_csts_p = true;
 }
 
 
@@ -146,6 +121,8 @@  pph_stream_open (const char *name, const char *mode)
   else
     pph_init_read (stream);
 
+  pph_cache_preload (stream);
+
   return stream;
 }
 
@@ -433,15 +410,7 @@  pph_cache_insert_at (pph_stream *stream, void *data, unsigned ix)
   void **map_slot;
 
   map_slot = pointer_map_insert (stream->cache.m, data);
-  if (*map_slot)
-    {
-      /* DATA already existed in the cache.  Do nothing, but check
-	 that we are trying to insert DATA in the same slot that we
-	 had it in before.  */
-      unsigned HOST_WIDE_INT prev_ix = (unsigned HOST_WIDE_INT) *map_slot;
-      gcc_assert (prev_ix == ix);
-    }
-  else
+  if (*map_slot == NULL)
     {
       *map_slot = (void *) (unsigned HOST_WIDE_INT) ix;
       if (ix + 1 > VEC_length (void_p, stream->cache.v))
@@ -451,9 +420,10 @@  pph_cache_insert_at (pph_stream *stream, void *data, unsigned ix)
 }
 
 
-/* Add pointer DATA to the pickle cache in STREAM.  On exit, *IX_P will
-   contain the slot number where DATA is stored.  Return true if DATA
-   already existed in the cache, false otherwise.  */
+/* Add pointer DATA to the pickle cache in STREAM.  If IX_P is not
+   NULL, on exit *IX_P will contain the slot number where DATA is
+   stored.  Return true if DATA already existed in the cache, false
+   otherwise.  */
 
 bool
 pph_cache_add (pph_stream *stream, void *data, unsigned *ix_p)
@@ -477,7 +447,8 @@  pph_cache_add (pph_stream *stream, void *data, unsigned *ix_p)
       existed_p = true;
     }
 
-  *ix_p = ix;
+  if (ix_p)
+    *ix_p = ix;
 
   return existed_p;
 }
diff --git a/gcc/cp/pph-streamer.h b/gcc/cp/pph-streamer.h
index ee9869a..5c90be0 100644
--- a/gcc/cp/pph-streamer.h
+++ b/gcc/cp/pph-streamer.h
@@ -199,8 +199,6 @@  void *pph_cache_get (pph_stream *, unsigned);
 void pph_flush_buffers (pph_stream *);
 void pph_init_write (pph_stream *);
 void pph_write_tree (struct output_block *, tree, bool);
-void pph_pack_value_fields (struct bitpack_d *, tree);
-void pph_out_tree_header (struct output_block *, tree);
 void pph_add_decl_to_symtab (tree);
 void pph_add_include (pph_stream *);
 void pph_writer_init (void);
@@ -214,10 +212,7 @@  struct binding_table_s *pph_in_binding_table (pph_stream *);
 
 /* In pph-streamer-in.c.  */
 void pph_init_read (pph_stream *);
-void pph_read_tree (struct lto_input_block *, struct data_in *, tree);
-void pph_unpack_value_fields (struct bitpack_d *, tree);
-tree pph_alloc_tree (enum tree_code, struct lto_input_block *,
-	             struct data_in *);
+tree pph_read_tree (struct lto_input_block *, struct data_in *);
 location_t pph_read_location (struct lto_input_block *, struct data_in *);
 void pph_read_file (const char *);
 
@@ -236,7 +231,7 @@  pph_out_tree (pph_stream *stream, tree t)
 {
   if (flag_pph_tracer >= 1)
     pph_trace_tree (stream, t);
-  lto_output_tree (stream->encoder.w.ob, t, false);
+  pph_write_tree (stream->encoder.w.ob, t, false);
 }
 
 /* Output array A of cardinality C of ASTs to STREAM.  */
@@ -250,7 +245,7 @@  pph_out_tree_array (pph_stream *stream, tree *a, size_t c)
     {
       if (flag_pph_tracer >= 1)
         pph_trace_tree (stream, a[i]);
-      lto_output_tree (stream->encoder.w.ob, a[i]);
+      pph_write_tree (stream->encoder.w.ob, a[i]);
     }
 }
 #endif
@@ -262,7 +257,7 @@  pph_out_tree_or_ref_1 (pph_stream *stream, tree t, int tlevel)
 {
   if (flag_pph_tracer >= tlevel)
     pph_trace_tree (stream, t);
-  lto_output_tree (stream->encoder.w.ob, t, false);
+  pph_write_tree (stream->encoder.w.ob, t, false);
 }
 
 /* Output AST T to STREAM.  Trigger tracing at -fpph-tracer=2.  */
@@ -335,7 +330,7 @@  pph_out_tree_VEC (pph_stream *stream, VEC(tree,gc) *v)
     {
       if (flag_pph_tracer >= 1)
         pph_trace_tree (stream, t);
-      lto_output_tree (stream->encoder.w.ob, t);
+      pph_write_tree (stream->encoder.w.ob, t);
     }
 }
 #endif
@@ -430,7 +425,7 @@  pph_in_location (pph_stream *stream)
 static inline tree
 pph_in_tree (pph_stream *stream)
 {
-  tree t = lto_input_tree (stream->encoder.r.ib, stream->encoder.r.data_in);
+  tree t = pph_read_tree (stream->encoder.r.ib, stream->encoder.r.data_in);
   if (flag_pph_tracer >= 4)
     pph_trace_tree (stream, t);
   return t;
@@ -445,7 +440,7 @@  pph_in_tree_array (pph_stream *stream, tree *a, size_t c)
   size_t i;
   for (i = 0; i < c; ++i)
     {
-      tree t = lto_input_tree (stream->encoder.r.ib, stream->encoder.r.data_in);
+      tree t = pph_read_tree (stream->encoder.r.ib, stream->encoder.r.data_in);
       if (flag_pph_tracer >= 4)
         pph_trace_tree (stream, t, false); /* FIXME pph: always false? */
       a[i] = t;
@@ -463,7 +458,7 @@  pph_in_tree_VEC (pph_stream *stream, VEC(tree,gc) *v)
   unsigned int c = pph_in_uint (stream);
   for (i = 0; i < c; ++i)
     {
-      tree t = lto_input_tree (stream->encoder.r.ib, stream->encoder.r.data_in);
+      tree t = pph_read_tree (stream->encoder.r.ib, stream->encoder.r.data_in);
       if (flag_pph_tracer >= 4)
         pph_trace_tree (stream, t, false); /* FIXME pph: always false? */
       VEC_safe_push (tree, gc, v, t);
diff --git a/gcc/testsuite/g++.dg/pph/x1tmplclass2.cc b/gcc/testsuite/g++.dg/pph/x1tmplclass2.cc
index ac0d52e..2c7a8f3 100644
--- a/gcc/testsuite/g++.dg/pph/x1tmplclass2.cc
+++ b/gcc/testsuite/g++.dg/pph/x1tmplclass2.cc
@@ -1,5 +1,5 @@ 
 // { dg-xfail-if "BOGUS" { "*-*-*" } { "-fpph-map=pph.map" } }
-// { dg-bogus "x1tmplclass2.cc:1:0: fatal error: LTO_tags out of range: Range is 0 to 355, value is 22276" "" { xfail *-*-* } 0 }
+// { dg-bogus "x1tmplclass2.cc:1:0: internal compiler error: in pph_in_start_record, at cp/pph-streamer-in.c" "" { xfail *-*-* } 0 }
 
 #include "x0tmplclass23.h"
 #include "a0tmplclass2_u.h"
diff --git a/gcc/testsuite/g++.dg/pph/x4tmplclass2.cc b/gcc/testsuite/g++.dg/pph/x4tmplclass2.cc
index 6e5a61b..7c7e6a5 100644
--- a/gcc/testsuite/g++.dg/pph/x4tmplclass2.cc
+++ b/gcc/testsuite/g++.dg/pph/x4tmplclass2.cc
@@ -1,5 +1,5 @@ 
 // { dg-xfail-if "BOGUS" { "*-*-*" } { "-fpph-map=pph.map" } }
-// { dg-bogus "x4tmplclass2.cc:1:0: fatal error: LTO_tags out of range: Range is 0 to 355, value is 22275" "" { xfail *-*-* } 0 }
+// { dg-bogus "x4tmplclass2.cc:1:0: internal compiler error: in pph_in_start_record, at cp/pph-streamer-in.c" "" { xfail *-*-* } 0 }
 
 #include "x0tmplclass21.h"
 #include "x0tmplclass22.h"
diff --git a/gcc/testsuite/g++.dg/pph/z4tmplclass2.cc b/gcc/testsuite/g++.dg/pph/z4tmplclass2.cc
index 88d02b6..b932f5e 100644
--- a/gcc/testsuite/g++.dg/pph/z4tmplclass2.cc
+++ b/gcc/testsuite/g++.dg/pph/z4tmplclass2.cc
@@ -1,5 +1,5 @@ 
 // { dg-xfail-if "BOGUS" { "*-*-*" } { "-fpph-map=pph.map" } }
-// { dg-bogus "z4tmplclass2.cc:1:0: fatal error: LTO_tags out of range: Range is 0 to 355, value is 22276" "" { xfail *-*-* } 0 }
+// { dg-bogus "z4tmplclass2.cc:1:0: internal compiler error: in pph_in_start_record, at cp/pph-streamer-in.c" "" { xfail *-*-* } 0 }
 
 #include "x0tmplclass23.h"
 #include "x0tmplclass24.h"