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"
