diff mbox

[lto] Remove most streamer hooks. (issue4863041)

Message ID 20110811023759.D405D1DA19F@topo.tor.corp.google.com
State New
Headers show

Commit Message

Diego Novillo Aug. 11, 2011, 2:37 a.m. UTC
This implements step #4 from my streamer refactoring series at
http://gcc.gnu.org/ml/gcc-patches/2011-08/msg00765.html
(I skipped steps #2 and #3 for now, because I needed this change in
the PPH branch).

This patch opens up the generic tree streamer interface so that
streamers can use them independently.  With this, I started pushing
LTO-specific bits into lto-streamer*.

There are zero functional changes for LTO.  This simply moves some
functions to tree-streamer* and makes them external, so they can be
called from lto-streamer*.

The main changes are:

1- struct streamer_hooks is reduced to 4 callbacks: read_tree,
   write_tree, input_location and output_location.
   Both read_tree and write_tree change their semantics.  Before, they
   were called *after* the generic code had handled all the
   language-independent parts of the tree.  Now they are the main
   entry point, so each streamer is responsible for writing and
   reading the whole tree.
   
   The API in the tree streamer offers functions to read/write the
   tree header and the body, a streamer cache and everything that
   used to be inside the LTO streamer.  This makes no difference to
   LTO, since it simply means that some formerly static functions are
   now extern functions in tree-streamer*.

   The only big change for LTO is mechanical.  The low-level
   pickling/unpickling routines in the tree streamer need to call the
   write_tree and read_tree hooks instead of
   lto_output_tree/lto_input_tree.  So, the bulk of this patch are
   calls to stream_write_tree and stream_read_tree (two macros that
   expand to streamer_hooks.write_tree and streamer_hooks.read_tree).

2- Removed lto_output_tree_or_ref.  We now have a single entry point
   to the routine that's supposed to handle a tree.  So,
   lto_output_tree now checks if the caller wants a reference and the
   tree is indexable before trying to pickle it.

3- Separated the materialization of read trees from their insertion
   into the streamer cache and the streaming of bitfield values.  We
   were previously doing all this in one routine, but PPH needs to
   handle its own pickle cache, and it needs to read
   language-dependent bitfields.

4- Remove LTO-specific checks from lto_preload_common_nodes.  There
   were some checks done on main_identifier_node, fileptr_type_node,
   etc that only make sense for LTO.  We were doing those checks in
   lto_init, anyway.

5- Handle CALL_EXPR in lto_materialize_tree.  Despite the name this is
   a generic tree streaming function (the renaming patch will come
   in the next few days).  Handling CALL_EXPR does not
   affect LTO (since those nodes are never allowed), but it is a
   generic tree code so it makes more sense to handle it here.

6- Fix erroneous use of output_record_start when emitting NULL trees.
   In a couple of low-level pickling routines, we were calling
   output_record_start (ob, LTO_null) to indicate a NULL tree.  For
   LTO, this doesn't matter, but PPH implements its own tree
   delimiters (because of how the pickle cache works), so writing an
   LTO_null tag is not the same as writing a NULL tree.  For LTO, this
   just means an extra call to lto_output_tree (which will write the
   LTO_null) tag.


I was sorely tempted to start doing some renaming, but this patch
shifts quite a bit of code around.  I didn't want to make it harder
to review.

I have tested this patch with an LTO profiledbootstrap on x86_64.  The
patch is against the PPH branch, but right now the branch is very
close to trunk, so it will apply with little/no changes.

I expect some more further cleanups separating the generic and
LTO-specific parts.  But this is a good first step for PPH.

OK for trunk?


Diego.

	* Makefile.in (TREE_STREAMER_H): Add STREAMER_HOOKS_H.
 	(gimple-streamer-in.o): Add dependency on TREE_STREAMER_H.
 	* tree-streamer.h (stream_read_tree): New.  Replace all calls
 	to lto_input_tree with it.
 	(stream_write_tree): New.  Replace all calls to lto_output_tree,
 	lto_output_tree_ref and lto_output_tree_or_ref with it.
 	* lto-streamer-in.c (lto_read_tree): Inline code from
 	lto_streamer_read_tree.
 	(lto_input_tree): Move from tree-streamer-in.c.
 	* lto-streamer-out.c (lto_output_tree_ref): Make static.
 	Remove handling of NULL values for EXPR.
 	Do not handle EXPRs that are not indexable.
 	(lto_write_tree): Move from tree-streamer-out.c.
 	Inline lto_streamer_write_tree.
 	(lto_output_tree): Move from tree-streamer-out.c.
 	If REF_P is true and EXPR is indexable, call lto_output_tree_ref.
 	* lto-streamer.c (lto_record_common_node): Move to tree-streamer.c.
 	(lto_preload_common_nodes): Likewise.
 	Remove assertions and adjustments for nodes
 	main_identifier_node, ptrdiff_type_node and fileptr_type_node.
 	(lto_streamer_hooks_init): Set streamer_hooks.write_tree to
 	lto_output_tree and streamer_hooks.read_tree to
 	lto_input_tree.
 	* lto-streamer.h (lto_input_tree): Declare.
 	(lto_output_tree_ref): Remove.
 	* streamer-hooks.h (struct streamer_hooks): Remove fields
 	preload_common_nodes, indexable_with_decls_p,
 	pack_value_fields, unpack_value_fields, output_tree_header and
 	has_unique_integer_csts_p.
 	Update all users.
 	* tree-streamer-in.c (lto_materialize_tree): Make extern.
 	(lto_input_tree_pointers): Likewise.
 	(lto_read_tree): Move to lto-streamer-in.c.
 	(lto_input_integer_cst): Make extern.
 	(lto_get_pickled_tree): Likewise.
 	(lto_get_builtin_tree): Likewise.
 	(lto_input_tree): Move to lto-streamer-in.c.
 	* tree-streamer-out.c (pack_value_fields): Make extern.
 	(lto_output_tree_or_ref): Remove.  Replace all callers with
 	calls to stream_write_tree.
 	(lto_output_builtin_tree): Make extern.
 	(lto_streamer_write_tree): Inline into lto_write_tree.
 	(lto_output_tree_pointers): Make extern.
 	(lto_output_tree_header): Likewise.
 	(lto_output_integer_cst): Likewise.
 	(lto_write_tree): Move to lto-streamer-out.c.
 	(lto_output_tree): Likewise.
 	* tree-streamer.c (lto_record_common_node): Move from
 	lto-streamer.c
 	(preload_common_nodes): Likewise.
 	(lto_streamer_cache_create): Call it.
 	* tree-streamer.h: Include streamer-hooks.h.
 	(stream_write_tree): New.
 	(stream_read_tree): New.
 	(lto_input_tree): Remove.
 	(lto_materialize_tree): Declare.
 	(lto_input_tree_pointers): Declare.
 	(lto_get_pickled_tree): Declare.
 	(lto_get_builtin_tree): Declare.
 	(lto_input_integer_cst): Declare.
 	(lto_output_tree_header): Declare.
 	(pack_value_fields): Declare.
 	(lto_output_tree_pointers): Declare.
 	(lto_output_integer_cst): Declare.
 	(lto_output_builtin_tree): Declare.

	* lto-streamer-in.c (lto_read_tree): Call lto_streamer_cache_append
	and tree_read_bitfields.
	* lto-streamer-out.c (lto_is_streamable): Move from lto-streamer.c
	(lto_write_tree): Call it.
	* lto-streamer.c (lto_is_streamable): Move to lto-streamer-out.c
	* streamer-hooks.h (struct streamer_hooks): Remove fields
	name, is_streamable and alloc_tree. Update all users.
	* tree-streamer-in.c (tree_read_bitfields): Factor out of ...
	(lto_materialize_tree): ... here.
	Handle CALL_EXPR codes.
	Remove call to lto_streamer_cache_append.
	* tree-streamer-out.c (lto_output_tree_header): Handle
	CALL_EXPR nodes.
	* tree-streamer.h (tree_read_bitfields): Declare.

	* lto-streamer.h (lto_stream_as_builtin_p): Move ...
	* tree-streamer.h (lto_stream_as_builtin_p): ... here.

	* streamer-hooks.h (stream_write_tree): Move from tree-streamer.h.
	Convert it to a macro.
	(stream_read_tree): Likewise.

	* tree-streamer-out.c (lto_output_ts_decl_with_vis_tree_pointers):
	Call stream_write_tree instead of output_record_start.
	(lto_output_ts_binfo_tree_pointers): Likewise.
---
 gcc/ChangeLog.pph         |  102 +++++++++++++++
 gcc/Makefile.in           |    5 +-
 gcc/gimple-streamer-in.c  |   10 +-
 gcc/gimple-streamer-out.c |   11 +-
 gcc/ipa-inline-analysis.c |    4 +-
 gcc/ipa-prop.c            |   28 ++--
 gcc/lto-cgraph.c          |    4 +-
 gcc/lto-streamer-in.c     |  138 ++++++++++++++++-----
 gcc/lto-streamer-out.c    |  218 +++++++++++++++++++++++++--------
 gcc/lto-streamer.c        |  113 +----------------
 gcc/lto-streamer.h        |   13 +--
 gcc/lto/lto-lang.c        |    1 +
 gcc/lto/lto.c             |    2 +-
 gcc/streamer-hooks.h      |   90 +++-----------
 gcc/tree-streamer-in.c    |  279 +++++++++++++++--------------------------
 gcc/tree-streamer-out.c   |  304 +++++++++++----------------------------------
 gcc/tree-streamer.c       |   62 +++++++++-
 gcc/tree-streamer.h       |   27 ++++-
 18 files changed, 688 insertions(+), 723 deletions(-)

Comments

Richard Biener Aug. 11, 2011, 8:45 a.m. UTC | #1
On Wed, 10 Aug 2011, Diego Novillo wrote:

> 
> This implements step #4 from my streamer refactoring series at
> http://gcc.gnu.org/ml/gcc-patches/2011-08/msg00765.html
> (I skipped steps #2 and #3 for now, because I needed this change in
> the PPH branch).
> 
> This patch opens up the generic tree streamer interface so that
> streamers can use them independently.  With this, I started pushing
> LTO-specific bits into lto-streamer*.
> 
> There are zero functional changes for LTO.  This simply moves some
> functions to tree-streamer* and makes them external, so they can be
> called from lto-streamer*.
> 
> The main changes are:
> 
> 1- struct streamer_hooks is reduced to 4 callbacks: read_tree,
>    write_tree, input_location and output_location.
>    Both read_tree and write_tree change their semantics.  Before, they
>    were called *after* the generic code had handled all the
>    language-independent parts of the tree.  Now they are the main
>    entry point, so each streamer is responsible for writing and
>    reading the whole tree.
>    
>    The API in the tree streamer offers functions to read/write the
>    tree header and the body, a streamer cache and everything that
>    used to be inside the LTO streamer.  This makes no difference to
>    LTO, since it simply means that some formerly static functions are
>    now extern functions in tree-streamer*.
> 
>    The only big change for LTO is mechanical.  The low-level
>    pickling/unpickling routines in the tree streamer need to call the
>    write_tree and read_tree hooks instead of
>    lto_output_tree/lto_input_tree.  So, the bulk of this patch are
>    calls to stream_write_tree and stream_read_tree (two macros that
>    expand to streamer_hooks.write_tree and streamer_hooks.read_tree).
> 
> 2- Removed lto_output_tree_or_ref.  We now have a single entry point
>    to the routine that's supposed to handle a tree.  So,
>    lto_output_tree now checks if the caller wants a reference and the
>    tree is indexable before trying to pickle it.
> 
> 3- Separated the materialization of read trees from their insertion
>    into the streamer cache and the streaming of bitfield values.  We
>    were previously doing all this in one routine, but PPH needs to
>    handle its own pickle cache, and it needs to read
>    language-dependent bitfields.
> 
> 4- Remove LTO-specific checks from lto_preload_common_nodes.  There
>    were some checks done on main_identifier_node, fileptr_type_node,
>    etc that only make sense for LTO.  We were doing those checks in
>    lto_init, anyway.
> 
> 5- Handle CALL_EXPR in lto_materialize_tree.  Despite the name this is
>    a generic tree streaming function (the renaming patch will come
>    in the next few days).  Handling CALL_EXPR does not
>    affect LTO (since those nodes are never allowed), but it is a
>    generic tree code so it makes more sense to handle it here.

That's the only odd thing - because we reject it in
lto_is_streamable ().  Why "does it make sense" to handle it there?
I don't think it makes sense - in fact you should be able to
replace its handling with gcc_unreachable ().  Oh, I see, this
is in tree-streamer.c and thus to be renamed in subsequent patches?

> 6- Fix erroneous use of output_record_start when emitting NULL trees.
>    In a couple of low-level pickling routines, we were calling
>    output_record_start (ob, LTO_null) to indicate a NULL tree.  For
>    LTO, this doesn't matter, but PPH implements its own tree
>    delimiters (because of how the pickle cache works), so writing an
>    LTO_null tag is not the same as writing a NULL tree.  For LTO, this
>    just means an extra call to lto_output_tree (which will write the
>    LTO_null) tag.
> 
> 
> I was sorely tempted to start doing some renaming, but this patch
> shifts quite a bit of code around.  I didn't want to make it harder
> to review.
> 
> I have tested this patch with an LTO profiledbootstrap on x86_64.  The
> patch is against the PPH branch, but right now the branch is very
> close to trunk, so it will apply with little/no changes.
> 
> I expect some more further cleanups separating the generic and
> LTO-specific parts.  But this is a good first step for PPH.
> 
> OK for trunk?

Ok.

Thanks,
Richard.

> 
> Diego.
> 
> 	* Makefile.in (TREE_STREAMER_H): Add STREAMER_HOOKS_H.
>  	(gimple-streamer-in.o): Add dependency on TREE_STREAMER_H.
>  	* tree-streamer.h (stream_read_tree): New.  Replace all calls
>  	to lto_input_tree with it.
>  	(stream_write_tree): New.  Replace all calls to lto_output_tree,
>  	lto_output_tree_ref and lto_output_tree_or_ref with it.
>  	* lto-streamer-in.c (lto_read_tree): Inline code from
>  	lto_streamer_read_tree.
>  	(lto_input_tree): Move from tree-streamer-in.c.
>  	* lto-streamer-out.c (lto_output_tree_ref): Make static.
>  	Remove handling of NULL values for EXPR.
>  	Do not handle EXPRs that are not indexable.
>  	(lto_write_tree): Move from tree-streamer-out.c.
>  	Inline lto_streamer_write_tree.
>  	(lto_output_tree): Move from tree-streamer-out.c.
>  	If REF_P is true and EXPR is indexable, call lto_output_tree_ref.
>  	* lto-streamer.c (lto_record_common_node): Move to tree-streamer.c.
>  	(lto_preload_common_nodes): Likewise.
>  	Remove assertions and adjustments for nodes
>  	main_identifier_node, ptrdiff_type_node and fileptr_type_node.
>  	(lto_streamer_hooks_init): Set streamer_hooks.write_tree to
>  	lto_output_tree and streamer_hooks.read_tree to
>  	lto_input_tree.
>  	* lto-streamer.h (lto_input_tree): Declare.
>  	(lto_output_tree_ref): Remove.
>  	* streamer-hooks.h (struct streamer_hooks): Remove fields
>  	preload_common_nodes, indexable_with_decls_p,
>  	pack_value_fields, unpack_value_fields, output_tree_header and
>  	has_unique_integer_csts_p.
>  	Update all users.
>  	* tree-streamer-in.c (lto_materialize_tree): Make extern.
>  	(lto_input_tree_pointers): Likewise.
>  	(lto_read_tree): Move to lto-streamer-in.c.
>  	(lto_input_integer_cst): Make extern.
>  	(lto_get_pickled_tree): Likewise.
>  	(lto_get_builtin_tree): Likewise.
>  	(lto_input_tree): Move to lto-streamer-in.c.
>  	* tree-streamer-out.c (pack_value_fields): Make extern.
>  	(lto_output_tree_or_ref): Remove.  Replace all callers with
>  	calls to stream_write_tree.
>  	(lto_output_builtin_tree): Make extern.
>  	(lto_streamer_write_tree): Inline into lto_write_tree.
>  	(lto_output_tree_pointers): Make extern.
>  	(lto_output_tree_header): Likewise.
>  	(lto_output_integer_cst): Likewise.
>  	(lto_write_tree): Move to lto-streamer-out.c.
>  	(lto_output_tree): Likewise.
>  	* tree-streamer.c (lto_record_common_node): Move from
>  	lto-streamer.c
>  	(preload_common_nodes): Likewise.
>  	(lto_streamer_cache_create): Call it.
>  	* tree-streamer.h: Include streamer-hooks.h.
>  	(stream_write_tree): New.
>  	(stream_read_tree): New.
>  	(lto_input_tree): Remove.
>  	(lto_materialize_tree): Declare.
>  	(lto_input_tree_pointers): Declare.
>  	(lto_get_pickled_tree): Declare.
>  	(lto_get_builtin_tree): Declare.
>  	(lto_input_integer_cst): Declare.
>  	(lto_output_tree_header): Declare.
>  	(pack_value_fields): Declare.
>  	(lto_output_tree_pointers): Declare.
>  	(lto_output_integer_cst): Declare.
>  	(lto_output_builtin_tree): Declare.
> 
> 	* lto-streamer-in.c (lto_read_tree): Call lto_streamer_cache_append
> 	and tree_read_bitfields.
> 	* lto-streamer-out.c (lto_is_streamable): Move from lto-streamer.c
> 	(lto_write_tree): Call it.
> 	* lto-streamer.c (lto_is_streamable): Move to lto-streamer-out.c
> 	* streamer-hooks.h (struct streamer_hooks): Remove fields
> 	name, is_streamable and alloc_tree. Update all users.
> 	* tree-streamer-in.c (tree_read_bitfields): Factor out of ...
> 	(lto_materialize_tree): ... here.
> 	Handle CALL_EXPR codes.
> 	Remove call to lto_streamer_cache_append.
> 	* tree-streamer-out.c (lto_output_tree_header): Handle
> 	CALL_EXPR nodes.
> 	* tree-streamer.h (tree_read_bitfields): Declare.
> 
> 	* lto-streamer.h (lto_stream_as_builtin_p): Move ...
> 	* tree-streamer.h (lto_stream_as_builtin_p): ... here.
> 
> 	* streamer-hooks.h (stream_write_tree): Move from tree-streamer.h.
> 	Convert it to a macro.
> 	(stream_read_tree): Likewise.
> 
> 	* tree-streamer-out.c (lto_output_ts_decl_with_vis_tree_pointers):
> 	Call stream_write_tree instead of output_record_start.
> 	(lto_output_ts_binfo_tree_pointers): Likewise.
> ---
>  gcc/ChangeLog.pph         |  102 +++++++++++++++
>  gcc/Makefile.in           |    5 +-
>  gcc/gimple-streamer-in.c  |   10 +-
>  gcc/gimple-streamer-out.c |   11 +-
>  gcc/ipa-inline-analysis.c |    4 +-
>  gcc/ipa-prop.c            |   28 ++--
>  gcc/lto-cgraph.c          |    4 +-
>  gcc/lto-streamer-in.c     |  138 ++++++++++++++++-----
>  gcc/lto-streamer-out.c    |  218 +++++++++++++++++++++++++--------
>  gcc/lto-streamer.c        |  113 +----------------
>  gcc/lto-streamer.h        |   13 +--
>  gcc/lto/lto-lang.c        |    1 +
>  gcc/lto/lto.c             |    2 +-
>  gcc/streamer-hooks.h      |   90 +++-----------
>  gcc/tree-streamer-in.c    |  279 +++++++++++++++--------------------------
>  gcc/tree-streamer-out.c   |  304 +++++++++++----------------------------------
>  gcc/tree-streamer.c       |   62 +++++++++-
>  gcc/tree-streamer.h       |   27 ++++-
>  18 files changed, 688 insertions(+), 723 deletions(-)
> 
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index 333d721..9f8d905 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -1002,7 +1002,8 @@ LTO_STREAMER_H = lto-streamer.h $(LINKER_PLUGIN_API_H) $(TARGET_H) \
>  DATA_STREAMER_H = data-streamer.h $(VEC_H) $(LTO_STREAMER_H)
>  GIMPLE_STREAMER_H = gimple-streamer.h $(LTO_STREAMER_H) $(BASIC_BLOCK_H) \
>  		    $(FUNCTION_H)
> -TREE_STREAMER_H = tree-streamer.h $(TREE_H) $(LTO_STREAMER_H)
> +TREE_STREAMER_H = tree-streamer.h $(TREE_H) $(LTO_STREAMER_H) \
> +		  $(STREAMER_HOOKS_H)
>  STREAMER_HOOKS_H = streamer-hooks.h $(TREE_H)
>  TREE_VECTORIZER_H = tree-vectorizer.h $(TREE_DATA_REF_H)
>  IPA_PROP_H = ipa-prop.h $(TREE_H) $(VEC_H) $(CGRAPH_H) $(GIMPLE_H) alloc-pool.h
> @@ -2312,7 +2313,7 @@ gimple-streamer-in.o: gimple-streamer-in.c $(CONFIG_H) $(SYSTEM_H) \
>      $(TREE_STREAMER_H) $(DIAGNOSTIC_H)
>  gimple-streamer-out.o: gimple-streamer-out.c $(CONFIG_H) $(SYSTEM_H) \
>      coretypes.h $(GIMPLE_STREAMER_H) $(DATA_STREAMER_H) $(TREE_FLOW_H) \
> -    $(LTO_STREAMER_H)
> +    $(LTO_STREAMER_H) $(TREE_STREAMER_H)
>  tree-streamer.o: tree-streamer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
>      $(TREE_STREAMER_H) $(STREAMER_HOOKS_H)
>  tree-streamer-in.o: tree-streamer-in.c $(CONFIG_H) $(SYSTEM_H) \
> diff --git a/gcc/gimple-streamer-in.c b/gcc/gimple-streamer-in.c
> index dd91c73..78ab729 100644
> --- a/gcc/gimple-streamer-in.c
> +++ b/gcc/gimple-streamer-in.c
> @@ -52,7 +52,7 @@ input_phi (struct lto_input_block *ib, basic_block bb, struct data_in *data_in,
>       were in the original program.  */
>    for (i = 0; i < len; i++)
>      {
> -      tree def = lto_input_tree (ib, data_in);
> +      tree def = stream_read_tree (ib, data_in);
>        int src_index = lto_input_uleb128 (ib);
>        location_t arg_loc = lto_input_location (ib, data_in);
>        basic_block sbb = BASIC_BLOCK_FOR_FUNCTION (fn, src_index);
> @@ -103,7 +103,7 @@ input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
>    gimple_set_location (stmt, lto_input_location (ib, data_in));
>  
>    /* Read lexical block reference.  */
> -  gimple_set_block (stmt, lto_input_tree (ib, data_in));
> +  gimple_set_block (stmt, stream_read_tree (ib, data_in));
>  
>    /* Read in all the operands.  */
>    switch (code)
> @@ -113,7 +113,7 @@ input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
>        break;
>  
>      case GIMPLE_EH_MUST_NOT_THROW:
> -      gimple_eh_must_not_throw_set_fndecl (stmt, lto_input_tree (ib, data_in));
> +      gimple_eh_must_not_throw_set_fndecl (stmt, stream_read_tree (ib, data_in));
>        break;
>  
>      case GIMPLE_EH_DISPATCH:
> @@ -143,7 +143,7 @@ input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
>      case GIMPLE_DEBUG:
>        for (i = 0; i < num_ops; i++)
>  	{
> -	  tree op = lto_input_tree (ib, data_in);
> +	  tree op = stream_read_tree (ib, data_in);
>  	  gimple_set_op (stmt, i, op);
>  	  if (!op)
>  	    continue;
> @@ -223,7 +223,7 @@ input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
>  	    gimple_call_set_internal_fn
>  	      (stmt, lto_input_enum (ib, internal_fn, IFN_LAST));
>  	  else
> -	    gimple_call_set_fntype (stmt, lto_input_tree (ib, data_in));
> +	    gimple_call_set_fntype (stmt, stream_read_tree (ib, data_in));
>  	}
>        break;
>  
> diff --git a/gcc/gimple-streamer-out.c b/gcc/gimple-streamer-out.c
> index 0a41510..233862c 100644
> --- a/gcc/gimple-streamer-out.c
> +++ b/gcc/gimple-streamer-out.c
> @@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "data-streamer.h"
>  #include "gimple-streamer.h"
>  #include "lto-streamer.h"
> +#include "tree-streamer.h"
>  
>  /* Output PHI function PHI to the main stream in OB.  */
>  
> @@ -40,7 +41,7 @@ output_phi (struct output_block *ob, gimple phi)
>  
>    for (i = 0; i < len; i++)
>      {
> -      lto_output_tree_ref (ob, gimple_phi_arg_def (phi, i));
> +      stream_write_tree (ob, gimple_phi_arg_def (phi, i), true);
>        output_uleb128 (ob, gimple_phi_arg_edge (phi, i)->src->index);
>        lto_output_location (ob, gimple_phi_arg_location (phi, i));
>      }
> @@ -76,7 +77,7 @@ output_gimple_stmt (struct output_block *ob, gimple stmt)
>    lto_output_location (ob, gimple_location (stmt));
>  
>    /* Emit the lexical block holding STMT.  */
> -  lto_output_tree (ob, gimple_block (stmt), true);
> +  stream_write_tree (ob, gimple_block (stmt), true);
>  
>    /* Emit the operands.  */
>    switch (gimple_code (stmt))
> @@ -86,7 +87,7 @@ output_gimple_stmt (struct output_block *ob, gimple stmt)
>        break;
>  
>      case GIMPLE_EH_MUST_NOT_THROW:
> -      lto_output_tree_ref (ob, gimple_eh_must_not_throw_fndecl (stmt));
> +      stream_write_tree (ob, gimple_eh_must_not_throw_fndecl (stmt), true);
>        break;
>  
>      case GIMPLE_EH_DISPATCH:
> @@ -133,7 +134,7 @@ output_gimple_stmt (struct output_block *ob, gimple stmt)
>  		  TREE_THIS_VOLATILE (*basep) = volatilep;
>  		}
>  	    }
> -	  lto_output_tree_ref (ob, op);
> +	  stream_write_tree (ob, op, true);
>  	}
>        if (is_gimple_call (stmt))
>  	{
> @@ -141,7 +142,7 @@ output_gimple_stmt (struct output_block *ob, gimple stmt)
>  	    lto_output_enum (ob->main_stream, internal_fn,
>  			     IFN_LAST, gimple_call_internal_fn (stmt));
>  	  else
> -	    lto_output_tree_ref (ob, gimple_call_fntype (stmt));
> +	    stream_write_tree (ob, gimple_call_fntype (stmt), true);
>  	}
>        break;
>  
> diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c
> index bc65a45..f3214e2 100644
> --- a/gcc/ipa-inline-analysis.c
> +++ b/gcc/ipa-inline-analysis.c
> @@ -2407,7 +2407,7 @@ inline_read_section (struct lto_file_decl_data *file_data, const char *data,
>  	  struct condition c;
>  	  c.operand_num = lto_input_uleb128 (&ib);
>  	  c.code = (enum tree_code) lto_input_uleb128 (&ib);
> -	  c.val = lto_input_tree (&ib, data_in);
> +	  c.val = stream_read_tree (&ib, data_in);
>  	  VEC_safe_push (condition, gc, info->conds, &c);
>  	}
>        count2 = lto_input_uleb128 (&ib);
> @@ -2552,7 +2552,7 @@ inline_write_summary (cgraph_node_set set,
>  					 c->operand_num);
>  	      lto_output_uleb128_stream (ob->main_stream,
>  					 c->code);
> -	      lto_output_tree (ob, c->val, true);
> +	      stream_write_tree (ob, c->val, true);
>  	    }
>  	  lto_output_uleb128_stream (ob->main_stream,
>  				     VEC_length (size_time_entry, info->entry));
> diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
> index 7f9f547..0997cf5 100644
> --- a/gcc/ipa-prop.c
> +++ b/gcc/ipa-prop.c
> @@ -2652,13 +2652,13 @@ ipa_write_jump_function (struct output_block *ob,
>      case IPA_JF_UNKNOWN:
>        break;
>      case IPA_JF_KNOWN_TYPE:
> -      lto_output_tree (ob, jump_func->value.base_binfo, true);
> +      stream_write_tree (ob, jump_func->value.base_binfo, true);
>        break;
>      case IPA_JF_CONST:
> -      lto_output_tree (ob, jump_func->value.constant, true);
> +      stream_write_tree (ob, jump_func->value.constant, true);
>        break;
>      case IPA_JF_PASS_THROUGH:
> -      lto_output_tree (ob, jump_func->value.pass_through.operand, true);
> +      stream_write_tree (ob, jump_func->value.pass_through.operand, true);
>        lto_output_uleb128_stream (ob->main_stream,
>  				 jump_func->value.pass_through.formal_id);
>        lto_output_uleb128_stream (ob->main_stream,
> @@ -2667,13 +2667,13 @@ ipa_write_jump_function (struct output_block *ob,
>      case IPA_JF_ANCESTOR:
>        lto_output_uleb128_stream (ob->main_stream,
>  				 jump_func->value.ancestor.offset);
> -      lto_output_tree (ob, jump_func->value.ancestor.type, true);
> +      stream_write_tree (ob, jump_func->value.ancestor.type, true);
>        lto_output_uleb128_stream (ob->main_stream,
>  				 jump_func->value.ancestor.formal_id);
>        break;
>      case IPA_JF_CONST_MEMBER_PTR:
> -      lto_output_tree (ob, jump_func->value.member_cst.pfn, true);
> -      lto_output_tree (ob, jump_func->value.member_cst.delta, false);
> +      stream_write_tree (ob, jump_func->value.member_cst.pfn, true);
> +      stream_write_tree (ob, jump_func->value.member_cst.delta, false);
>        break;
>      }
>  }
> @@ -2692,24 +2692,24 @@ ipa_read_jump_function (struct lto_input_block *ib,
>      case IPA_JF_UNKNOWN:
>        break;
>      case IPA_JF_KNOWN_TYPE:
> -      jump_func->value.base_binfo = lto_input_tree (ib, data_in);
> +      jump_func->value.base_binfo = stream_read_tree (ib, data_in);
>        break;
>      case IPA_JF_CONST:
> -      jump_func->value.constant = lto_input_tree (ib, data_in);
> +      jump_func->value.constant = stream_read_tree (ib, data_in);
>        break;
>      case IPA_JF_PASS_THROUGH:
> -      jump_func->value.pass_through.operand = lto_input_tree (ib, data_in);
> +      jump_func->value.pass_through.operand = stream_read_tree (ib, data_in);
>        jump_func->value.pass_through.formal_id = lto_input_uleb128 (ib);
>        jump_func->value.pass_through.operation = (enum tree_code) lto_input_uleb128 (ib);
>        break;
>      case IPA_JF_ANCESTOR:
>        jump_func->value.ancestor.offset = lto_input_uleb128 (ib);
> -      jump_func->value.ancestor.type = lto_input_tree (ib, data_in);
> +      jump_func->value.ancestor.type = stream_read_tree (ib, data_in);
>        jump_func->value.ancestor.formal_id = lto_input_uleb128 (ib);
>        break;
>      case IPA_JF_CONST_MEMBER_PTR:
> -      jump_func->value.member_cst.pfn = lto_input_tree (ib, data_in);
> -      jump_func->value.member_cst.delta = lto_input_tree (ib, data_in);
> +      jump_func->value.member_cst.pfn = stream_read_tree (ib, data_in);
> +      jump_func->value.member_cst.delta = stream_read_tree (ib, data_in);
>        break;
>      }
>  }
> @@ -2733,7 +2733,7 @@ ipa_write_indirect_edge_info (struct output_block *ob,
>    if (ii->polymorphic)
>      {
>        lto_output_sleb128_stream (ob->main_stream, ii->otr_token);
> -      lto_output_tree (ob, ii->otr_type, true);
> +      stream_write_tree (ob, ii->otr_type, true);
>      }
>  }
>  
> @@ -2755,7 +2755,7 @@ ipa_read_indirect_edge_info (struct lto_input_block *ib,
>    if (ii->polymorphic)
>      {
>        ii->otr_token = (HOST_WIDE_INT) lto_input_sleb128 (ib);
> -      ii->otr_type = lto_input_tree (ib, data_in);
> +      ii->otr_type = stream_read_tree (ib, data_in);
>      }
>  }
>  
> diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c
> index c4da1ff..00462d8 100644
> --- a/gcc/lto-cgraph.c
> +++ b/gcc/lto-cgraph.c
> @@ -1581,7 +1581,7 @@ output_node_opt_summary (struct output_block *ob,
>           mechanism to store function local declarations into summaries.  */
>        gcc_assert (parm);
>        lto_output_uleb128_stream (ob->main_stream, parm_num);
> -      lto_output_tree (ob, map->new_tree, true);
> +      stream_write_tree (ob, map->new_tree, true);
>        bp = bitpack_create (ob->main_stream);
>        bp_pack_value (&bp, map->replace_p, 1);
>        bp_pack_value (&bp, map->ref_p, 1);
> @@ -1688,7 +1688,7 @@ input_node_opt_summary (struct cgraph_node *node,
>  	parm_num --;
>        map->parm_num = lto_input_uleb128 (ib_main);
>        map->old_tree = NULL;
> -      map->new_tree = lto_input_tree (ib_main, data_in);
> +      map->new_tree = stream_read_tree (ib_main, data_in);
>        bp = lto_input_bitpack (ib_main);
>        map->replace_p = bp_unpack_value (&bp, 1);
>        map->ref_p = bp_unpack_value (&bp, 1);
> diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
> index c6cba35..e43ff28 100644
> --- a/gcc/lto-streamer-in.c
> +++ b/gcc/lto-streamer-in.c
> @@ -204,7 +204,7 @@ lto_input_location (struct lto_input_block *ib, struct data_in *data_in)
>     TAG is the expected node that should be found in IB, if TAG belongs
>     to one of the indexable trees, expect to read a reference index to
>     be looked up in one of the symbol tables, otherwise read the pysical
> -   representation of the tree using lto_input_tree.  FN is the
> +   representation of the tree using stream_read_tree.  FN is the
>     function scope for the read tree.  */
>  
>  tree
> @@ -289,9 +289,9 @@ lto_input_eh_catch_list (struct lto_input_block *ib, struct data_in *data_in,
>  
>        /* Read the catch node.  */
>        n = ggc_alloc_cleared_eh_catch_d ();
> -      n->type_list = lto_input_tree (ib, data_in);
> -      n->filter_list = lto_input_tree (ib, data_in);
> -      n->label = lto_input_tree (ib, data_in);
> +      n->type_list = stream_read_tree (ib, data_in);
> +      n->filter_list = stream_read_tree (ib, data_in);
> +      n->label = stream_read_tree (ib, data_in);
>  
>        /* Register all the types in N->FILTER_LIST.  */
>        for (list = n->filter_list; list; list = TREE_CHAIN (list))
> @@ -360,8 +360,8 @@ input_eh_region (struct lto_input_block *ib, struct data_in *data_in, int ix)
>  	  tree l;
>  
>  	  r->type = ERT_ALLOWED_EXCEPTIONS;
> -	  r->u.allowed.type_list = lto_input_tree (ib, data_in);
> -	  r->u.allowed.label = lto_input_tree (ib, data_in);
> +	  r->u.allowed.type_list = stream_read_tree (ib, data_in);
> +	  r->u.allowed.label = stream_read_tree (ib, data_in);
>  	  r->u.allowed.filter = lto_input_uleb128 (ib);
>  
>  	  for (l = r->u.allowed.type_list; l ; l = TREE_CHAIN (l))
> @@ -371,7 +371,7 @@ input_eh_region (struct lto_input_block *ib, struct data_in *data_in, int ix)
>  
>        case LTO_ert_must_not_throw:
>  	r->type = ERT_MUST_NOT_THROW;
> -	r->u.must_not_throw.failure_decl = lto_input_tree (ib, data_in);
> +	r->u.must_not_throw.failure_decl = stream_read_tree (ib, data_in);
>  	r->u.must_not_throw.failure_loc = lto_input_location (ib, data_in);
>  	break;
>  
> @@ -406,7 +406,7 @@ input_eh_lp (struct lto_input_block *ib, struct data_in *data_in, int ix)
>    gcc_assert (lp->index == ix);
>    lp->next_lp = (eh_landing_pad) (intptr_t) lto_input_sleb128 (ib);
>    lp->region = (eh_region) (intptr_t) lto_input_sleb128 (ib);
> -  lp->post_landing_pad = lto_input_tree (ib, data_in);
> +  lp->post_landing_pad = stream_read_tree (ib, data_in);
>  
>    return lp;
>  }
> @@ -551,7 +551,7 @@ input_eh_regions (struct lto_input_block *ib, struct data_in *data_in,
>        VEC_safe_grow (tree, gc, fn->eh->ttype_data, len);
>        for (i = 0; i < len; i++)
>  	{
> -	  tree ttype = lto_input_tree (ib, data_in);
> +	  tree ttype = stream_read_tree (ib, data_in);
>  	  VEC_replace (tree, fn->eh->ttype_data, i, ttype);
>  	}
>      }
> @@ -566,7 +566,7 @@ input_eh_regions (struct lto_input_block *ib, struct data_in *data_in,
>  	  VEC_safe_grow (tree, gc, fn->eh->ehspec_data.arm_eabi, len);
>  	  for (i = 0; i < len; i++)
>  	    {
> -	      tree t = lto_input_tree (ib, data_in);
> +	      tree t = stream_read_tree (ib, data_in);
>  	      VEC_replace (tree, fn->eh->ehspec_data.arm_eabi, i, t);
>  	    }
>  	}
> @@ -709,7 +709,7 @@ input_ssa_names (struct lto_input_block *ib, struct data_in *data_in,
>  	VEC_quick_push (tree, SSANAMES (fn), NULL_TREE);
>  
>        is_default_def = (lto_input_1_unsigned (ib) != 0);
> -      name = lto_input_tree (ib, data_in);
> +      name = stream_read_tree (ib, data_in);
>        ssa_name = make_ssa_name_fn (fn, name, gimple_build_nop ());
>  
>        if (is_default_def)
> @@ -783,8 +783,8 @@ input_struct_function_base (struct function *fn, struct data_in *data_in,
>    /* tree decl;						-- ignored */
>  
>    /* Read the static chain and non-local goto save area.  */
> -  fn->static_chain_decl = lto_input_tree (ib, data_in);
> -  fn->nonlocal_goto_save_area = lto_input_tree (ib, data_in);
> +  fn->static_chain_decl = stream_read_tree (ib, data_in);
> +  fn->nonlocal_goto_save_area = stream_read_tree (ib, data_in);
>  
>    /* Read all the local symbols.  */
>    len = lto_input_sleb128 (ib);
> @@ -794,7 +794,7 @@ input_struct_function_base (struct function *fn, struct data_in *data_in,
>        VEC_safe_grow (tree, gc, fn->local_decls, len);
>        for (i = 0; i < len; i++)
>  	{
> -	  tree t = lto_input_tree (ib, data_in);
> +	  tree t = stream_read_tree (ib, data_in);
>  	  VEC_replace (tree, fn->local_decls, i, t);
>  	}
>      }
> @@ -855,7 +855,7 @@ input_function (tree fn_decl, struct data_in *data_in,
>  
>    /* Read all function arguments.  We need to re-map them here to the
>       arguments of the merged function declaration.  */
> -  args = lto_input_tree (ib, data_in);
> +  args = stream_read_tree (ib, data_in);
>    for (oarg = args, narg = DECL_ARGUMENTS (fn_decl);
>         oarg && narg;
>         oarg = TREE_CHAIN (oarg), narg = TREE_CHAIN (narg))
> @@ -876,7 +876,7 @@ input_function (tree fn_decl, struct data_in *data_in,
>    input_eh_regions (ib, data_in, fn);
>  
>    /* Read the tree of lexical scopes for the function.  */
> -  DECL_INITIAL (fn_decl) = lto_input_tree (ib, data_in);
> +  DECL_INITIAL (fn_decl) = stream_read_tree (ib, data_in);
>    gcc_assert (DECL_INITIAL (fn_decl));
>    DECL_SAVED_TREE (fn_decl) = NULL_TREE;
>    node = cgraph_get_create_node (fn_decl);
> @@ -957,7 +957,7 @@ input_alias_pairs (struct lto_input_block *ib, struct data_in *data_in)
>  
>    clear_line_info (data_in);
>  
> -  var = lto_input_tree (ib, data_in);
> +  var = stream_read_tree (ib, data_in);
>    while (var)
>      {
>        const char *orig_name, *new_name;
> @@ -965,7 +965,7 @@ input_alias_pairs (struct lto_input_block *ib, struct data_in *data_in)
>  
>        p = VEC_safe_push (alias_pair, gc, alias_pairs, NULL);
>        p->decl = var;
> -      p->target = lto_input_tree (ib, data_in);
> +      p->target = stream_read_tree (ib, data_in);
>  
>        /* If the target is a static object, we may have registered a
>  	 new name for it to avoid clashes between statics coming from
> @@ -975,7 +975,7 @@ input_alias_pairs (struct lto_input_block *ib, struct data_in *data_in)
>        if (strcmp (orig_name, new_name) != 0)
>  	p->target = get_identifier (new_name);
>  
> -      var = lto_input_tree (ib, data_in);
> +      var = stream_read_tree (ib, data_in);
>      }
>  }
>  
> @@ -1081,18 +1081,98 @@ lto_input_constructors_and_inits (struct lto_file_decl_data *file_data,
>  }
>  
>  
> -/* LTO streamer hook for reading GIMPLE trees.  IB and DATA_IN are as in
> -   lto_read_tree.  EXPR is the tree was materialized by lto_read_tree and
> -   needs GIMPLE specific data to be filled in.  */
> +/* Read the physical representation of a tree node with tag TAG from
> +   input block IB using the per-file context in DATA_IN.  */
>  
> -void
> -lto_streamer_read_tree (struct lto_input_block *ib, struct data_in *data_in,
> -			tree expr)
> +static tree
> +lto_read_tree (struct lto_input_block *ib, struct data_in *data_in,
> +	       enum LTO_tags tag)
>  {
> -  if (DECL_P (expr)
> -      && TREE_CODE (expr) != FUNCTION_DECL
> -      && TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
> -    DECL_INITIAL (expr) = lto_input_tree (ib, data_in);
> +  /* Instantiate a new tree node.  */
> +  tree result = lto_materialize_tree (ib, data_in, tag);
> +
> +  /* Enter RESULT in the reader cache.  This will make RESULT
> +     available so that circular references in the rest of the tree
> +     structure can be resolved in subsequent calls to stream_read_tree.  */
> +  lto_streamer_cache_append (data_in->reader_cache, result);
> +
> +  /* Read all the bitfield values in RESULT.  Note that for LTO, we
> +     only write language-independent bitfields, so no more unpacking is
> +     needed.  */
> +  tree_read_bitfields (ib, result);
> +
> +  /* Read all the pointer fields in RESULT.  */
> +  lto_input_tree_pointers (ib, data_in, result);
> +
> +  /* Read any LTO-specific data not read by the tree streamer.  */
> +  if (DECL_P (result)
> +      && TREE_CODE (result) != FUNCTION_DECL
> +      && TREE_CODE (result) != TRANSLATION_UNIT_DECL)
> +    DECL_INITIAL (result) = stream_read_tree (ib, data_in);
> +
> +  /* We should never try to instantiate an MD or NORMAL builtin here.  */
> +  if (TREE_CODE (result) == FUNCTION_DECL)
> +    gcc_assert (!lto_stream_as_builtin_p (result));
> +
> +  /* end_marker = */ lto_input_1_unsigned (ib);
> +
> +#ifdef LTO_STREAMER_DEBUG
> +  /* Remove the mapping to RESULT's original address set by
> +     lto_materialize_tree.  */
> +  lto_orig_address_remove (result);
> +#endif
> +
> +  return result;
> +}
> +
> +
> +/* Read a tree from input block IB using the per-file context in
> +   DATA_IN.  This context is used, for example, to resolve references
> +   to previously read nodes.  */
> +
> +tree
> +lto_input_tree (struct lto_input_block *ib, struct data_in *data_in)
> +{
> +  enum LTO_tags tag;
> +  tree result;
> +
> +  tag = input_record_start (ib);
> +  gcc_assert ((unsigned) tag < (unsigned) LTO_NUM_TAGS);
> +
> +  if (tag == LTO_null)
> +    result = NULL_TREE;
> +  else if (tag >= LTO_field_decl_ref && tag <= LTO_global_decl_ref)
> +    {
> +      /* If TAG is a reference to an indexable tree, the next value
> +	 in IB is the index into the table where we expect to find
> +	 that tree.  */
> +      result = lto_input_tree_ref (ib, data_in, cfun, tag);
> +    }
> +  else if (tag == LTO_tree_pickle_reference)
> +    {
> +      /* If TAG is a reference to a previously read tree, look it up in
> +	 the reader cache.  */
> +      result = lto_get_pickled_tree (ib, data_in);
> +    }
> +  else if (tag == LTO_builtin_decl)
> +    {
> +      /* If we are going to read a built-in function, all we need is
> +	 the code and class.  */
> +      result = lto_get_builtin_tree (ib, data_in);
> +    }
> +  else if (tag == lto_tree_code_to_tag (INTEGER_CST))
> +    {
> +      /* For integer constants we only need the type and its hi/low
> +	 words.  */
> +      result = lto_input_integer_cst (ib, data_in);
> +    }
> +  else
> +    {
> +      /* Otherwise, materialize a new node from IB.  */
> +      result = lto_read_tree (ib, data_in, tag);
> +    }
> +
> +  return result;
>  }
>  
>  
> diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
> index d8711e3..cfd3365 100644
> --- a/gcc/lto-streamer-out.c
> +++ b/gcc/lto-streamer-out.c
> @@ -194,25 +194,11 @@ lto_output_location (struct output_block *ob, location_t loc)
>     output block OB.  Otherwise, output the physical representation of
>     EXPR to OB.  */
>  
> -void
> +static void
>  lto_output_tree_ref (struct output_block *ob, tree expr)
>  {
>    enum tree_code code;
>  
> -  if (expr == NULL_TREE)
> -    {
> -      output_record_start (ob, LTO_null);
> -      return;
> -    }
> -
> -  if (!tree_is_indexable (expr))
> -    {
> -      /* Even though we are emitting the physical representation of
> -	 EXPR, its leaves must be emitted as references.  */
> -      lto_output_tree (ob, expr, true);
> -      return;
> -    }
> -
>    if (TYPE_P (expr))
>      {
>        output_type_ref (ob, expr);
> @@ -239,8 +225,7 @@ lto_output_tree_ref (struct output_block *ob, tree expr)
>  
>      case VAR_DECL:
>      case DEBUG_EXPR_DECL:
> -      gcc_assert (decl_function_context (expr) == NULL
> -		  || TREE_STATIC (expr));
> +      gcc_assert (decl_function_context (expr) == NULL || TREE_STATIC (expr));
>        output_record_start (ob, LTO_global_decl_ref);
>        lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
>        break;
> @@ -282,22 +267,153 @@ lto_output_tree_ref (struct output_block *ob, tree expr)
>        break;
>  
>      default:
> -      {
> -	/* See if the streamer allows this node to be indexable
> -	   like other global declarations.  */
> -	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 ();
> -	  }
> -      }
> +      /* No other node is indexable, so it should have been handled by
> +	 lto_output_tree.  */
> +      gcc_unreachable ();
> +    }
> +}
> +
> +
> +/* Return true if EXPR is a tree node that can be written to disk.  */
> +
> +static inline bool
> +lto_is_streamable (tree expr)
> +{
> +  enum tree_code code = TREE_CODE (expr);
> +
> +  /* Notice that we reject SSA_NAMEs as well.  We only emit the SSA
> +     name version in lto_output_tree_ref (see output_ssa_names).  */
> +  return !is_lang_specific (expr)
> +	 && code != SSA_NAME
> +	 && code != CALL_EXPR
> +	 && code != LANG_TYPE
> +	 && code != MODIFY_EXPR
> +	 && code != INIT_EXPR
> +	 && code != TARGET_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);
> +}
> +
> +
> +/* Write a physical representation of tree node EXPR to output block
> +   OB.  If REF_P is true, the leaves of EXPR are emitted as references
> +   via lto_output_tree_ref.  IX is the index into the streamer cache
> +   where EXPR is stored.  */
> +
> +static void
> +lto_write_tree (struct output_block *ob, tree expr, bool ref_p)
> +{
> +  struct bitpack_d bp;
> +
> +  if (!lto_is_streamable (expr))
> +    internal_error ("tree code %qs is not supported in LTO streams",
> +	            tree_code_name[TREE_CODE (expr)]);
> +
> +  /* 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);
> +  pack_value_fields (&bp, expr);
> +  lto_output_bitpack (&bp);
> +
> +  /* Write all the pointer fields in EXPR.  */
> +  lto_output_tree_pointers (ob, expr, ref_p);
> +
> +  /* Write any LTO-specific data to OB.  */
> +  if (DECL_P (expr)
> +      && TREE_CODE (expr) != FUNCTION_DECL
> +      && TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
> +    {
> +      /* Handle DECL_INITIAL for symbols.  */
> +      tree initial = DECL_INITIAL (expr);
> +      if (TREE_CODE (expr) == VAR_DECL
> +	  && (TREE_STATIC (expr) || DECL_EXTERNAL (expr))
> +	  && initial)
> +	{
> +	  lto_varpool_encoder_t varpool_encoder;
> +	  struct varpool_node *vnode;
> +
> +	  varpool_encoder = ob->decl_state->varpool_node_encoder;
> +	  vnode = varpool_get_node (expr);
> +	  if (!vnode)
> +	    initial = error_mark_node;
> +	  else if (!lto_varpool_encoder_encode_initializer_p (varpool_encoder,
> +							      vnode))
> +	    initial = NULL;
> +	}
> +
> +      stream_write_tree (ob, initial, ref_p);
> +    }
> +
> +  /* Mark the end of EXPR.  */
> +  output_zero (ob);
> +}
> +
> +
> +/* Emit the physical representation of tree node EXPR to output block
> +   OB.  If REF_P is true, the leaves of EXPR are emitted as references
> +   via lto_output_tree_ref.  */
> +
> +void
> +lto_output_tree (struct output_block *ob, tree expr, bool ref_p)
> +{
> +  unsigned ix;
> +  bool existed_p;
> +
> +  if (expr == NULL_TREE)
> +    {
> +      output_record_start (ob, LTO_null);
> +      return;
> +    }
> +
> +  if (ref_p && tree_is_indexable (expr))
> +    {
> +      lto_output_tree_ref (ob, expr);
> +      return;
> +    }
> +
> +  /* INTEGER_CST nodes are special because they need their original type
> +     to be materialized by the reader (to implement TYPE_CACHED_VALUES).  */
> +  if (TREE_CODE (expr) == INTEGER_CST)
> +    {
> +      lto_output_integer_cst (ob, expr, ref_p);
> +      return;
> +    }
> +
> +  existed_p = lto_streamer_cache_insert (ob->writer_cache, expr, &ix);
> +  if (existed_p)
> +    {
> +      /* If a node has already been streamed out, make sure that
> +	 we don't write it more than once.  Otherwise, the reader
> +	 will instantiate two different nodes for the same object.  */
> +      output_record_start (ob, LTO_tree_pickle_reference);
> +      output_uleb128 (ob, ix);
> +      lto_output_enum (ob->main_stream, LTO_tags, LTO_NUM_TAGS,
> +		       lto_tree_code_to_tag (TREE_CODE (expr)));
> +    }
> +  else 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
> +    {
> +      /* This is the first time we see EXPR, write its fields
> +	 to OB.  */
> +      lto_write_tree (ob, expr, ref_p);
>      }
>  }
>  
> @@ -312,9 +428,9 @@ output_eh_try_list (struct output_block *ob, eh_catch first)
>    for (n = first; n; n = n->next_catch)
>      {
>        output_record_start (ob, LTO_eh_catch);
> -      lto_output_tree_ref (ob, n->type_list);
> -      lto_output_tree_ref (ob, n->filter_list);
> -      lto_output_tree_ref (ob, n->label);
> +      stream_write_tree (ob, n->type_list, true);
> +      stream_write_tree (ob, n->filter_list, true);
> +      stream_write_tree (ob, n->label, true);
>      }
>  
>    output_record_start (ob, LTO_null);
> @@ -371,13 +487,13 @@ output_eh_region (struct output_block *ob, eh_region r)
>      }
>    else if (r->type == ERT_ALLOWED_EXCEPTIONS)
>      {
> -      lto_output_tree_ref (ob, r->u.allowed.type_list);
> -      lto_output_tree_ref (ob, r->u.allowed.label);
> +      stream_write_tree (ob, r->u.allowed.type_list, true);
> +      stream_write_tree (ob, r->u.allowed.label, true);
>        output_uleb128 (ob, r->u.allowed.filter);
>      }
>    else if (r->type == ERT_MUST_NOT_THROW)
>      {
> -      lto_output_tree_ref (ob, r->u.must_not_throw.failure_decl);
> +      stream_write_tree (ob, r->u.must_not_throw.failure_decl, true);
>        lto_output_location (ob, r->u.must_not_throw.failure_loc);
>      }
>  
> @@ -411,7 +527,7 @@ output_eh_lp (struct output_block *ob, eh_landing_pad lp)
>    else
>      output_zero (ob);
>  
> -  lto_output_tree_ref (ob, lp->post_landing_pad);
> +  stream_write_tree (ob, lp->post_landing_pad, true);
>  }
>  
>  
> @@ -445,7 +561,7 @@ output_eh_regions (struct output_block *ob, struct function *fn)
>        /* Emit all the runtime type data.  */
>        output_sleb128 (ob, VEC_length (tree, fn->eh->ttype_data));
>        FOR_EACH_VEC_ELT (tree, fn->eh->ttype_data, i, ttype)
> -	lto_output_tree_ref (ob, ttype);
> +	stream_write_tree (ob, ttype, true);
>  
>        /* Emit the table of action chains.  */
>        if (targetm.arm_eabi_unwinder)
> @@ -453,7 +569,7 @@ output_eh_regions (struct output_block *ob, struct function *fn)
>  	  tree t;
>  	  output_sleb128 (ob, VEC_length (tree, fn->eh->ehspec_data.arm_eabi));
>  	  FOR_EACH_VEC_ELT (tree, fn->eh->ehspec_data.arm_eabi, i, t)
> -	    lto_output_tree_ref (ob, t);
> +	    stream_write_tree (ob, t, true);
>  	}
>        else
>  	{
> @@ -491,7 +607,7 @@ output_ssa_names (struct output_block *ob, struct function *fn)
>  
>        output_uleb128 (ob, i);
>        lto_output_1_stream (ob->main_stream, SSA_NAME_IS_DEFAULT_DEF (ptr));
> -      lto_output_tree_ref (ob, SSA_NAME_VAR (ptr));
> +      stream_write_tree (ob, SSA_NAME_VAR (ptr), true);
>      }
>  
>    output_zero (ob);
> @@ -619,13 +735,13 @@ output_struct_function_base (struct output_block *ob, struct function *fn)
>    /* tree decl;						-- ignored */
>  
>    /* Output the static chain and non-local goto save area.  */
> -  lto_output_tree_ref (ob, fn->static_chain_decl);
> -  lto_output_tree_ref (ob, fn->nonlocal_goto_save_area);
> +  stream_write_tree (ob, fn->static_chain_decl, true);
> +  stream_write_tree (ob, fn->nonlocal_goto_save_area, true);
>  
>    /* Output all the local variables in the function.  */
>    output_sleb128 (ob, VEC_length (tree, fn->local_decls));
>    FOR_EACH_VEC_ELT (tree, fn->local_decls, i, t)
> -    lto_output_tree_ref (ob, t);
> +    stream_write_tree (ob, t, true);
>  
>    /* struct machine_function * machine;			-- ignored */
>    /* struct language_function * language;		-- maybe elsewhere */
> @@ -695,7 +811,7 @@ output_function (struct cgraph_node *node)
>    output_struct_function_base (ob, fn);
>  
>    /* Output the head of the arguments list.  */
> -  lto_output_tree_ref (ob, DECL_ARGUMENTS (function));
> +  stream_write_tree (ob, DECL_ARGUMENTS (function), true);
>  
>    /* Output all the SSA names used in the function.  */
>    output_ssa_names (ob, fn);
> @@ -705,7 +821,7 @@ output_function (struct cgraph_node *node)
>  
>    /* Output DECL_INITIAL for the function, which contains the tree of
>       lexical scopes.  */
> -  lto_output_tree (ob, DECL_INITIAL (function), true);
> +  stream_write_tree (ob, DECL_INITIAL (function), true);
>  
>    /* We will renumber the statements.  The code that does this uses
>       the same ordering that we use for serializing them so we can use
> @@ -838,8 +954,8 @@ output_unreferenced_globals (cgraph_node_set set, varpool_node_set vset)
>    FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p)
>      if (output_alias_pair_p (p, defined, set, vset))
>        {
> -	lto_output_tree_ref (ob, p->decl);
> -	lto_output_tree_ref (ob, p->target);
> +	stream_write_tree (ob, p->decl, true);
> +	stream_write_tree (ob, p->target, true);
>        }
>    symbol_alias_set_destroy (defined);
>  
> @@ -1009,7 +1125,7 @@ write_global_stream (struct output_block *ob,
>      {
>        t = lto_tree_ref_encoder_get_tree (encoder, index);
>        if (!lto_streamer_cache_lookup (ob->writer_cache, t, NULL))
> -	lto_output_tree (ob, t, false);
> +	stream_write_tree (ob, t, false);
>      }
>  }
>  
> diff --git a/gcc/lto-streamer.c b/gcc/lto-streamer.c
> index 328e654..01a681f 100644
> --- a/gcc/lto-streamer.c
> +++ b/gcc/lto-streamer.c
> @@ -257,86 +257,6 @@ print_lto_report (void)
>  }
>  
>  
> -/* Record NODE in CACHE.  */
> -
> -static void
> -lto_record_common_node (struct lto_streamer_cache_d *cache, tree node)
> -{
> -  /* We have to make sure to fill exactly the same number of
> -     elements for all frontends.  That can include NULL trees.
> -     As our hash table can't deal with zero entries we'll simply stream
> -     a random other tree.  A NULL tree never will be looked up so it
> -     doesn't matter which tree we replace it with, just to be sure
> -     use error_mark_node.  */
> -  if (!node)
> -    node = error_mark_node;
> -
> -  lto_streamer_cache_append (cache, node);
> -
> -  if (POINTER_TYPE_P (node)
> -      || TREE_CODE (node) == COMPLEX_TYPE
> -      || TREE_CODE (node) == ARRAY_TYPE)
> -    lto_record_common_node (cache, TREE_TYPE (node));
> -  else if (TREE_CODE (node) == RECORD_TYPE)
> -    {
> -      /* The FIELD_DECLs of structures should be shared, so that every
> -	 COMPONENT_REF uses the same tree node when referencing a field.
> -	 Pointer equality between FIELD_DECLs is used by the alias
> -	 machinery to compute overlapping memory references (See
> -	 nonoverlapping_component_refs_p).  */
> -      tree f;
> -      for (f = TYPE_FIELDS (node); f; f = TREE_CHAIN (f))
> -	lto_record_common_node (cache, f);
> -    }
> -}
> -
> -/* Preload common nodes into CACHE and make sure they are merged
> -   properly according to the gimple type table.  */
> -
> -static void
> -lto_preload_common_nodes (struct lto_streamer_cache_d *cache)
> -{
> -  unsigned i;
> -
> -  /* The MAIN_IDENTIFIER_NODE is normally set up by the front-end, but the
> -     LTO back-end must agree. Currently, the only languages that set this
> -     use the name "main".  */
> -  if (main_identifier_node)
> -    {
> -      const char *main_name = IDENTIFIER_POINTER (main_identifier_node);
> -      gcc_assert (strcmp (main_name, "main") == 0);
> -    }
> -  else
> -    main_identifier_node = get_identifier ("main");
> -
> -  gcc_assert (ptrdiff_type_node == integer_type_node);
> -
> -  /* FIXME lto.  In the C++ front-end, fileptr_type_node is defined as a
> -     variant copy of of ptr_type_node, rather than ptr_node itself.  The
> -     distinction should only be relevant to the front-end, so we always
> -     use the C definition here in lto1.
> -
> -     These should be assured in pass_ipa_free_lang_data.  */
> -  gcc_assert (fileptr_type_node == ptr_type_node);
> -  gcc_assert (TYPE_MAIN_VARIANT (fileptr_type_node) == ptr_type_node);
> -
> -  for (i = 0; i < itk_none; i++)
> -    /* Skip itk_char.  char_type_node is dependent on -f[un]signed-char.  */
> -    if (i != itk_char)
> -      lto_record_common_node (cache, integer_types[i]);
> -
> -  for (i = 0; i < TYPE_KIND_LAST; i++)
> -    lto_record_common_node (cache, sizetype_tab[i]);
> -
> -  for (i = 0; i < TI_MAX; i++)
> -    /* Skip boolean type and constants, they are frontend dependent.  */
> -    if (i != TI_BOOLEAN_TYPE
> -	&& i != TI_BOOLEAN_FALSE
> -	&& i != TI_BOOLEAN_TRUE)
> -      lto_record_common_node (cache, global_trees[i]);
> -}
> -
> -
>  #ifdef LTO_STREAMER_DEBUG
>  static htab_t tree_htab;
>  
> @@ -464,41 +384,12 @@ lto_check_version (int major, int minor)
>  }
>  
>  
> -/* Return true if EXPR is a tree node that can be written to disk.  */
> -static inline bool
> -lto_is_streamable (tree expr)
> -{
> -  enum tree_code code = TREE_CODE (expr);
> -
> -  /* Notice that we reject SSA_NAMEs as well.  We only emit the SSA
> -     name version in lto_output_tree_ref (see output_ssa_names).  */
> -  return !is_lang_specific (expr)
> -	 && code != SSA_NAME
> -	 && code != CALL_EXPR
> -	 && code != LANG_TYPE
> -	 && code != MODIFY_EXPR
> -	 && code != INIT_EXPR
> -	 && code != TARGET_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);
> -}
> -
> -
>  /* Initialize all the streamer hooks used for streaming GIMPLE.  */
>  
>  void
>  lto_streamer_hooks_init (void)
>  {
>    streamer_hooks_init ();
> -  streamer_hooks.name = "gimple";
> -  streamer_hooks.preload_common_nodes = lto_preload_common_nodes;
> -  streamer_hooks.is_streamable = lto_is_streamable;
> -  streamer_hooks.write_tree = lto_streamer_write_tree;
> -  streamer_hooks.read_tree = lto_streamer_read_tree;
> +  streamer_hooks.write_tree = lto_output_tree;
> +  streamer_hooks.read_tree = lto_input_tree;
>  }
> diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h
> index 30688ad..fc0255f 100644
> --- a/gcc/lto-streamer.h
> +++ b/gcc/lto-streamer.h
> @@ -821,6 +821,7 @@ tree lto_input_tree_ref (struct lto_input_block *, struct data_in *,
>  			 struct function *, enum LTO_tags);
>  void lto_tag_check_set (enum LTO_tags, int, ...);
>  void lto_init_eh (void);
> +tree lto_input_tree (struct lto_input_block *, struct data_in *);
>  
>  
>  /* In lto-streamer-out.c  */
> @@ -836,7 +837,6 @@ void lto_output_decl_state_streams (struct output_block *,
>  void lto_output_decl_state_refs (struct output_block *,
>  			         struct lto_output_stream *,
>  			         struct lto_out_decl_state *);
> -void lto_output_tree_ref (struct output_block *, tree);
>  void lto_output_location (struct output_block *, location_t);
>  
>  
> @@ -1030,17 +1030,6 @@ emit_label_in_global_context_p (tree label)
>    return DECL_NONLOCAL (label) || FORCED_LABEL (label);
>  }
>  
> -/* Return true if tree node EXPR should be streamed as a builtin.  For
> -   these nodes, we just emit the class and function code.  */
> -static inline bool
> -lto_stream_as_builtin_p (tree expr)
> -{
> -  return (TREE_CODE (expr) == FUNCTION_DECL
> -	  && DECL_IS_BUILTIN (expr)
> -	  && (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_NORMAL
> -	      || DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD));
> -}
> -
>  DEFINE_DECL_STREAM_FUNCS (TYPE, type)
>  DEFINE_DECL_STREAM_FUNCS (FIELD_DECL, field_decl)
>  DEFINE_DECL_STREAM_FUNCS (FN_DECL, fn_decl)
> diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c
> index 3574da0..83c41e6 100644
> --- a/gcc/lto/lto-lang.c
> +++ b/gcc/lto/lto-lang.c
> @@ -1099,6 +1099,7 @@ lto_init (void)
>       distinction should only be relevant to the front-end, so we
>       always use the C definition here in lto1.  */
>    gcc_assert (fileptr_type_node == ptr_type_node);
> +  gcc_assert (TYPE_MAIN_VARIANT (fileptr_type_node) == ptr_type_node);
>  
>    ptrdiff_type_node = integer_type_node;
>  
> diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
> index 93ff805..a50e777 100644
> --- a/gcc/lto/lto.c
> +++ b/gcc/lto/lto.c
> @@ -832,7 +832,7 @@ lto_read_decls (struct lto_file_decl_data *decl_data, const void *data,
>      {
>        tree t;
>        unsigned from = VEC_length (tree, data_in->reader_cache->nodes);
> -      t = lto_input_tree (&ib_main, data_in);
> +      t = stream_read_tree (&ib_main, data_in);
>        gcc_assert (t && ib_main.p <= ib_main.len);
>        uniquify_nodes (data_in, from);
>      }
> diff --git a/gcc/streamer-hooks.h b/gcc/streamer-hooks.h
> index 6dc9020..16c7361 100644
> --- a/gcc/streamer-hooks.h
> +++ b/gcc/streamer-hooks.h
> @@ -39,74 +39,20 @@ struct lto_streamer_cache_d;
>     Hooks marked [REQ] are required to be set.  Those marked [OPT] may
>     be NULL, if the streamer does not need to implement them.  */
>  struct streamer_hooks {
> -  /* [REQ] A string identifying this streamer.  */
> -  const char *name;
> -
> -  /* [REQ] Called by lto_streamer_cache_create to instantiate a cache of
> -     well-known nodes.  These are tree nodes that are always
> -     instantiated by the compiler on startup.  Additionally, these
> -     nodes need to be shared.  This function should call
> -     lto_streamer_cache_append on every tree node that it wishes to
> -     preload in the streamer cache.  This way, the writer will only
> -     write out a reference to the tree and the reader will instantiate
> -     the tree out of this pre-populated cache.  */
> -  void (*preload_common_nodes) (struct lto_streamer_cache_d *);
> -
> -  /* [REQ] Return true if the given tree is supported by this streamer.  */
> -  bool (*is_streamable) (tree);
> -
> -  /* [OPT] Called by lto_write_tree after writing all the common parts of
> -     a tree.  If defined, the callback is in charge of writing all
> -     the fields that lto_write_tree did not write out.  Arguments
> -     are as in lto_write_tree.
> -
> -     The following tree fields are not handled by common code:
> -
> -	DECL_ABSTRACT_ORIGIN
> -	DECL_INITIAL
> -	DECL_SAVED_TREE
> -
> -     Callbacks may choose to ignore or handle them.  If handled,
> -     the reader should read them in the exact same sequence written
> -     by the writer.  */
> +  /* [REQ] Called by every tree streaming routine that needs to write
> +     a tree node.  The arguments are: output_block where to write the
> +     node, the tree node to write and a boolean flag that should be true
> +     if the caller wants to write a reference to the tree, instead of the
> +     tree itself.  The referencing mechanism is up to each streamer to
> +     implement.  */
>    void (*write_tree) (struct output_block *, tree, bool);
>  
> -  /* [OPT] Called by lto_read_tree after reading all the common parts of
> -     a tree.  If defined, the callback is in charge of reading all
> -     the fields that lto_read_tree did not read in.  Arguments
> -     are as in lto_read_tree.  */
> -  void (*read_tree) (struct lto_input_block *, struct data_in *, tree);
> -
> -  /* [OPT] 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 global declarations).  */
> -  bool (*indexable_with_decls_p) (tree);
> -
> -  /* [OPT] 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);
> -
> -  /* [OPT] Called by unpack_value_fields to retrieve any non-pointer fields
> -     in the tree structure.  The arguments are as in unpack_value_fields.  */
> -  void (*unpack_value_fields) (struct bitpack_d *, tree);
> -
> -  /* [OPT] Called by lto_materialize_tree for tree nodes that it does not
> -     know how to allocate memory for.  If defined, this hook should
> -     return a new tree node of the given code.  The data_in and
> -     input_block arguments are passed in case the hook needs to
> -     read more data from the stream to allocate the node.
> -     If this hook returns NULL, then lto_materialize_tree will attempt
> -     to allocate the tree by calling make_node directly.  */
> -  tree (*alloc_tree) (enum tree_code, struct lto_input_block *,
> -                      struct data_in *);
> -
> -  /* [OPT] Called by lto_output_tree_header to write any streamer-specific
> -     information needed to allocate the tree.  This hook may assume
> -     that the basic header data (tree code, etc) has already been
> -     written.  It should only write any extra data needed to allocate
> -     the node (e.g., in the case of CALL_EXPR, this hook would write
> -     the number of arguments to the CALL_EXPR).  */
> -  void (*output_tree_header) (struct output_block *, tree);
> +  /* [REQ] Called by every tree streaming routine that needs to read
> +     a tree node.  It takes two arguments: an lto_input_block pointing
> +     to the buffer where to read from and a data_in instance with tables
> +     and descriptors needed by the unpickling routines.  It returns the
> +     tree instantiated from the stream.  */
> +  tree (*read_tree) (struct lto_input_block *, struct data_in *);
>  
>    /* [OPT] Called by lto_input_location to retrieve the source location of the
>       tree currently being read. If this hook returns NULL, lto_input_location
> @@ -117,14 +63,14 @@ struct streamer_hooks {
>       tree currently being written. If this hook returns NULL,
>       lto_output_location defaults to calling lto_output_location_bitpack.  */
>    void (*output_location) (struct output_block *, location_t);
> -
> -  /* [OPT] Non-zero if the streamer has special constants that cannot be
> -     shared and are used in pointer-equality tests (e.g., void_zero_node,
> -     truthvalue_false_node, etc).  These constants will be present in
> -     the streamer cache and should be streamed as references.  */
> -  unsigned has_unique_integer_csts_p : 1;
>  };
>  
> +#define stream_write_tree(OB, EXPR, REF_P) \
> +    streamer_hooks.write_tree(OB, EXPR, REF_P)
> +
> +#define stream_read_tree(IB, DATA_IN) \
> +    streamer_hooks.read_tree(IB, DATA_IN)
> +
>  /* Streamer hooks.  */
>  extern struct streamer_hooks streamer_hooks;
>  
> diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c
> index 25d076e..43bbe0e 100644
> --- a/gcc/tree-streamer-in.c
> +++ b/gcc/tree-streamer-in.c
> @@ -75,7 +75,7 @@ lto_input_chain (struct lto_input_block *ib, struct data_in *data_in)
>    count = lto_input_sleb128 (ib);
>    for (i = 0; i < count; i++)
>      {
> -      curr = lto_input_tree (ib, data_in);
> +      curr = stream_read_tree (ib, data_in);
>        if (prev)
>  	TREE_CHAIN (prev) = curr;
>        else
> @@ -404,9 +404,32 @@ unpack_value_fields (struct bitpack_d *bp, tree expr)
>  
>    if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
>      unpack_ts_translation_unit_decl_value_fields (bp, expr);
> +}
> +
> +
> +/* Read all the language-independent bitfield values for EXPR from IB.
> +   Return the partially unpacked bitpack so the caller can unpack any other
> +   bitfield values that the writer may have written.  */
>  
> -  if (streamer_hooks.unpack_value_fields)
> -    streamer_hooks.unpack_value_fields (bp, expr);
> +struct bitpack_d
> +tree_read_bitfields (struct lto_input_block *ib, tree expr)
> +{
> +  enum tree_code code;
> +  struct bitpack_d bp;
> +
> +  /* Read the bitpack of non-pointer values from IB.  */
> +  bp = lto_input_bitpack (ib);
> +
> +  /* The first word in BP contains the code of the tree that we
> +     are about to read.  */
> +  code = (enum tree_code) bp_unpack_value (&bp, 16);
> +  lto_tag_check (lto_tree_code_to_tag (code),
> +		 lto_tree_code_to_tag (TREE_CODE (expr)));
> +
> +  /* Unpack all the value fields from BP.  */
> +  unpack_value_fields (&bp, expr);
> +
> +  return bp;
>  }
>  
>  
> @@ -414,11 +437,10 @@ unpack_value_fields (struct bitpack_d *bp, tree expr)
>     DATA_IN.  The code for the new tree should match TAG.  Store in
>     *IX_P the index into the reader cache where the new tree is stored.  */
>  
> -static tree
> +tree
>  lto_materialize_tree (struct lto_input_block *ib, struct data_in *data_in,
>  		      enum LTO_tags tag)
>  {
> -  struct bitpack_d bp;
>    enum tree_code code;
>    tree result;
>  #ifdef LTO_STREAMER_DEBUG
> @@ -456,17 +478,16 @@ lto_materialize_tree (struct lto_input_block *ib, struct data_in *data_in,
>        unsigned HOST_WIDE_INT len = lto_input_uleb128 (ib);
>        result = make_tree_binfo (len);
>      }
> +  else if (code == CALL_EXPR)
> +    {
> +      unsigned HOST_WIDE_INT nargs = lto_input_uleb128 (ib);
> +      return build_vl_exp (CALL_EXPR, nargs + 3);
> +    }
>    else
>      {
> -      /* For all other nodes, see if the streamer knows how to allocate
> -	 it.  */
> -      if (streamer_hooks.alloc_tree)
> -	result = streamer_hooks.alloc_tree (code, ib, data_in);
> -
> -      /* If the hook did not handle it, materialize the tree with a raw
> +      /* For all other nodes, materialize the tree with a raw
>  	 make_node call.  */
> -      if (result == NULL_TREE)
> -	result = make_node (code);
> +      result = make_node (code);
>      }
>  
>  #ifdef LTO_STREAMER_DEBUG
> @@ -478,22 +499,6 @@ lto_materialize_tree (struct lto_input_block *ib, struct data_in *data_in,
>    lto_orig_address_map (result, (intptr_t) orig_address_in_writer);
>  #endif
>  
> -  /* Read the bitpack of non-pointer values from IB.  */
> -  bp = lto_input_bitpack (ib);
> -
> -  /* The first word in BP contains the code of the tree that we
> -     are about to read.  */
> -  code = (enum tree_code) bp_unpack_value (&bp, 16);
> -  lto_tag_check (lto_tree_code_to_tag (code), tag);
> -
> -  /* Unpack all the value fields from BP.  */
> -  unpack_value_fields (&bp, result);
> -
> -  /* Enter RESULT in the reader cache.  This will make RESULT
> -     available so that circular references in the rest of the tree
> -     structure can be resolved in subsequent calls to lto_input_tree.  */
> -  lto_streamer_cache_append (data_in->reader_cache, result);
> -
>    return result;
>  }
>  
> @@ -508,7 +513,7 @@ lto_input_ts_common_tree_pointers (struct lto_input_block *ib,
>  				   struct data_in *data_in, tree expr)
>  {
>    if (TREE_CODE (expr) != IDENTIFIER_NODE)
> -    TREE_TYPE (expr) = lto_input_tree (ib, data_in);
> +    TREE_TYPE (expr) = stream_read_tree (ib, data_in);
>  }
>  
>  
> @@ -532,8 +537,8 @@ static void
>  lto_input_ts_complex_tree_pointers (struct lto_input_block *ib,
>  				    struct data_in *data_in, tree expr)
>  {
> -  TREE_REALPART (expr) = lto_input_tree (ib, data_in);
> -  TREE_IMAGPART (expr) = lto_input_tree (ib, data_in);
> +  TREE_REALPART (expr) = stream_read_tree (ib, data_in);
> +  TREE_IMAGPART (expr) = stream_read_tree (ib, data_in);
>  }
>  
>  
> @@ -545,8 +550,8 @@ static void
>  lto_input_ts_decl_minimal_tree_pointers (struct lto_input_block *ib,
>  					 struct data_in *data_in, tree expr)
>  {
> -  DECL_NAME (expr) = lto_input_tree (ib, data_in);
> -  DECL_CONTEXT (expr) = lto_input_tree (ib, data_in);
> +  DECL_NAME (expr) = stream_read_tree (ib, data_in);
> +  DECL_CONTEXT (expr) = stream_read_tree (ib, data_in);
>    DECL_SOURCE_LOCATION (expr) = lto_input_location (ib, data_in);
>  }
>  
> @@ -559,9 +564,9 @@ static void
>  lto_input_ts_decl_common_tree_pointers (struct lto_input_block *ib,
>  					struct data_in *data_in, tree expr)
>  {
> -  DECL_SIZE (expr) = lto_input_tree (ib, data_in);
> -  DECL_SIZE_UNIT (expr) = lto_input_tree (ib, data_in);
> -  DECL_ATTRIBUTES (expr) = lto_input_tree (ib, data_in);
> +  DECL_SIZE (expr) = stream_read_tree (ib, data_in);
> +  DECL_SIZE_UNIT (expr) = stream_read_tree (ib, data_in);
> +  DECL_ATTRIBUTES (expr) = stream_read_tree (ib, data_in);
>  
>    /* Do not stream DECL_ABSTRACT_ORIGIN.  We cannot handle debug information
>       for early inlining so drop it on the floor instead of ICEing in
> @@ -573,11 +578,11 @@ lto_input_ts_decl_common_tree_pointers (struct lto_input_block *ib,
>    if ((TREE_CODE (expr) == VAR_DECL
>         || TREE_CODE (expr) == PARM_DECL)
>        && DECL_HAS_VALUE_EXPR_P (expr))
> -    SET_DECL_VALUE_EXPR (expr, lto_input_tree (ib, data_in));
> +    SET_DECL_VALUE_EXPR (expr, stream_read_tree (ib, data_in));
>  
>    if (TREE_CODE (expr) == VAR_DECL)
>      {
> -      tree dexpr = lto_input_tree (ib, data_in);
> +      tree dexpr = stream_read_tree (ib, data_in);
>        if (dexpr)
>  	SET_DECL_DEBUG_EXPR (expr, dexpr);
>      }
> @@ -594,10 +599,10 @@ lto_input_ts_decl_non_common_tree_pointers (struct lto_input_block *ib,
>  {
>    if (TREE_CODE (expr) == FUNCTION_DECL)
>      {
> -      DECL_ARGUMENTS (expr) = lto_input_tree (ib, data_in);
> -      DECL_RESULT (expr) = lto_input_tree (ib, data_in);
> +      DECL_ARGUMENTS (expr) = stream_read_tree (ib, data_in);
> +      DECL_RESULT (expr) = stream_read_tree (ib, data_in);
>      }
> -  DECL_VINDEX (expr) = lto_input_tree (ib, data_in);
> +  DECL_VINDEX (expr) = stream_read_tree (ib, data_in);
>  }
>  
>  
> @@ -611,15 +616,15 @@ lto_input_ts_decl_with_vis_tree_pointers (struct lto_input_block *ib,
>  {
>    tree id;
>  
> -  id = lto_input_tree (ib, data_in);
> +  id = stream_read_tree (ib, data_in);
>    if (id)
>      {
>        gcc_assert (TREE_CODE (id) == IDENTIFIER_NODE);
>        SET_DECL_ASSEMBLER_NAME (expr, id);
>      }
>  
> -  DECL_SECTION_NAME (expr) = lto_input_tree (ib, data_in);
> -  DECL_COMDAT_GROUP (expr) = lto_input_tree (ib, data_in);
> +  DECL_SECTION_NAME (expr) = stream_read_tree (ib, data_in);
> +  DECL_COMDAT_GROUP (expr) = stream_read_tree (ib, data_in);
>  }
>  
>  
> @@ -631,11 +636,11 @@ static void
>  lto_input_ts_field_decl_tree_pointers (struct lto_input_block *ib,
>  				       struct data_in *data_in, tree expr)
>  {
> -  DECL_FIELD_OFFSET (expr) = lto_input_tree (ib, data_in);
> -  DECL_BIT_FIELD_TYPE (expr) = lto_input_tree (ib, data_in);
> -  DECL_QUALIFIER (expr) = lto_input_tree (ib, data_in);
> -  DECL_FIELD_BIT_OFFSET (expr) = lto_input_tree (ib, data_in);
> -  DECL_FCONTEXT (expr) = lto_input_tree (ib, data_in);
> +  DECL_FIELD_OFFSET (expr) = stream_read_tree (ib, data_in);
> +  DECL_BIT_FIELD_TYPE (expr) = stream_read_tree (ib, data_in);
> +  DECL_QUALIFIER (expr) = stream_read_tree (ib, data_in);
> +  DECL_FIELD_BIT_OFFSET (expr) = stream_read_tree (ib, data_in);
> +  DECL_FCONTEXT (expr) = stream_read_tree (ib, data_in);
>    TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
>  }
>  
> @@ -650,9 +655,9 @@ lto_input_ts_function_decl_tree_pointers (struct lto_input_block *ib,
>  {
>    /* DECL_STRUCT_FUNCTION is handled by lto_input_function.  FIXME lto,
>       maybe it should be handled here?  */
> -  DECL_FUNCTION_PERSONALITY (expr) = lto_input_tree (ib, data_in);
> -  DECL_FUNCTION_SPECIFIC_TARGET (expr) = lto_input_tree (ib, data_in);
> -  DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr) = lto_input_tree (ib, data_in);
> +  DECL_FUNCTION_PERSONALITY (expr) = stream_read_tree (ib, data_in);
> +  DECL_FUNCTION_SPECIFIC_TARGET (expr) = stream_read_tree (ib, data_in);
> +  DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr) = stream_read_tree (ib, data_in);
>  
>    /* If the file contains a function with an EH personality set,
>       then it was compiled with -fexceptions.  In that case, initialize
> @@ -670,19 +675,19 @@ static void
>  lto_input_ts_type_common_tree_pointers (struct lto_input_block *ib,
>  					struct data_in *data_in, tree expr)
>  {
> -  TYPE_SIZE (expr) = lto_input_tree (ib, data_in);
> -  TYPE_SIZE_UNIT (expr) = lto_input_tree (ib, data_in);
> -  TYPE_ATTRIBUTES (expr) = lto_input_tree (ib, data_in);
> -  TYPE_NAME (expr) = lto_input_tree (ib, data_in);
> +  TYPE_SIZE (expr) = stream_read_tree (ib, data_in);
> +  TYPE_SIZE_UNIT (expr) = stream_read_tree (ib, data_in);
> +  TYPE_ATTRIBUTES (expr) = stream_read_tree (ib, data_in);
> +  TYPE_NAME (expr) = stream_read_tree (ib, data_in);
>    /* Do not stream TYPE_POINTER_TO or TYPE_REFERENCE_TO.  They will be
>       reconstructed during fixup.  */
>    /* Do not stream TYPE_NEXT_VARIANT, we reconstruct the variant lists
>       during fixup.  */
> -  TYPE_MAIN_VARIANT (expr) = lto_input_tree (ib, data_in);
> -  TYPE_CONTEXT (expr) = lto_input_tree (ib, data_in);
> +  TYPE_MAIN_VARIANT (expr) = stream_read_tree (ib, data_in);
> +  TYPE_CONTEXT (expr) = stream_read_tree (ib, data_in);
>    /* TYPE_CANONICAL gets re-computed during type merging.  */
>    TYPE_CANONICAL (expr) = NULL_TREE;
> -  TYPE_STUB_DECL (expr) = lto_input_tree (ib, data_in);
> +  TYPE_STUB_DECL (expr) = stream_read_tree (ib, data_in);
>  }
>  
>  /* Read all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
> @@ -695,20 +700,20 @@ lto_input_ts_type_non_common_tree_pointers (struct lto_input_block *ib,
>  					    tree expr)
>  {
>    if (TREE_CODE (expr) == ENUMERAL_TYPE)
> -    TYPE_VALUES (expr) = lto_input_tree (ib, data_in);
> +    TYPE_VALUES (expr) = stream_read_tree (ib, data_in);
>    else if (TREE_CODE (expr) == ARRAY_TYPE)
> -    TYPE_DOMAIN (expr) = lto_input_tree (ib, data_in);
> +    TYPE_DOMAIN (expr) = stream_read_tree (ib, data_in);
>    else if (RECORD_OR_UNION_TYPE_P (expr))
> -    TYPE_FIELDS (expr) = lto_input_tree (ib, data_in);
> +    TYPE_FIELDS (expr) = stream_read_tree (ib, data_in);
>    else if (TREE_CODE (expr) == FUNCTION_TYPE
>  	   || TREE_CODE (expr) == METHOD_TYPE)
> -    TYPE_ARG_TYPES (expr) = lto_input_tree (ib, data_in);
> +    TYPE_ARG_TYPES (expr) = stream_read_tree (ib, data_in);
>  
>    if (!POINTER_TYPE_P (expr))
> -    TYPE_MINVAL (expr) = lto_input_tree (ib, data_in);
> -  TYPE_MAXVAL (expr) = lto_input_tree (ib, data_in);
> +    TYPE_MINVAL (expr) = stream_read_tree (ib, data_in);
> +  TYPE_MAXVAL (expr) = stream_read_tree (ib, data_in);
>    if (RECORD_OR_UNION_TYPE_P (expr))
> -    TYPE_BINFO (expr) = lto_input_tree (ib, data_in);
> +    TYPE_BINFO (expr) = stream_read_tree (ib, data_in);
>  }
>  
>  
> @@ -720,8 +725,8 @@ static void
>  lto_input_ts_list_tree_pointers (struct lto_input_block *ib,
>  				 struct data_in *data_in, tree expr)
>  {
> -  TREE_PURPOSE (expr) = lto_input_tree (ib, data_in);
> -  TREE_VALUE (expr) = lto_input_tree (ib, data_in);
> +  TREE_PURPOSE (expr) = stream_read_tree (ib, data_in);
> +  TREE_VALUE (expr) = stream_read_tree (ib, data_in);
>    TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
>  }
>  
> @@ -739,7 +744,7 @@ lto_input_ts_vec_tree_pointers (struct lto_input_block *ib,
>    /* Note that TREE_VEC_LENGTH was read by lto_materialize_tree to
>       instantiate EXPR.  */
>    for (i = 0; i < TREE_VEC_LENGTH (expr); i++)
> -    TREE_VEC_ELT (expr, i) = lto_input_tree (ib, data_in);
> +    TREE_VEC_ELT (expr, i) = stream_read_tree (ib, data_in);
>  }
>  
>  
> @@ -759,11 +764,11 @@ lto_input_ts_exp_tree_pointers (struct lto_input_block *ib,
>    gcc_assert (length == TREE_OPERAND_LENGTH (expr));
>  
>    for (i = 0; i < length; i++)
> -    TREE_OPERAND (expr, i) = lto_input_tree (ib, data_in);
> +    TREE_OPERAND (expr, i) = stream_read_tree (ib, data_in);
>  
>    loc = lto_input_location (ib, data_in);
>    SET_EXPR_LOCATION (expr, loc);
> -  TREE_BLOCK (expr) = lto_input_tree (ib, data_in);
> +  TREE_BLOCK (expr) = stream_read_tree (ib, data_in);
>  }
>  
>  
> @@ -784,13 +789,13 @@ lto_input_ts_block_tree_pointers (struct lto_input_block *ib,
>       for early inlining so drop it on the floor instead of ICEing in
>       dwarf2out.c.  */
>  
> -  BLOCK_SUPERCONTEXT (expr) = lto_input_tree (ib, data_in);
> +  BLOCK_SUPERCONTEXT (expr) = stream_read_tree (ib, data_in);
>  
>    /* Do not stream BLOCK_ABSTRACT_ORIGIN.  We cannot handle debug information
>       for early inlining so drop it on the floor instead of ICEing in
>       dwarf2out.c.  */
> -  BLOCK_FRAGMENT_ORIGIN (expr) = lto_input_tree (ib, data_in);
> -  BLOCK_FRAGMENT_CHAIN (expr) = lto_input_tree (ib, data_in);
> +  BLOCK_FRAGMENT_ORIGIN (expr) = stream_read_tree (ib, data_in);
> +  BLOCK_FRAGMENT_CHAIN (expr) = stream_read_tree (ib, data_in);
>  
>    /* We re-compute BLOCK_SUBBLOCKS of our parent here instead
>       of streaming it.  For non-BLOCK BLOCK_SUPERCONTEXTs we still
> @@ -831,16 +836,16 @@ lto_input_ts_binfo_tree_pointers (struct lto_input_block *ib,
>       list on the writer side.  */
>    do
>      {
> -      t = lto_input_tree (ib, data_in);
> +      t = stream_read_tree (ib, data_in);
>        if (t)
>  	VEC_quick_push (tree, BINFO_BASE_BINFOS (expr), t);
>      }
>    while (t);
>  
> -  BINFO_OFFSET (expr) = lto_input_tree (ib, data_in);
> -  BINFO_VTABLE (expr) = lto_input_tree (ib, data_in);
> -  BINFO_VIRTUALS (expr) = lto_input_tree (ib, data_in);
> -  BINFO_VPTR_FIELD (expr) = lto_input_tree (ib, data_in);
> +  BINFO_OFFSET (expr) = stream_read_tree (ib, data_in);
> +  BINFO_VTABLE (expr) = stream_read_tree (ib, data_in);
> +  BINFO_VIRTUALS (expr) = stream_read_tree (ib, data_in);
> +  BINFO_VPTR_FIELD (expr) = stream_read_tree (ib, data_in);
>  
>    len = lto_input_uleb128 (ib);
>    if (len > 0)
> @@ -848,14 +853,14 @@ lto_input_ts_binfo_tree_pointers (struct lto_input_block *ib,
>        VEC_reserve_exact (tree, gc, BINFO_BASE_ACCESSES (expr), len);
>        for (i = 0; i < len; i++)
>  	{
> -	  tree a = lto_input_tree (ib, data_in);
> +	  tree a = stream_read_tree (ib, data_in);
>  	  VEC_quick_push (tree, BINFO_BASE_ACCESSES (expr), a);
>  	}
>      }
>  
> -  BINFO_INHERITANCE_CHAIN (expr) = lto_input_tree (ib, data_in);
> -  BINFO_SUBVTT_INDEX (expr) = lto_input_tree (ib, data_in);
> -  BINFO_VPTR_INDEX (expr) = lto_input_tree (ib, data_in);
> +  BINFO_INHERITANCE_CHAIN (expr) = stream_read_tree (ib, data_in);
> +  BINFO_SUBVTT_INDEX (expr) = stream_read_tree (ib, data_in);
> +  BINFO_VPTR_INDEX (expr) = stream_read_tree (ib, data_in);
>  }
>  
>  
> @@ -874,8 +879,8 @@ lto_input_ts_constructor_tree_pointers (struct lto_input_block *ib,
>      {
>        tree index, value;
>  
> -      index = lto_input_tree (ib, data_in);
> -      value = lto_input_tree (ib, data_in);
> +      index = stream_read_tree (ib, data_in);
> +      value = stream_read_tree (ib, data_in);
>        CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (expr), index, value);
>      }
>  }
> @@ -909,11 +914,10 @@ lto_input_ts_translation_unit_decl_tree_pointers (struct lto_input_block *ib,
>    VEC_safe_push (tree, gc, all_translation_units, expr);
>  }
>  
> -/* Helper for lto_input_tree.  Read all pointer fields in EXPR from
> -   input block IB.  DATA_IN contains tables and descriptors for the
> -   file being read.  */
> +/* Read all pointer fields in EXPR from input block IB.  DATA_IN
> +   contains tables and descriptors for the file being read.  */
>  
> -static void
> +void
>  lto_input_tree_pointers (struct lto_input_block *ib, struct data_in *data_in,
>  			 tree expr)
>  {
> @@ -980,52 +984,17 @@ lto_input_tree_pointers (struct lto_input_block *ib, struct data_in *data_in,
>  }
>  
>  
> -/* Read the physical representation of a tree node with tag TAG from
> -   input block IB using the per-file context in DATA_IN.  */
> -
> -static tree
> -lto_read_tree (struct lto_input_block *ib, struct data_in *data_in,
> -	       enum LTO_tags tag)
> -{
> -  tree result;
> -
> -  result = lto_materialize_tree (ib, data_in, tag);
> -
> -  /* Read all the pointer fields in RESULT.  */
> -  lto_input_tree_pointers (ib, data_in, result);
> -
> -  /* Call back into the streaming module to read anything else it
> -     may need.  */
> -  if (streamer_hooks.read_tree)
> -    streamer_hooks.read_tree (ib, data_in, result);
> -
> -  /* We should never try to instantiate an MD or NORMAL builtin here.  */
> -  if (TREE_CODE (result) == FUNCTION_DECL)
> -    gcc_assert (!lto_stream_as_builtin_p (result));
> -
> -  /* end_marker = */ lto_input_1_unsigned (ib);
> -
> -#ifdef LTO_STREAMER_DEBUG
> -  /* Remove the mapping to RESULT's original address set by
> -     lto_materialize_tree.  */
> -  lto_orig_address_remove (result);
> -#endif
> -
> -  return result;
> -}
> -
> -
>  /* Read and INTEGER_CST node from input block IB using the per-file
>     context in DATA_IN.  */
>  
> -static tree
> +tree
>  lto_input_integer_cst (struct lto_input_block *ib, struct data_in *data_in)
>  {
>    tree result, type;
>    HOST_WIDE_INT low, high;
>    bool overflow_p;
>  
> -  type = lto_input_tree (ib, data_in);
> +  type = stream_read_tree (ib, data_in);
>    overflow_p = (lto_input_1_unsigned (ib) != 0);
>    low = lto_input_uleb128 (ib);
>    high = lto_input_uleb128 (ib);
> @@ -1046,7 +1015,7 @@ lto_input_integer_cst (struct lto_input_block *ib, struct data_in *data_in)
>  /* Read an index IX from input block IB and return the tree node at
>     DATA_IN->FILE_DATA->GLOBALS_INDEX[IX].  */
>  
> -static tree
> +tree
>  lto_get_pickled_tree (struct lto_input_block *ib, struct data_in *data_in)
>  {
>    unsigned HOST_WIDE_INT ix;
> @@ -1065,9 +1034,9 @@ lto_get_pickled_tree (struct lto_input_block *ib, struct data_in *data_in)
>  
>  
>  /* Read a code and class from input block IB and return the
> -   corresponding builtin.  DATA_IN is as in lto_input_tree.  */
> +   corresponding builtin.  DATA_IN is as in stream_read_tree.  */
>  
> -static tree
> +tree
>  lto_get_builtin_tree (struct lto_input_block *ib, struct data_in *data_in)
>  {
>    enum built_in_class fclass;
> @@ -1104,53 +1073,3 @@ lto_get_builtin_tree (struct lto_input_block *ib, struct data_in *data_in)
>  
>    return result;
>  }
> -
> -
> -/* Read a tree from input block IB using the per-file context in
> -   DATA_IN.  This context is used, for example, to resolve references
> -   to previously read nodes.  */
> -
> -tree
> -lto_input_tree (struct lto_input_block *ib, struct data_in *data_in)
> -{
> -  enum LTO_tags tag;
> -  tree result;
> -
> -  tag = input_record_start (ib);
> -  gcc_assert ((unsigned) tag < (unsigned) LTO_NUM_TAGS);
> -
> -  if (tag == LTO_null)
> -    result = NULL_TREE;
> -  else if (tag >= LTO_field_decl_ref && tag <= LTO_global_decl_ref)
> -    {
> -      /* If TAG is a reference to an indexable tree, the next value
> -	 in IB is the index into the table where we expect to find
> -	 that tree.  */
> -      result = lto_input_tree_ref (ib, data_in, cfun, tag);
> -    }
> -  else if (tag == LTO_tree_pickle_reference)
> -    {
> -      /* If TAG is a reference to a previously read tree, look it up in
> -	 the reader cache.  */
> -      result = lto_get_pickled_tree (ib, data_in);
> -    }
> -  else if (tag == LTO_builtin_decl)
> -    {
> -      /* If we are going to read a built-in function, all we need is
> -	 the code and class.  */
> -      result = lto_get_builtin_tree (ib, data_in);
> -    }
> -  else if (tag == lto_tree_code_to_tag (INTEGER_CST))
> -    {
> -      /* For integer constants we only need the type and its hi/low
> -	 words.  */
> -      result = lto_input_integer_cst (ib, data_in);
> -    }
> -  else
> -    {
> -      /* Otherwise, materialize a new node from IB.  */
> -      result = lto_read_tree (ib, data_in, tag);
> -    }
> -
> -  return result;
> -}
> diff --git a/gcc/tree-streamer-out.c b/gcc/tree-streamer-out.c
> index b4ec28d..08af52a 100644
> --- a/gcc/tree-streamer-out.c
> +++ b/gcc/tree-streamer-out.c
> @@ -308,7 +308,7 @@ pack_ts_translation_unit_decl_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSE
>  
>  /* Pack all the non-pointer fields in EXPR into a bit pack.  */
>  
> -static void
> +void
>  pack_value_fields (struct bitpack_d *bp, tree expr)
>  {
>    enum tree_code code;
> @@ -345,29 +345,13 @@ pack_value_fields (struct bitpack_d *bp, tree expr)
>  
>    if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
>      pack_ts_translation_unit_decl_value_fields (bp, expr);
> -
> -  if (streamer_hooks.pack_value_fields)
> -    streamer_hooks.pack_value_fields (bp, expr);
> -}
> -
> -
> -/* If REF_P is true, emit a reference to EXPR in output block OB,
> -   otherwise emit the physical representation of EXPR in OB.  */
> -
> -static inline void
> -lto_output_tree_or_ref (struct output_block *ob, tree expr, bool ref_p)
> -{
> -  if (ref_p)
> -    lto_output_tree_ref (ob, expr);
> -  else
> -    lto_output_tree (ob, expr, false);
>  }
>  
>  
>  /* Write the code and class of builtin EXPR to output block OB.  IX is
>     the index into the streamer cache where EXPR is stored.*/
>  
> -static void
> +void
>  lto_output_builtin_tree (struct output_block *ob, tree expr)
>  {
>    gcc_assert (lto_stream_as_builtin_p (expr));
> @@ -399,39 +383,6 @@ lto_output_builtin_tree (struct output_block *ob, tree expr)
>  }
>  
>  
> -/* GIMPLE hook for writing GIMPLE-specific parts of trees.  OB, EXPR
> -   and REF_P are as in lto_write_tree.  */
> -
> -void
> -lto_streamer_write_tree (struct output_block *ob, tree expr, bool ref_p)
> -{
> -  if (DECL_P (expr)
> -      && TREE_CODE (expr) != FUNCTION_DECL
> -      && TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
> -    {
> -      /* Handle DECL_INITIAL for symbols.  */
> -      tree initial = DECL_INITIAL (expr);
> -      if (TREE_CODE (expr) == VAR_DECL
> -	  && (TREE_STATIC (expr) || DECL_EXTERNAL (expr))
> -	  && initial)
> -	{
> -	  lto_varpool_encoder_t varpool_encoder;
> -	  struct varpool_node *vnode;
> -
> -	  varpool_encoder = ob->decl_state->varpool_node_encoder;
> -	  vnode = varpool_get_node (expr);
> -	  if (!vnode)
> -	    initial = error_mark_node;
> -	  else if (!lto_varpool_encoder_encode_initializer_p (varpool_encoder,
> -							      vnode))
> -	    initial = NULL;
> -	}
> -
> -      lto_output_tree_or_ref (ob, initial, ref_p);
> -    }
> -}
> -
> -
>  /* Emit the chain of tree nodes starting at T.  OB is the output block
>     to write to.  REF_P is true if chain elements should be emitted
>     as references.  */
> @@ -452,7 +403,7 @@ lto_output_chain (struct output_block *ob, tree t, bool ref_p)
>        saved_chain = TREE_CHAIN (t);
>        TREE_CHAIN (t) = NULL_TREE;
>  
> -      lto_output_tree_or_ref (ob, t, ref_p);
> +      stream_write_tree (ob, t, ref_p);
>  
>        TREE_CHAIN (t) = saved_chain;
>        t = TREE_CHAIN (t);
> @@ -469,7 +420,7 @@ lto_output_ts_common_tree_pointers (struct output_block *ob, tree expr,
>  				    bool ref_p)
>  {
>    if (TREE_CODE (expr) != IDENTIFIER_NODE)
> -    lto_output_tree_or_ref (ob, TREE_TYPE (expr), ref_p);
> +    stream_write_tree (ob, TREE_TYPE (expr), ref_p);
>  }
>  
>  
> @@ -493,8 +444,8 @@ static void
>  lto_output_ts_complex_tree_pointers (struct output_block *ob, tree expr,
>  				     bool ref_p)
>  {
> -  lto_output_tree_or_ref (ob, TREE_REALPART (expr), ref_p);
> -  lto_output_tree_or_ref (ob, TREE_IMAGPART (expr), ref_p);
> +  stream_write_tree (ob, TREE_REALPART (expr), ref_p);
> +  stream_write_tree (ob, TREE_IMAGPART (expr), ref_p);
>  }
>  
>  
> @@ -506,8 +457,8 @@ static void
>  lto_output_ts_decl_minimal_tree_pointers (struct output_block *ob, tree expr,
>  					  bool ref_p)
>  {
> -  lto_output_tree_or_ref (ob, DECL_NAME (expr), ref_p);
> -  lto_output_tree_or_ref (ob, DECL_CONTEXT (expr), ref_p);
> +  stream_write_tree (ob, DECL_NAME (expr), ref_p);
> +  stream_write_tree (ob, DECL_CONTEXT (expr), ref_p);
>    lto_output_location (ob, DECL_SOURCE_LOCATION (expr));
>  }
>  
> @@ -520,13 +471,13 @@ static void
>  lto_output_ts_decl_common_tree_pointers (struct output_block *ob, tree expr,
>  					 bool ref_p)
>  {
> -  lto_output_tree_or_ref (ob, DECL_SIZE (expr), ref_p);
> -  lto_output_tree_or_ref (ob, DECL_SIZE_UNIT (expr), ref_p);
> +  stream_write_tree (ob, DECL_SIZE (expr), ref_p);
> +  stream_write_tree (ob, DECL_SIZE_UNIT (expr), ref_p);
>  
>    /* Note, DECL_INITIAL is not handled here.  Since DECL_INITIAL needs
>       special handling in LTO, it must be handled by streamer hooks.  */
>  
> -  lto_output_tree_or_ref (ob, DECL_ATTRIBUTES (expr), ref_p);
> +  stream_write_tree (ob, DECL_ATTRIBUTES (expr), ref_p);
>  
>    /* Do not stream DECL_ABSTRACT_ORIGIN.  We cannot handle debug information
>       for early inlining so drop it on the floor instead of ICEing in
> @@ -538,10 +489,10 @@ lto_output_ts_decl_common_tree_pointers (struct output_block *ob, tree expr,
>    if ((TREE_CODE (expr) == VAR_DECL
>         || TREE_CODE (expr) == PARM_DECL)
>        && DECL_HAS_VALUE_EXPR_P (expr))
> -    lto_output_tree_or_ref (ob, DECL_VALUE_EXPR (expr), ref_p);
> +    stream_write_tree (ob, DECL_VALUE_EXPR (expr), ref_p);
>  
>    if (TREE_CODE (expr) == VAR_DECL)
> -    lto_output_tree_or_ref (ob, DECL_DEBUG_EXPR (expr), ref_p);
> +    stream_write_tree (ob, DECL_DEBUG_EXPR (expr), ref_p);
>  }
>  
>  
> @@ -555,10 +506,10 @@ lto_output_ts_decl_non_common_tree_pointers (struct output_block *ob,
>  {
>    if (TREE_CODE (expr) == FUNCTION_DECL)
>      {
> -      lto_output_tree_or_ref (ob, DECL_ARGUMENTS (expr), ref_p);
> -      lto_output_tree_or_ref (ob, DECL_RESULT (expr), ref_p);
> +      stream_write_tree (ob, DECL_ARGUMENTS (expr), ref_p);
> +      stream_write_tree (ob, DECL_RESULT (expr), ref_p);
>      }
> -  lto_output_tree_or_ref (ob, DECL_VINDEX (expr), ref_p);
> +  stream_write_tree (ob, DECL_VINDEX (expr), ref_p);
>  }
>  
>  
> @@ -572,12 +523,12 @@ lto_output_ts_decl_with_vis_tree_pointers (struct output_block *ob, tree expr,
>  {
>    /* Make sure we don't inadvertently set the assembler name.  */
>    if (DECL_ASSEMBLER_NAME_SET_P (expr))
> -    lto_output_tree_or_ref (ob, DECL_ASSEMBLER_NAME (expr), ref_p);
> +    stream_write_tree (ob, DECL_ASSEMBLER_NAME (expr), ref_p);
>    else
> -    output_record_start (ob, LTO_null);
> +    stream_write_tree (ob, NULL_TREE, false);
>  
> -  lto_output_tree_or_ref (ob, DECL_SECTION_NAME (expr), ref_p);
> -  lto_output_tree_or_ref (ob, DECL_COMDAT_GROUP (expr), ref_p);
> +  stream_write_tree (ob, DECL_SECTION_NAME (expr), ref_p);
> +  stream_write_tree (ob, DECL_COMDAT_GROUP (expr), ref_p);
>  }
>  
>  
> @@ -589,11 +540,11 @@ static void
>  lto_output_ts_field_decl_tree_pointers (struct output_block *ob, tree expr,
>  					bool ref_p)
>  {
> -  lto_output_tree_or_ref (ob, DECL_FIELD_OFFSET (expr), ref_p);
> -  lto_output_tree_or_ref (ob, DECL_BIT_FIELD_TYPE (expr), ref_p);
> -  lto_output_tree_or_ref (ob, DECL_QUALIFIER (expr), ref_p);
> -  lto_output_tree_or_ref (ob, DECL_FIELD_BIT_OFFSET (expr), ref_p);
> -  lto_output_tree_or_ref (ob, DECL_FCONTEXT (expr), ref_p);
> +  stream_write_tree (ob, DECL_FIELD_OFFSET (expr), ref_p);
> +  stream_write_tree (ob, DECL_BIT_FIELD_TYPE (expr), ref_p);
> +  stream_write_tree (ob, DECL_QUALIFIER (expr), ref_p);
> +  stream_write_tree (ob, DECL_FIELD_BIT_OFFSET (expr), ref_p);
> +  stream_write_tree (ob, DECL_FCONTEXT (expr), ref_p);
>    lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
>  }
>  
> @@ -608,10 +559,9 @@ lto_output_ts_function_decl_tree_pointers (struct output_block *ob, tree expr,
>  {
>    /* DECL_STRUCT_FUNCTION is handled by lto_streamer-out.c:output_function
>       or by pph-specific code.  */
> -  lto_output_tree_or_ref (ob, DECL_FUNCTION_PERSONALITY (expr), ref_p);
> -  lto_output_tree_or_ref (ob, DECL_FUNCTION_SPECIFIC_TARGET (expr), ref_p);
> -  lto_output_tree_or_ref (ob, DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr),
> -			  ref_p);
> +  stream_write_tree (ob, DECL_FUNCTION_PERSONALITY (expr), ref_p);
> +  stream_write_tree (ob, DECL_FUNCTION_SPECIFIC_TARGET (expr), ref_p);
> +  stream_write_tree (ob, DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr), ref_p);
>  }
>  
>  
> @@ -623,19 +573,19 @@ static void
>  lto_output_ts_type_common_tree_pointers (struct output_block *ob, tree expr,
>  					 bool ref_p)
>  {
> -  lto_output_tree_or_ref (ob, TYPE_SIZE (expr), ref_p);
> -  lto_output_tree_or_ref (ob, TYPE_SIZE_UNIT (expr), ref_p);
> -  lto_output_tree_or_ref (ob, TYPE_ATTRIBUTES (expr), ref_p);
> -  lto_output_tree_or_ref (ob, TYPE_NAME (expr), ref_p);
> +  stream_write_tree (ob, TYPE_SIZE (expr), ref_p);
> +  stream_write_tree (ob, TYPE_SIZE_UNIT (expr), ref_p);
> +  stream_write_tree (ob, TYPE_ATTRIBUTES (expr), ref_p);
> +  stream_write_tree (ob, TYPE_NAME (expr), ref_p);
>    /* Do not stream TYPE_POINTER_TO or TYPE_REFERENCE_TO.  They will be
>       reconstructed during fixup.  */
>    /* Do not stream TYPE_NEXT_VARIANT, we reconstruct the variant lists
>       during fixup.  */
> -  lto_output_tree_or_ref (ob, TYPE_MAIN_VARIANT (expr), ref_p);
> -  lto_output_tree_or_ref (ob, TYPE_CONTEXT (expr), ref_p);
> +  stream_write_tree (ob, TYPE_MAIN_VARIANT (expr), ref_p);
> +  stream_write_tree (ob, TYPE_CONTEXT (expr), ref_p);
>    /* TYPE_CANONICAL is re-computed during type merging, so no need
>       to stream it here.  */
> -  lto_output_tree_or_ref (ob, TYPE_STUB_DECL (expr), ref_p);
> +  stream_write_tree (ob, TYPE_STUB_DECL (expr), ref_p);
>  }
>  
>  /* Write all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
> @@ -647,20 +597,20 @@ lto_output_ts_type_non_common_tree_pointers (struct output_block *ob,
>  					     tree expr, bool ref_p)
>  {
>    if (TREE_CODE (expr) == ENUMERAL_TYPE)
> -    lto_output_tree_or_ref (ob, TYPE_VALUES (expr), ref_p);
> +    stream_write_tree (ob, TYPE_VALUES (expr), ref_p);
>    else if (TREE_CODE (expr) == ARRAY_TYPE)
> -    lto_output_tree_or_ref (ob, TYPE_DOMAIN (expr), ref_p);
> +    stream_write_tree (ob, TYPE_DOMAIN (expr), ref_p);
>    else if (RECORD_OR_UNION_TYPE_P (expr))
> -    lto_output_tree_or_ref (ob, TYPE_FIELDS (expr), ref_p);
> +    stream_write_tree (ob, TYPE_FIELDS (expr), ref_p);
>    else if (TREE_CODE (expr) == FUNCTION_TYPE
>  	   || TREE_CODE (expr) == METHOD_TYPE)
> -    lto_output_tree_or_ref (ob, TYPE_ARG_TYPES (expr), ref_p);
> +    stream_write_tree (ob, TYPE_ARG_TYPES (expr), ref_p);
>  
>    if (!POINTER_TYPE_P (expr))
> -    lto_output_tree_or_ref (ob, TYPE_MINVAL (expr), ref_p);
> -  lto_output_tree_or_ref (ob, TYPE_MAXVAL (expr), ref_p);
> +    stream_write_tree (ob, TYPE_MINVAL (expr), ref_p);
> +  stream_write_tree (ob, TYPE_MAXVAL (expr), ref_p);
>    if (RECORD_OR_UNION_TYPE_P (expr))
> -    lto_output_tree_or_ref (ob, TYPE_BINFO (expr), ref_p);
> +    stream_write_tree (ob, TYPE_BINFO (expr), ref_p);
>  }
>  
>  
> @@ -672,8 +622,8 @@ static void
>  lto_output_ts_list_tree_pointers (struct output_block *ob, tree expr,
>  				  bool ref_p)
>  {
> -  lto_output_tree_or_ref (ob, TREE_PURPOSE (expr), ref_p);
> -  lto_output_tree_or_ref (ob, TREE_VALUE (expr), ref_p);
> +  stream_write_tree (ob, TREE_PURPOSE (expr), ref_p);
> +  stream_write_tree (ob, TREE_VALUE (expr), ref_p);
>    lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
>  }
>  
> @@ -690,7 +640,7 @@ lto_output_ts_vec_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
>    /* Note that the number of slots for EXPR has already been emitted
>       in EXPR's header (see lto_output_tree_header).  */
>    for (i = 0; i < TREE_VEC_LENGTH (expr); i++)
> -    lto_output_tree_or_ref (ob, TREE_VEC_ELT (expr, i), ref_p);
> +    stream_write_tree (ob, TREE_VEC_ELT (expr, i), ref_p);
>  }
>  
>  
> @@ -705,9 +655,9 @@ lto_output_ts_exp_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
>  
>    output_sleb128 (ob, TREE_OPERAND_LENGTH (expr));
>    for (i = 0; i < TREE_OPERAND_LENGTH (expr); i++)
> -    lto_output_tree_or_ref (ob, TREE_OPERAND (expr, i), ref_p);
> +    stream_write_tree (ob, TREE_OPERAND (expr, i), ref_p);
>    lto_output_location (ob, EXPR_LOCATION (expr));
> -  lto_output_tree_or_ref (ob, TREE_BLOCK (expr), ref_p);
> +  stream_write_tree (ob, TREE_BLOCK (expr), ref_p);
>  }
>  
>  
> @@ -728,12 +678,12 @@ lto_output_ts_block_tree_pointers (struct output_block *ob, tree expr,
>       for early inlining so drop it on the floor instead of ICEing in
>       dwarf2out.c.  */
>  
> -  lto_output_tree_or_ref (ob, BLOCK_SUPERCONTEXT (expr), ref_p);
> +  stream_write_tree (ob, BLOCK_SUPERCONTEXT (expr), ref_p);
>    /* Do not stream BLOCK_ABSTRACT_ORIGIN.  We cannot handle debug information
>       for early inlining so drop it on the floor instead of ICEing in
>       dwarf2out.c.  */
> -  lto_output_tree_or_ref (ob, BLOCK_FRAGMENT_ORIGIN (expr), ref_p);
> -  lto_output_tree_or_ref (ob, BLOCK_FRAGMENT_CHAIN (expr), ref_p);
> +  stream_write_tree (ob, BLOCK_FRAGMENT_ORIGIN (expr), ref_p);
> +  stream_write_tree (ob, BLOCK_FRAGMENT_CHAIN (expr), ref_p);
>    /* Do not output BLOCK_SUBBLOCKS.  Instead on streaming-in this
>       list is re-constructed from BLOCK_SUPERCONTEXT.  */
>  }
> @@ -754,25 +704,25 @@ lto_output_ts_binfo_tree_pointers (struct output_block *ob, tree expr,
>       EXPR's header (see lto_output_tree_header) because this length
>       is needed to build the empty BINFO node on the reader side.  */
>    FOR_EACH_VEC_ELT (tree, BINFO_BASE_BINFOS (expr), i, t)
> -    lto_output_tree_or_ref (ob, t, ref_p);
> -  output_record_start (ob, LTO_null);
> +    stream_write_tree (ob, t, ref_p);
> +  stream_write_tree (ob, NULL_TREE, false);
>  
> -  lto_output_tree_or_ref (ob, BINFO_OFFSET (expr), ref_p);
> -  lto_output_tree_or_ref (ob, BINFO_VTABLE (expr), ref_p);
> +  stream_write_tree (ob, BINFO_OFFSET (expr), ref_p);
> +  stream_write_tree (ob, BINFO_VTABLE (expr), ref_p);
>    /* BINFO_VIRTUALS is used to drive type based devirtualizatoin.  It often links
>       together large portions of programs making it harder to partition.  Becuase
>       devirtualization is interesting before inlining, only, there is no real
>       need to ship it into ltrans partition.  */
> -  lto_output_tree_or_ref (ob, flag_wpa ? NULL : BINFO_VIRTUALS (expr), ref_p);
> -  lto_output_tree_or_ref (ob, BINFO_VPTR_FIELD (expr), ref_p);
> +  stream_write_tree (ob, flag_wpa ? NULL : BINFO_VIRTUALS (expr), ref_p);
> +  stream_write_tree (ob, BINFO_VPTR_FIELD (expr), ref_p);
>  
>    output_uleb128 (ob, VEC_length (tree, BINFO_BASE_ACCESSES (expr)));
>    FOR_EACH_VEC_ELT (tree, BINFO_BASE_ACCESSES (expr), i, t)
> -    lto_output_tree_or_ref (ob, t, ref_p);
> +    stream_write_tree (ob, t, ref_p);
>  
> -  lto_output_tree_or_ref (ob, BINFO_INHERITANCE_CHAIN (expr), ref_p);
> -  lto_output_tree_or_ref (ob, BINFO_SUBVTT_INDEX (expr), ref_p);
> -  lto_output_tree_or_ref (ob, BINFO_VPTR_INDEX (expr), ref_p);
> +  stream_write_tree (ob, BINFO_INHERITANCE_CHAIN (expr), ref_p);
> +  stream_write_tree (ob, BINFO_SUBVTT_INDEX (expr), ref_p);
> +  stream_write_tree (ob, BINFO_VPTR_INDEX (expr), ref_p);
>  }
>  
>  
> @@ -790,8 +740,8 @@ lto_output_ts_constructor_tree_pointers (struct output_block *ob, tree expr,
>    output_uleb128 (ob, CONSTRUCTOR_NELTS (expr));
>    FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (expr), i, index, value)
>      {
> -      lto_output_tree_or_ref (ob, index, ref_p);
> -      lto_output_tree_or_ref (ob, value, ref_p);
> +      stream_write_tree (ob, index, ref_p);
> +      stream_write_tree (ob, value, ref_p);
>      }
>  }
>  
> @@ -826,11 +776,10 @@ lto_output_ts_translation_unit_decl_tree_pointers (struct output_block *ob,
>  		     TRANSLATION_UNIT_LANGUAGE (expr), true);
>  }
>  
> -/* Helper for lto_output_tree.  Write all pointer fields in EXPR to output
> -   block OB.  If REF_P is true, the leaves of EXPR are emitted as
> -   references.  */
> +/* Write all pointer fields in EXPR to output block OB.  If REF_P is true,
> +   the leaves of EXPR are emitted as references.  */
>  
> -static void
> +void
>  lto_output_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
>  {
>    enum tree_code code;
> @@ -899,9 +848,9 @@ lto_output_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
>  /* Emit header information for tree EXPR to output block OB.  The header
>     contains everything needed to instantiate an empty skeleton for
>     EXPR on the reading side.  IX is the index into the streamer cache
> -   where EXPR is stored.  REF_P is as in lto_output_tree.  */
> +   where EXPR is stored.  */
>  
> -static void
> +void
>  lto_output_tree_header (struct output_block *ob, tree expr)
>  {
>    enum LTO_tags tag;
> @@ -909,9 +858,6 @@ lto_output_tree_header (struct output_block *ob, tree expr)
>  
>    /* We should not see any tree nodes not handled by the streamer.  */
>    code = TREE_CODE (expr);
> -  if (!streamer_hooks.is_streamable (expr))
> -    internal_error ("tree code %qs is not supported in %s streams",
> -		    tree_code_name[code], streamer_hooks.name);
>  
>    /* The header of a tree node consists of its tag, the size of
>       the node, and any other information needed to instantiate
> @@ -940,128 +886,20 @@ lto_output_tree_header (struct output_block *ob, tree expr)
>      output_sleb128 (ob, TREE_VEC_LENGTH (expr));
>    else if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
>      output_uleb128 (ob, BINFO_N_BASE_BINFOS (expr));
> -
> -  /* Allow the streamer to write any streamer-specific information
> -     needed to instantiate the node when reading.  */
> -  if (streamer_hooks.output_tree_header)
> -    streamer_hooks.output_tree_header (ob, expr);
> +  else if (TREE_CODE (expr) == CALL_EXPR)
> +    output_uleb128 (ob, call_expr_nargs (expr));
>  }
>  
>  
>  /* Emit the integer constant CST to output block OB.  If REF_P is true,
>     CST's type will be emitted as a reference.  */
>  
> -static void
> +void
>  lto_output_integer_cst (struct output_block *ob, tree cst, bool ref_p)
>  {
>    output_record_start (ob, lto_tree_code_to_tag (INTEGER_CST));
> -  lto_output_tree_or_ref (ob, TREE_TYPE (cst), ref_p);
> +  stream_write_tree (ob, TREE_TYPE (cst), ref_p);
>    lto_output_1_stream (ob->main_stream, TREE_OVERFLOW_P (cst));
>    output_uleb128 (ob, TREE_INT_CST_LOW (cst));
>    output_uleb128 (ob, TREE_INT_CST_HIGH (cst));
>  }
> -
> -
> -/* Write a physical representation of tree node EXPR to output block
> -   OB.  If REF_P is true, the leaves of EXPR are emitted as references
> -   via lto_output_tree_ref.  IX is the index into the streamer cache
> -   where EXPR is stored.  */
> -
> -static void
> -lto_write_tree (struct output_block *ob, tree expr, bool ref_p)
> -{
> -  struct bitpack_d bp;
> -
> -  /* 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);
> -  pack_value_fields (&bp, expr);
> -  lto_output_bitpack (&bp);
> -
> -  /* Write all the pointer fields in EXPR.  */
> -  lto_output_tree_pointers (ob, expr, ref_p);
> -
> -  /* Call back into the streaming module to see if it needs to write
> -     anything that was not written by the common streamer.  */
> -  if (streamer_hooks.write_tree)
> -    streamer_hooks.write_tree (ob, expr, ref_p);
> -
> -  /* Mark the end of EXPR.  */
> -  output_zero (ob);
> -}
> -
> -
> -/* Emit the physical representation of tree node EXPR to output block
> -   OB.  If REF_P is true, the leaves of EXPR are emitted as references
> -   via lto_output_tree_ref.  */
> -
> -void
> -lto_output_tree (struct output_block *ob, tree expr, bool ref_p)
> -{
> -  unsigned ix;
> -  bool existed_p;
> -
> -  if (expr == NULL_TREE)
> -    {
> -      output_record_start (ob, LTO_null);
> -      return;
> -    }
> -
> -  /* INTEGER_CST nodes are special because they need their original type
> -     to be materialized by the reader (to implement TYPE_CACHED_VALUES).  */
> -  if (TREE_CODE (expr) == INTEGER_CST)
> -    {
> -      bool is_special;
> -
> -     /* There are some constants that are special to the streamer
> -	(e.g., void_zero_node, truthvalue_false_node).
> -	These constants cannot be rematerialized with
> -	build_int_cst_wide because they may actually lack a type (like
> -	void_zero_node) and they need to be pointer-identical to trees
> -	materialized by the compiler tables like global_trees or
> -	c_global_trees.
> -
> -	If the streamer told us that it has special constants, they
> -	will be preloaded in the streamer cache.  If we find a match,
> -	then stream the constant as a reference so the reader can
> -	re-materialize it from the cache.  */
> -      is_special = streamer_hooks.has_unique_integer_csts_p
> -		   && lto_streamer_cache_lookup (ob->writer_cache, expr, NULL);
> -      if (!is_special)
> -	{
> -	  lto_output_integer_cst (ob, expr, ref_p);
> -	  return;
> -	}
> -    }
> -
> -  existed_p = lto_streamer_cache_insert (ob->writer_cache, expr, &ix);
> -  if (existed_p)
> -    {
> -      /* If a node has already been streamed out, make sure that
> -	 we don't write it more than once.  Otherwise, the reader
> -	 will instantiate two different nodes for the same object.  */
> -      output_record_start (ob, LTO_tree_pickle_reference);
> -      output_uleb128 (ob, ix);
> -      lto_output_enum (ob->main_stream, LTO_tags, LTO_NUM_TAGS,
> -		       lto_tree_code_to_tag (TREE_CODE (expr)));
> -    }
> -  else 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
> -    {
> -      /* This is the first time we see EXPR, write its fields
> -	 to OB.  */
> -      lto_write_tree (ob, expr, ref_p);
> -    }
> -}
> diff --git a/gcc/tree-streamer.c b/gcc/tree-streamer.c
> index d5fe93a..0517441 100644
> --- a/gcc/tree-streamer.c
> +++ b/gcc/tree-streamer.c
> @@ -245,6 +245,66 @@ lto_streamer_cache_get (struct lto_streamer_cache_d *cache, unsigned ix)
>    return VEC_index (tree, cache->nodes, ix);
>  }
>  
> +
> +/* Record NODE in CACHE.  */
> +
> +static void
> +lto_record_common_node (struct lto_streamer_cache_d *cache, tree node)
> +{
> +  /* We have to make sure to fill exactly the same number of
> +     elements for all frontends.  That can include NULL trees.
> +     As our hash table can't deal with zero entries we'll simply stream
> +     a random other tree.  A NULL tree never will be looked up so it
> +     doesn't matter which tree we replace it with, just to be sure
> +     use error_mark_node.  */
> +  if (!node)
> +    node = error_mark_node;
> +
> +  lto_streamer_cache_append (cache, node);
> +
> +  if (POINTER_TYPE_P (node)
> +      || TREE_CODE (node) == COMPLEX_TYPE
> +      || TREE_CODE (node) == ARRAY_TYPE)
> +    lto_record_common_node (cache, TREE_TYPE (node));
> +  else if (TREE_CODE (node) == RECORD_TYPE)
> +    {
> +      /* The FIELD_DECLs of structures should be shared, so that every
> +	 COMPONENT_REF uses the same tree node when referencing a field.
> +	 Pointer equality between FIELD_DECLs is used by the alias
> +	 machinery to compute overlapping memory references (See
> +	 nonoverlapping_component_refs_p).  */
> +      tree f;
> +      for (f = TYPE_FIELDS (node); f; f = TREE_CHAIN (f))
> +	lto_record_common_node (cache, f);
> +    }
> +}
> +
> +
> +/* Preload common nodes into CACHE and make sure they are merged
> +   properly according to the gimple type table.  */
> +
> +static void
> +preload_common_nodes (struct lto_streamer_cache_d *cache)
> +{
> +  unsigned i;
> +
> +  for (i = 0; i < itk_none; i++)
> +    /* Skip itk_char.  char_type_node is dependent on -f[un]signed-char.  */
> +    if (i != itk_char)
> +      lto_record_common_node (cache, integer_types[i]);
> +
> +  for (i = 0; i < TYPE_KIND_LAST; i++)
> +    lto_record_common_node (cache, sizetype_tab[i]);
> +
> +  for (i = 0; i < TI_MAX; i++)
> +    /* Skip boolean type and constants, they are frontend dependent.  */
> +    if (i != TI_BOOLEAN_TYPE
> +	&& i != TI_BOOLEAN_FALSE
> +	&& i != TI_BOOLEAN_TRUE)
> +      lto_record_common_node (cache, global_trees[i]);
> +}
> +
> +
>  /* Create a cache of pickled nodes.  */
>  
>  struct lto_streamer_cache_d *
> @@ -259,7 +319,7 @@ lto_streamer_cache_create (void)
>    /* Load all the well-known tree nodes that are always created by
>       the compiler on startup.  This prevents writing them out
>       unnecessarily.  */
> -  streamer_hooks.preload_common_nodes (cache);
> +  preload_common_nodes (cache);
>  
>    return cache;
>  }
> diff --git a/gcc/tree-streamer.h b/gcc/tree-streamer.h
> index 652659c..a3de831 100644
> --- a/gcc/tree-streamer.h
> +++ b/gcc/tree-streamer.h
> @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3.  If not see
>  #define GCC_TREE_STREAMER_H
>  
>  #include "tree.h"
> +#include "streamer-hooks.h"
>  #include "lto-streamer.h"
>  
>  /* Cache of pickled nodes.  Used to avoid writing the same node more
> @@ -51,16 +52,36 @@ struct lto_streamer_cache_d
>    VEC(tree,heap) *nodes;
>  };
>  
> +/* Return true if tree node EXPR should be streamed as a builtin.  For
> +   these nodes, we just emit the class and function code.  */
> +static inline bool
> +lto_stream_as_builtin_p (tree expr)
> +{
> +  return (TREE_CODE (expr) == FUNCTION_DECL
> +	  && DECL_IS_BUILTIN (expr)
> +	  && (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_NORMAL
> +	      || DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD));
> +}
> +
>  /* In tree-streamer-in.c.  */
>  tree input_string_cst (struct data_in *, struct lto_input_block *);
> -tree lto_input_tree (struct lto_input_block *, struct data_in *);
>  void lto_streamer_read_tree (struct lto_input_block *, struct data_in *, tree);
>  tree lto_input_chain (struct lto_input_block *, struct data_in *);
> +tree lto_materialize_tree (struct lto_input_block *, struct data_in *,
> +			   enum LTO_tags);
> +void lto_input_tree_pointers (struct lto_input_block *, struct data_in *, tree);
> +tree lto_get_pickled_tree (struct lto_input_block *, struct data_in *);
> +tree lto_get_builtin_tree (struct lto_input_block *, struct data_in *);
> +tree lto_input_integer_cst (struct lto_input_block *, struct data_in *);
> +struct bitpack_d tree_read_bitfields (struct lto_input_block *, tree);
>  
>  /* In tree-streamer-out.c.  */
> -void lto_streamer_write_tree (struct output_block *, tree, bool);
> -void lto_output_chain (struct output_block *, tree, bool);
>  void lto_output_chain (struct output_block *, tree, bool);
> +void lto_output_tree_header (struct output_block *, tree);
> +void pack_value_fields (struct bitpack_d *, tree);
> +void lto_output_tree_pointers (struct output_block *, tree, bool);
> +void lto_output_integer_cst (struct output_block *, tree, bool);
> +void lto_output_builtin_tree (struct output_block *, tree);
>  
>  /* In tree-streamer.c.  */
>  void check_handled_ts_structures (void);
>
Michael Matz Aug. 11, 2011, 12:23 p.m. UTC | #2
Hi,

On Wed, 10 Aug 2011, Diego Novillo wrote:

>    The API in the tree streamer offers functions to read/write the
>    tree header and the body, a streamer cache and everything that
>    used to be inside the LTO streamer.  This makes no difference to
>    LTO, since it simply means that some formerly static functions are
>    now extern functions in tree-streamer*.
> 
>    The only big change for LTO is mechanical.  The low-level
>    pickling/unpickling routines in the tree streamer need to call the
>    write_tree and read_tree hooks instead of
>    lto_output_tree/lto_input_tree.  So, the bulk of this patch are
>    calls to stream_write_tree and stream_read_tree (two macros that
>    expand to streamer_hooks.write_tree and streamer_hooks.read_tree).

The obvious question: have you measured performance (with an optimized 
cc1) on a medium sized exectutable, say cc1 itself?  (I'm worrying about 
inlining that doesn't happen anymore).


Ciao,
Michael.
Diego Novillo Aug. 11, 2011, 12:30 p.m. UTC | #3
On Thu, Aug 11, 2011 at 08:23, Michael Matz <matz@suse.de> wrote:

> The obvious question: have you measured performance (with an optimized
> cc1) on a medium sized exectutable, say cc1 itself?  (I'm worrying about
> inlining that doesn't happen anymore).

Ah, good point.  No, I haven't.  I'll measure it.


Diego.
Diego Novillo Aug. 11, 2011, 12:39 p.m. UTC | #4
On Thu, Aug 11, 2011 at 04:45, Richard Guenther <rguenther@suse.de> wrote:

>> 5- Handle CALL_EXPR in lto_materialize_tree.  Despite the name this is
>>    a generic tree streaming function (the renaming patch will come
>>    in the next few days).  Handling CALL_EXPR does not
>>    affect LTO (since those nodes are never allowed), but it is a
>>    generic tree code so it makes more sense to handle it here.
>
> That's the only odd thing - because we reject it in
> lto_is_streamable ().  Why "does it make sense" to handle it there?
> I don't think it makes sense - in fact you should be able to
> replace its handling with gcc_unreachable ().  Oh, I see, this
> is in tree-streamer.c and thus to be renamed in subsequent patches?

Correct.  lto_is_streamable() will keep rejecting CALL_EXPRs, but the
generic streamer handles it because it's, after all, a generic tree.

There are other LTO-specific behaviour that need to be addressed in
the tree streamer.  For example, in
lto_output_ts_binfo_tree_pointers() we have this code:

  /* BINFO_VIRTUALS is used to drive type based devirtualizatoin.  It
often links
     together large portions of programs making it harder to partition.  Becuase
     devirtualization is interesting before inlining, only, there is no real
     need to ship it into ltrans partition.  */
  stream_write_tree (ob, flag_wpa ? NULL : BINFO_VIRTUALS (expr), ref_p);

Right now, this does not affect PPH because -fwpa is never set, but
it's a wart.  One way of addressing this would be for lto_write_tree
to clear out the BINFO_VIRTUALS on TREE_BINFO nodes before calling
lto_output_tree_pointers, but that seems gross.  Any other options?


Diego.
Diego Novillo Aug. 11, 2011, 4:49 p.m. UTC | #5
On Thu, Aug 11, 2011 at 08:23, Michael Matz <matz@suse.de> wrote:

> The obvious question: have you measured performance (with an optimized
> cc1) on a medium sized exectutable, say cc1 itself?  (I'm worrying about
> inlining that doesn't happen anymore).

I compared three things: profiled bootstrap time for C, LTO
compilation of insn-attrtab.o and LTO link of cc1.  I found no
significant differences:

Bootstrap: before = 3,177 secs.  after = 3,133 secs (-1% difference)
insn-attrtab.o: before = 83.85 secs. after = 83.69 secs (0% difference)
cc1 link: before = 57.55 secs. after = 57.19 secs (-1% difference)

I also tested on the stage1 compiler (to remove the effects of the LTO
optimizations).  Again, little to no differences:

insn-attrtab.o: before = 345.65 secs.  after = 347.29 secs (0% difference)
cc1 link: before = 99.30 secs. after = 99.39 secs (0% difference)

The effect of the callbacks is negligible.


Diego.
diff mbox

Patch

diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 333d721..9f8d905 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1002,7 +1002,8 @@  LTO_STREAMER_H = lto-streamer.h $(LINKER_PLUGIN_API_H) $(TARGET_H) \
 DATA_STREAMER_H = data-streamer.h $(VEC_H) $(LTO_STREAMER_H)
 GIMPLE_STREAMER_H = gimple-streamer.h $(LTO_STREAMER_H) $(BASIC_BLOCK_H) \
 		    $(FUNCTION_H)
-TREE_STREAMER_H = tree-streamer.h $(TREE_H) $(LTO_STREAMER_H)
+TREE_STREAMER_H = tree-streamer.h $(TREE_H) $(LTO_STREAMER_H) \
+		  $(STREAMER_HOOKS_H)
 STREAMER_HOOKS_H = streamer-hooks.h $(TREE_H)
 TREE_VECTORIZER_H = tree-vectorizer.h $(TREE_DATA_REF_H)
 IPA_PROP_H = ipa-prop.h $(TREE_H) $(VEC_H) $(CGRAPH_H) $(GIMPLE_H) alloc-pool.h
@@ -2312,7 +2313,7 @@  gimple-streamer-in.o: gimple-streamer-in.c $(CONFIG_H) $(SYSTEM_H) \
     $(TREE_STREAMER_H) $(DIAGNOSTIC_H)
 gimple-streamer-out.o: gimple-streamer-out.c $(CONFIG_H) $(SYSTEM_H) \
     coretypes.h $(GIMPLE_STREAMER_H) $(DATA_STREAMER_H) $(TREE_FLOW_H) \
-    $(LTO_STREAMER_H)
+    $(LTO_STREAMER_H) $(TREE_STREAMER_H)
 tree-streamer.o: tree-streamer.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
     $(TREE_STREAMER_H) $(STREAMER_HOOKS_H)
 tree-streamer-in.o: tree-streamer-in.c $(CONFIG_H) $(SYSTEM_H) \
diff --git a/gcc/gimple-streamer-in.c b/gcc/gimple-streamer-in.c
index dd91c73..78ab729 100644
--- a/gcc/gimple-streamer-in.c
+++ b/gcc/gimple-streamer-in.c
@@ -52,7 +52,7 @@  input_phi (struct lto_input_block *ib, basic_block bb, struct data_in *data_in,
      were in the original program.  */
   for (i = 0; i < len; i++)
     {
-      tree def = lto_input_tree (ib, data_in);
+      tree def = stream_read_tree (ib, data_in);
       int src_index = lto_input_uleb128 (ib);
       location_t arg_loc = lto_input_location (ib, data_in);
       basic_block sbb = BASIC_BLOCK_FOR_FUNCTION (fn, src_index);
@@ -103,7 +103,7 @@  input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
   gimple_set_location (stmt, lto_input_location (ib, data_in));
 
   /* Read lexical block reference.  */
-  gimple_set_block (stmt, lto_input_tree (ib, data_in));
+  gimple_set_block (stmt, stream_read_tree (ib, data_in));
 
   /* Read in all the operands.  */
   switch (code)
@@ -113,7 +113,7 @@  input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
       break;
 
     case GIMPLE_EH_MUST_NOT_THROW:
-      gimple_eh_must_not_throw_set_fndecl (stmt, lto_input_tree (ib, data_in));
+      gimple_eh_must_not_throw_set_fndecl (stmt, stream_read_tree (ib, data_in));
       break;
 
     case GIMPLE_EH_DISPATCH:
@@ -143,7 +143,7 @@  input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
     case GIMPLE_DEBUG:
       for (i = 0; i < num_ops; i++)
 	{
-	  tree op = lto_input_tree (ib, data_in);
+	  tree op = stream_read_tree (ib, data_in);
 	  gimple_set_op (stmt, i, op);
 	  if (!op)
 	    continue;
@@ -223,7 +223,7 @@  input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in,
 	    gimple_call_set_internal_fn
 	      (stmt, lto_input_enum (ib, internal_fn, IFN_LAST));
 	  else
-	    gimple_call_set_fntype (stmt, lto_input_tree (ib, data_in));
+	    gimple_call_set_fntype (stmt, stream_read_tree (ib, data_in));
 	}
       break;
 
diff --git a/gcc/gimple-streamer-out.c b/gcc/gimple-streamer-out.c
index 0a41510..233862c 100644
--- a/gcc/gimple-streamer-out.c
+++ b/gcc/gimple-streamer-out.c
@@ -27,6 +27,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "data-streamer.h"
 #include "gimple-streamer.h"
 #include "lto-streamer.h"
+#include "tree-streamer.h"
 
 /* Output PHI function PHI to the main stream in OB.  */
 
@@ -40,7 +41,7 @@  output_phi (struct output_block *ob, gimple phi)
 
   for (i = 0; i < len; i++)
     {
-      lto_output_tree_ref (ob, gimple_phi_arg_def (phi, i));
+      stream_write_tree (ob, gimple_phi_arg_def (phi, i), true);
       output_uleb128 (ob, gimple_phi_arg_edge (phi, i)->src->index);
       lto_output_location (ob, gimple_phi_arg_location (phi, i));
     }
@@ -76,7 +77,7 @@  output_gimple_stmt (struct output_block *ob, gimple stmt)
   lto_output_location (ob, gimple_location (stmt));
 
   /* Emit the lexical block holding STMT.  */
-  lto_output_tree (ob, gimple_block (stmt), true);
+  stream_write_tree (ob, gimple_block (stmt), true);
 
   /* Emit the operands.  */
   switch (gimple_code (stmt))
@@ -86,7 +87,7 @@  output_gimple_stmt (struct output_block *ob, gimple stmt)
       break;
 
     case GIMPLE_EH_MUST_NOT_THROW:
-      lto_output_tree_ref (ob, gimple_eh_must_not_throw_fndecl (stmt));
+      stream_write_tree (ob, gimple_eh_must_not_throw_fndecl (stmt), true);
       break;
 
     case GIMPLE_EH_DISPATCH:
@@ -133,7 +134,7 @@  output_gimple_stmt (struct output_block *ob, gimple stmt)
 		  TREE_THIS_VOLATILE (*basep) = volatilep;
 		}
 	    }
-	  lto_output_tree_ref (ob, op);
+	  stream_write_tree (ob, op, true);
 	}
       if (is_gimple_call (stmt))
 	{
@@ -141,7 +142,7 @@  output_gimple_stmt (struct output_block *ob, gimple stmt)
 	    lto_output_enum (ob->main_stream, internal_fn,
 			     IFN_LAST, gimple_call_internal_fn (stmt));
 	  else
-	    lto_output_tree_ref (ob, gimple_call_fntype (stmt));
+	    stream_write_tree (ob, gimple_call_fntype (stmt), true);
 	}
       break;
 
diff --git a/gcc/ipa-inline-analysis.c b/gcc/ipa-inline-analysis.c
index bc65a45..f3214e2 100644
--- a/gcc/ipa-inline-analysis.c
+++ b/gcc/ipa-inline-analysis.c
@@ -2407,7 +2407,7 @@  inline_read_section (struct lto_file_decl_data *file_data, const char *data,
 	  struct condition c;
 	  c.operand_num = lto_input_uleb128 (&ib);
 	  c.code = (enum tree_code) lto_input_uleb128 (&ib);
-	  c.val = lto_input_tree (&ib, data_in);
+	  c.val = stream_read_tree (&ib, data_in);
 	  VEC_safe_push (condition, gc, info->conds, &c);
 	}
       count2 = lto_input_uleb128 (&ib);
@@ -2552,7 +2552,7 @@  inline_write_summary (cgraph_node_set set,
 					 c->operand_num);
 	      lto_output_uleb128_stream (ob->main_stream,
 					 c->code);
-	      lto_output_tree (ob, c->val, true);
+	      stream_write_tree (ob, c->val, true);
 	    }
 	  lto_output_uleb128_stream (ob->main_stream,
 				     VEC_length (size_time_entry, info->entry));
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 7f9f547..0997cf5 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -2652,13 +2652,13 @@  ipa_write_jump_function (struct output_block *ob,
     case IPA_JF_UNKNOWN:
       break;
     case IPA_JF_KNOWN_TYPE:
-      lto_output_tree (ob, jump_func->value.base_binfo, true);
+      stream_write_tree (ob, jump_func->value.base_binfo, true);
       break;
     case IPA_JF_CONST:
-      lto_output_tree (ob, jump_func->value.constant, true);
+      stream_write_tree (ob, jump_func->value.constant, true);
       break;
     case IPA_JF_PASS_THROUGH:
-      lto_output_tree (ob, jump_func->value.pass_through.operand, true);
+      stream_write_tree (ob, jump_func->value.pass_through.operand, true);
       lto_output_uleb128_stream (ob->main_stream,
 				 jump_func->value.pass_through.formal_id);
       lto_output_uleb128_stream (ob->main_stream,
@@ -2667,13 +2667,13 @@  ipa_write_jump_function (struct output_block *ob,
     case IPA_JF_ANCESTOR:
       lto_output_uleb128_stream (ob->main_stream,
 				 jump_func->value.ancestor.offset);
-      lto_output_tree (ob, jump_func->value.ancestor.type, true);
+      stream_write_tree (ob, jump_func->value.ancestor.type, true);
       lto_output_uleb128_stream (ob->main_stream,
 				 jump_func->value.ancestor.formal_id);
       break;
     case IPA_JF_CONST_MEMBER_PTR:
-      lto_output_tree (ob, jump_func->value.member_cst.pfn, true);
-      lto_output_tree (ob, jump_func->value.member_cst.delta, false);
+      stream_write_tree (ob, jump_func->value.member_cst.pfn, true);
+      stream_write_tree (ob, jump_func->value.member_cst.delta, false);
       break;
     }
 }
@@ -2692,24 +2692,24 @@  ipa_read_jump_function (struct lto_input_block *ib,
     case IPA_JF_UNKNOWN:
       break;
     case IPA_JF_KNOWN_TYPE:
-      jump_func->value.base_binfo = lto_input_tree (ib, data_in);
+      jump_func->value.base_binfo = stream_read_tree (ib, data_in);
       break;
     case IPA_JF_CONST:
-      jump_func->value.constant = lto_input_tree (ib, data_in);
+      jump_func->value.constant = stream_read_tree (ib, data_in);
       break;
     case IPA_JF_PASS_THROUGH:
-      jump_func->value.pass_through.operand = lto_input_tree (ib, data_in);
+      jump_func->value.pass_through.operand = stream_read_tree (ib, data_in);
       jump_func->value.pass_through.formal_id = lto_input_uleb128 (ib);
       jump_func->value.pass_through.operation = (enum tree_code) lto_input_uleb128 (ib);
       break;
     case IPA_JF_ANCESTOR:
       jump_func->value.ancestor.offset = lto_input_uleb128 (ib);
-      jump_func->value.ancestor.type = lto_input_tree (ib, data_in);
+      jump_func->value.ancestor.type = stream_read_tree (ib, data_in);
       jump_func->value.ancestor.formal_id = lto_input_uleb128 (ib);
       break;
     case IPA_JF_CONST_MEMBER_PTR:
-      jump_func->value.member_cst.pfn = lto_input_tree (ib, data_in);
-      jump_func->value.member_cst.delta = lto_input_tree (ib, data_in);
+      jump_func->value.member_cst.pfn = stream_read_tree (ib, data_in);
+      jump_func->value.member_cst.delta = stream_read_tree (ib, data_in);
       break;
     }
 }
@@ -2733,7 +2733,7 @@  ipa_write_indirect_edge_info (struct output_block *ob,
   if (ii->polymorphic)
     {
       lto_output_sleb128_stream (ob->main_stream, ii->otr_token);
-      lto_output_tree (ob, ii->otr_type, true);
+      stream_write_tree (ob, ii->otr_type, true);
     }
 }
 
@@ -2755,7 +2755,7 @@  ipa_read_indirect_edge_info (struct lto_input_block *ib,
   if (ii->polymorphic)
     {
       ii->otr_token = (HOST_WIDE_INT) lto_input_sleb128 (ib);
-      ii->otr_type = lto_input_tree (ib, data_in);
+      ii->otr_type = stream_read_tree (ib, data_in);
     }
 }
 
diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c
index c4da1ff..00462d8 100644
--- a/gcc/lto-cgraph.c
+++ b/gcc/lto-cgraph.c
@@ -1581,7 +1581,7 @@  output_node_opt_summary (struct output_block *ob,
          mechanism to store function local declarations into summaries.  */
       gcc_assert (parm);
       lto_output_uleb128_stream (ob->main_stream, parm_num);
-      lto_output_tree (ob, map->new_tree, true);
+      stream_write_tree (ob, map->new_tree, true);
       bp = bitpack_create (ob->main_stream);
       bp_pack_value (&bp, map->replace_p, 1);
       bp_pack_value (&bp, map->ref_p, 1);
@@ -1688,7 +1688,7 @@  input_node_opt_summary (struct cgraph_node *node,
 	parm_num --;
       map->parm_num = lto_input_uleb128 (ib_main);
       map->old_tree = NULL;
-      map->new_tree = lto_input_tree (ib_main, data_in);
+      map->new_tree = stream_read_tree (ib_main, data_in);
       bp = lto_input_bitpack (ib_main);
       map->replace_p = bp_unpack_value (&bp, 1);
       map->ref_p = bp_unpack_value (&bp, 1);
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index c6cba35..e43ff28 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -204,7 +204,7 @@  lto_input_location (struct lto_input_block *ib, struct data_in *data_in)
    TAG is the expected node that should be found in IB, if TAG belongs
    to one of the indexable trees, expect to read a reference index to
    be looked up in one of the symbol tables, otherwise read the pysical
-   representation of the tree using lto_input_tree.  FN is the
+   representation of the tree using stream_read_tree.  FN is the
    function scope for the read tree.  */
 
 tree
@@ -289,9 +289,9 @@  lto_input_eh_catch_list (struct lto_input_block *ib, struct data_in *data_in,
 
       /* Read the catch node.  */
       n = ggc_alloc_cleared_eh_catch_d ();
-      n->type_list = lto_input_tree (ib, data_in);
-      n->filter_list = lto_input_tree (ib, data_in);
-      n->label = lto_input_tree (ib, data_in);
+      n->type_list = stream_read_tree (ib, data_in);
+      n->filter_list = stream_read_tree (ib, data_in);
+      n->label = stream_read_tree (ib, data_in);
 
       /* Register all the types in N->FILTER_LIST.  */
       for (list = n->filter_list; list; list = TREE_CHAIN (list))
@@ -360,8 +360,8 @@  input_eh_region (struct lto_input_block *ib, struct data_in *data_in, int ix)
 	  tree l;
 
 	  r->type = ERT_ALLOWED_EXCEPTIONS;
-	  r->u.allowed.type_list = lto_input_tree (ib, data_in);
-	  r->u.allowed.label = lto_input_tree (ib, data_in);
+	  r->u.allowed.type_list = stream_read_tree (ib, data_in);
+	  r->u.allowed.label = stream_read_tree (ib, data_in);
 	  r->u.allowed.filter = lto_input_uleb128 (ib);
 
 	  for (l = r->u.allowed.type_list; l ; l = TREE_CHAIN (l))
@@ -371,7 +371,7 @@  input_eh_region (struct lto_input_block *ib, struct data_in *data_in, int ix)
 
       case LTO_ert_must_not_throw:
 	r->type = ERT_MUST_NOT_THROW;
-	r->u.must_not_throw.failure_decl = lto_input_tree (ib, data_in);
+	r->u.must_not_throw.failure_decl = stream_read_tree (ib, data_in);
 	r->u.must_not_throw.failure_loc = lto_input_location (ib, data_in);
 	break;
 
@@ -406,7 +406,7 @@  input_eh_lp (struct lto_input_block *ib, struct data_in *data_in, int ix)
   gcc_assert (lp->index == ix);
   lp->next_lp = (eh_landing_pad) (intptr_t) lto_input_sleb128 (ib);
   lp->region = (eh_region) (intptr_t) lto_input_sleb128 (ib);
-  lp->post_landing_pad = lto_input_tree (ib, data_in);
+  lp->post_landing_pad = stream_read_tree (ib, data_in);
 
   return lp;
 }
@@ -551,7 +551,7 @@  input_eh_regions (struct lto_input_block *ib, struct data_in *data_in,
       VEC_safe_grow (tree, gc, fn->eh->ttype_data, len);
       for (i = 0; i < len; i++)
 	{
-	  tree ttype = lto_input_tree (ib, data_in);
+	  tree ttype = stream_read_tree (ib, data_in);
 	  VEC_replace (tree, fn->eh->ttype_data, i, ttype);
 	}
     }
@@ -566,7 +566,7 @@  input_eh_regions (struct lto_input_block *ib, struct data_in *data_in,
 	  VEC_safe_grow (tree, gc, fn->eh->ehspec_data.arm_eabi, len);
 	  for (i = 0; i < len; i++)
 	    {
-	      tree t = lto_input_tree (ib, data_in);
+	      tree t = stream_read_tree (ib, data_in);
 	      VEC_replace (tree, fn->eh->ehspec_data.arm_eabi, i, t);
 	    }
 	}
@@ -709,7 +709,7 @@  input_ssa_names (struct lto_input_block *ib, struct data_in *data_in,
 	VEC_quick_push (tree, SSANAMES (fn), NULL_TREE);
 
       is_default_def = (lto_input_1_unsigned (ib) != 0);
-      name = lto_input_tree (ib, data_in);
+      name = stream_read_tree (ib, data_in);
       ssa_name = make_ssa_name_fn (fn, name, gimple_build_nop ());
 
       if (is_default_def)
@@ -783,8 +783,8 @@  input_struct_function_base (struct function *fn, struct data_in *data_in,
   /* tree decl;						-- ignored */
 
   /* Read the static chain and non-local goto save area.  */
-  fn->static_chain_decl = lto_input_tree (ib, data_in);
-  fn->nonlocal_goto_save_area = lto_input_tree (ib, data_in);
+  fn->static_chain_decl = stream_read_tree (ib, data_in);
+  fn->nonlocal_goto_save_area = stream_read_tree (ib, data_in);
 
   /* Read all the local symbols.  */
   len = lto_input_sleb128 (ib);
@@ -794,7 +794,7 @@  input_struct_function_base (struct function *fn, struct data_in *data_in,
       VEC_safe_grow (tree, gc, fn->local_decls, len);
       for (i = 0; i < len; i++)
 	{
-	  tree t = lto_input_tree (ib, data_in);
+	  tree t = stream_read_tree (ib, data_in);
 	  VEC_replace (tree, fn->local_decls, i, t);
 	}
     }
@@ -855,7 +855,7 @@  input_function (tree fn_decl, struct data_in *data_in,
 
   /* Read all function arguments.  We need to re-map them here to the
      arguments of the merged function declaration.  */
-  args = lto_input_tree (ib, data_in);
+  args = stream_read_tree (ib, data_in);
   for (oarg = args, narg = DECL_ARGUMENTS (fn_decl);
        oarg && narg;
        oarg = TREE_CHAIN (oarg), narg = TREE_CHAIN (narg))
@@ -876,7 +876,7 @@  input_function (tree fn_decl, struct data_in *data_in,
   input_eh_regions (ib, data_in, fn);
 
   /* Read the tree of lexical scopes for the function.  */
-  DECL_INITIAL (fn_decl) = lto_input_tree (ib, data_in);
+  DECL_INITIAL (fn_decl) = stream_read_tree (ib, data_in);
   gcc_assert (DECL_INITIAL (fn_decl));
   DECL_SAVED_TREE (fn_decl) = NULL_TREE;
   node = cgraph_get_create_node (fn_decl);
@@ -957,7 +957,7 @@  input_alias_pairs (struct lto_input_block *ib, struct data_in *data_in)
 
   clear_line_info (data_in);
 
-  var = lto_input_tree (ib, data_in);
+  var = stream_read_tree (ib, data_in);
   while (var)
     {
       const char *orig_name, *new_name;
@@ -965,7 +965,7 @@  input_alias_pairs (struct lto_input_block *ib, struct data_in *data_in)
 
       p = VEC_safe_push (alias_pair, gc, alias_pairs, NULL);
       p->decl = var;
-      p->target = lto_input_tree (ib, data_in);
+      p->target = stream_read_tree (ib, data_in);
 
       /* If the target is a static object, we may have registered a
 	 new name for it to avoid clashes between statics coming from
@@ -975,7 +975,7 @@  input_alias_pairs (struct lto_input_block *ib, struct data_in *data_in)
       if (strcmp (orig_name, new_name) != 0)
 	p->target = get_identifier (new_name);
 
-      var = lto_input_tree (ib, data_in);
+      var = stream_read_tree (ib, data_in);
     }
 }
 
@@ -1081,18 +1081,98 @@  lto_input_constructors_and_inits (struct lto_file_decl_data *file_data,
 }
 
 
-/* LTO streamer hook for reading GIMPLE trees.  IB and DATA_IN are as in
-   lto_read_tree.  EXPR is the tree was materialized by lto_read_tree and
-   needs GIMPLE specific data to be filled in.  */
+/* Read the physical representation of a tree node with tag TAG from
+   input block IB using the per-file context in DATA_IN.  */
 
-void
-lto_streamer_read_tree (struct lto_input_block *ib, struct data_in *data_in,
-			tree expr)
+static tree
+lto_read_tree (struct lto_input_block *ib, struct data_in *data_in,
+	       enum LTO_tags tag)
 {
-  if (DECL_P (expr)
-      && TREE_CODE (expr) != FUNCTION_DECL
-      && TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
-    DECL_INITIAL (expr) = lto_input_tree (ib, data_in);
+  /* Instantiate a new tree node.  */
+  tree result = lto_materialize_tree (ib, data_in, tag);
+
+  /* Enter RESULT in the reader cache.  This will make RESULT
+     available so that circular references in the rest of the tree
+     structure can be resolved in subsequent calls to stream_read_tree.  */
+  lto_streamer_cache_append (data_in->reader_cache, result);
+
+  /* Read all the bitfield values in RESULT.  Note that for LTO, we
+     only write language-independent bitfields, so no more unpacking is
+     needed.  */
+  tree_read_bitfields (ib, result);
+
+  /* Read all the pointer fields in RESULT.  */
+  lto_input_tree_pointers (ib, data_in, result);
+
+  /* Read any LTO-specific data not read by the tree streamer.  */
+  if (DECL_P (result)
+      && TREE_CODE (result) != FUNCTION_DECL
+      && TREE_CODE (result) != TRANSLATION_UNIT_DECL)
+    DECL_INITIAL (result) = stream_read_tree (ib, data_in);
+
+  /* We should never try to instantiate an MD or NORMAL builtin here.  */
+  if (TREE_CODE (result) == FUNCTION_DECL)
+    gcc_assert (!lto_stream_as_builtin_p (result));
+
+  /* end_marker = */ lto_input_1_unsigned (ib);
+
+#ifdef LTO_STREAMER_DEBUG
+  /* Remove the mapping to RESULT's original address set by
+     lto_materialize_tree.  */
+  lto_orig_address_remove (result);
+#endif
+
+  return result;
+}
+
+
+/* Read a tree from input block IB using the per-file context in
+   DATA_IN.  This context is used, for example, to resolve references
+   to previously read nodes.  */
+
+tree
+lto_input_tree (struct lto_input_block *ib, struct data_in *data_in)
+{
+  enum LTO_tags tag;
+  tree result;
+
+  tag = input_record_start (ib);
+  gcc_assert ((unsigned) tag < (unsigned) LTO_NUM_TAGS);
+
+  if (tag == LTO_null)
+    result = NULL_TREE;
+  else if (tag >= LTO_field_decl_ref && tag <= LTO_global_decl_ref)
+    {
+      /* If TAG is a reference to an indexable tree, the next value
+	 in IB is the index into the table where we expect to find
+	 that tree.  */
+      result = lto_input_tree_ref (ib, data_in, cfun, tag);
+    }
+  else if (tag == LTO_tree_pickle_reference)
+    {
+      /* If TAG is a reference to a previously read tree, look it up in
+	 the reader cache.  */
+      result = lto_get_pickled_tree (ib, data_in);
+    }
+  else if (tag == LTO_builtin_decl)
+    {
+      /* If we are going to read a built-in function, all we need is
+	 the code and class.  */
+      result = lto_get_builtin_tree (ib, data_in);
+    }
+  else if (tag == lto_tree_code_to_tag (INTEGER_CST))
+    {
+      /* For integer constants we only need the type and its hi/low
+	 words.  */
+      result = lto_input_integer_cst (ib, data_in);
+    }
+  else
+    {
+      /* Otherwise, materialize a new node from IB.  */
+      result = lto_read_tree (ib, data_in, tag);
+    }
+
+  return result;
 }
 
 
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index d8711e3..cfd3365 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -194,25 +194,11 @@  lto_output_location (struct output_block *ob, location_t loc)
    output block OB.  Otherwise, output the physical representation of
    EXPR to OB.  */
 
-void
+static void
 lto_output_tree_ref (struct output_block *ob, tree expr)
 {
   enum tree_code code;
 
-  if (expr == NULL_TREE)
-    {
-      output_record_start (ob, LTO_null);
-      return;
-    }
-
-  if (!tree_is_indexable (expr))
-    {
-      /* Even though we are emitting the physical representation of
-	 EXPR, its leaves must be emitted as references.  */
-      lto_output_tree (ob, expr, true);
-      return;
-    }
-
   if (TYPE_P (expr))
     {
       output_type_ref (ob, expr);
@@ -239,8 +225,7 @@  lto_output_tree_ref (struct output_block *ob, tree expr)
 
     case VAR_DECL:
     case DEBUG_EXPR_DECL:
-      gcc_assert (decl_function_context (expr) == NULL
-		  || TREE_STATIC (expr));
+      gcc_assert (decl_function_context (expr) == NULL || TREE_STATIC (expr));
       output_record_start (ob, LTO_global_decl_ref);
       lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr);
       break;
@@ -282,22 +267,153 @@  lto_output_tree_ref (struct output_block *ob, tree expr)
       break;
 
     default:
-      {
-	/* See if the streamer allows this node to be indexable
-	   like other global declarations.  */
-	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 ();
-	  }
-      }
+      /* No other node is indexable, so it should have been handled by
+	 lto_output_tree.  */
+      gcc_unreachable ();
+    }
+}
+
+
+/* Return true if EXPR is a tree node that can be written to disk.  */
+
+static inline bool
+lto_is_streamable (tree expr)
+{
+  enum tree_code code = TREE_CODE (expr);
+
+  /* Notice that we reject SSA_NAMEs as well.  We only emit the SSA
+     name version in lto_output_tree_ref (see output_ssa_names).  */
+  return !is_lang_specific (expr)
+	 && code != SSA_NAME
+	 && code != CALL_EXPR
+	 && code != LANG_TYPE
+	 && code != MODIFY_EXPR
+	 && code != INIT_EXPR
+	 && code != TARGET_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);
+}
+
+
+/* Write a physical representation of tree node EXPR to output block
+   OB.  If REF_P is true, the leaves of EXPR are emitted as references
+   via lto_output_tree_ref.  IX is the index into the streamer cache
+   where EXPR is stored.  */
+
+static void
+lto_write_tree (struct output_block *ob, tree expr, bool ref_p)
+{
+  struct bitpack_d bp;
+
+  if (!lto_is_streamable (expr))
+    internal_error ("tree code %qs is not supported in LTO streams",
+	            tree_code_name[TREE_CODE (expr)]);
+
+  /* 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);
+  pack_value_fields (&bp, expr);
+  lto_output_bitpack (&bp);
+
+  /* Write all the pointer fields in EXPR.  */
+  lto_output_tree_pointers (ob, expr, ref_p);
+
+  /* Write any LTO-specific data to OB.  */
+  if (DECL_P (expr)
+      && TREE_CODE (expr) != FUNCTION_DECL
+      && TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
+    {
+      /* Handle DECL_INITIAL for symbols.  */
+      tree initial = DECL_INITIAL (expr);
+      if (TREE_CODE (expr) == VAR_DECL
+	  && (TREE_STATIC (expr) || DECL_EXTERNAL (expr))
+	  && initial)
+	{
+	  lto_varpool_encoder_t varpool_encoder;
+	  struct varpool_node *vnode;
+
+	  varpool_encoder = ob->decl_state->varpool_node_encoder;
+	  vnode = varpool_get_node (expr);
+	  if (!vnode)
+	    initial = error_mark_node;
+	  else if (!lto_varpool_encoder_encode_initializer_p (varpool_encoder,
+							      vnode))
+	    initial = NULL;
+	}
+
+      stream_write_tree (ob, initial, ref_p);
+    }
+
+  /* Mark the end of EXPR.  */
+  output_zero (ob);
+}
+
+
+/* Emit the physical representation of tree node EXPR to output block
+   OB.  If REF_P is true, the leaves of EXPR are emitted as references
+   via lto_output_tree_ref.  */
+
+void
+lto_output_tree (struct output_block *ob, tree expr, bool ref_p)
+{
+  unsigned ix;
+  bool existed_p;
+
+  if (expr == NULL_TREE)
+    {
+      output_record_start (ob, LTO_null);
+      return;
+    }
+
+  if (ref_p && tree_is_indexable (expr))
+    {
+      lto_output_tree_ref (ob, expr);
+      return;
+    }
+
+  /* INTEGER_CST nodes are special because they need their original type
+     to be materialized by the reader (to implement TYPE_CACHED_VALUES).  */
+  if (TREE_CODE (expr) == INTEGER_CST)
+    {
+      lto_output_integer_cst (ob, expr, ref_p);
+      return;
+    }
+
+  existed_p = lto_streamer_cache_insert (ob->writer_cache, expr, &ix);
+  if (existed_p)
+    {
+      /* If a node has already been streamed out, make sure that
+	 we don't write it more than once.  Otherwise, the reader
+	 will instantiate two different nodes for the same object.  */
+      output_record_start (ob, LTO_tree_pickle_reference);
+      output_uleb128 (ob, ix);
+      lto_output_enum (ob->main_stream, LTO_tags, LTO_NUM_TAGS,
+		       lto_tree_code_to_tag (TREE_CODE (expr)));
+    }
+  else 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
+    {
+      /* This is the first time we see EXPR, write its fields
+	 to OB.  */
+      lto_write_tree (ob, expr, ref_p);
     }
 }
 
@@ -312,9 +428,9 @@  output_eh_try_list (struct output_block *ob, eh_catch first)
   for (n = first; n; n = n->next_catch)
     {
       output_record_start (ob, LTO_eh_catch);
-      lto_output_tree_ref (ob, n->type_list);
-      lto_output_tree_ref (ob, n->filter_list);
-      lto_output_tree_ref (ob, n->label);
+      stream_write_tree (ob, n->type_list, true);
+      stream_write_tree (ob, n->filter_list, true);
+      stream_write_tree (ob, n->label, true);
     }
 
   output_record_start (ob, LTO_null);
@@ -371,13 +487,13 @@  output_eh_region (struct output_block *ob, eh_region r)
     }
   else if (r->type == ERT_ALLOWED_EXCEPTIONS)
     {
-      lto_output_tree_ref (ob, r->u.allowed.type_list);
-      lto_output_tree_ref (ob, r->u.allowed.label);
+      stream_write_tree (ob, r->u.allowed.type_list, true);
+      stream_write_tree (ob, r->u.allowed.label, true);
       output_uleb128 (ob, r->u.allowed.filter);
     }
   else if (r->type == ERT_MUST_NOT_THROW)
     {
-      lto_output_tree_ref (ob, r->u.must_not_throw.failure_decl);
+      stream_write_tree (ob, r->u.must_not_throw.failure_decl, true);
       lto_output_location (ob, r->u.must_not_throw.failure_loc);
     }
 
@@ -411,7 +527,7 @@  output_eh_lp (struct output_block *ob, eh_landing_pad lp)
   else
     output_zero (ob);
 
-  lto_output_tree_ref (ob, lp->post_landing_pad);
+  stream_write_tree (ob, lp->post_landing_pad, true);
 }
 
 
@@ -445,7 +561,7 @@  output_eh_regions (struct output_block *ob, struct function *fn)
       /* Emit all the runtime type data.  */
       output_sleb128 (ob, VEC_length (tree, fn->eh->ttype_data));
       FOR_EACH_VEC_ELT (tree, fn->eh->ttype_data, i, ttype)
-	lto_output_tree_ref (ob, ttype);
+	stream_write_tree (ob, ttype, true);
 
       /* Emit the table of action chains.  */
       if (targetm.arm_eabi_unwinder)
@@ -453,7 +569,7 @@  output_eh_regions (struct output_block *ob, struct function *fn)
 	  tree t;
 	  output_sleb128 (ob, VEC_length (tree, fn->eh->ehspec_data.arm_eabi));
 	  FOR_EACH_VEC_ELT (tree, fn->eh->ehspec_data.arm_eabi, i, t)
-	    lto_output_tree_ref (ob, t);
+	    stream_write_tree (ob, t, true);
 	}
       else
 	{
@@ -491,7 +607,7 @@  output_ssa_names (struct output_block *ob, struct function *fn)
 
       output_uleb128 (ob, i);
       lto_output_1_stream (ob->main_stream, SSA_NAME_IS_DEFAULT_DEF (ptr));
-      lto_output_tree_ref (ob, SSA_NAME_VAR (ptr));
+      stream_write_tree (ob, SSA_NAME_VAR (ptr), true);
     }
 
   output_zero (ob);
@@ -619,13 +735,13 @@  output_struct_function_base (struct output_block *ob, struct function *fn)
   /* tree decl;						-- ignored */
 
   /* Output the static chain and non-local goto save area.  */
-  lto_output_tree_ref (ob, fn->static_chain_decl);
-  lto_output_tree_ref (ob, fn->nonlocal_goto_save_area);
+  stream_write_tree (ob, fn->static_chain_decl, true);
+  stream_write_tree (ob, fn->nonlocal_goto_save_area, true);
 
   /* Output all the local variables in the function.  */
   output_sleb128 (ob, VEC_length (tree, fn->local_decls));
   FOR_EACH_VEC_ELT (tree, fn->local_decls, i, t)
-    lto_output_tree_ref (ob, t);
+    stream_write_tree (ob, t, true);
 
   /* struct machine_function * machine;			-- ignored */
   /* struct language_function * language;		-- maybe elsewhere */
@@ -695,7 +811,7 @@  output_function (struct cgraph_node *node)
   output_struct_function_base (ob, fn);
 
   /* Output the head of the arguments list.  */
-  lto_output_tree_ref (ob, DECL_ARGUMENTS (function));
+  stream_write_tree (ob, DECL_ARGUMENTS (function), true);
 
   /* Output all the SSA names used in the function.  */
   output_ssa_names (ob, fn);
@@ -705,7 +821,7 @@  output_function (struct cgraph_node *node)
 
   /* Output DECL_INITIAL for the function, which contains the tree of
      lexical scopes.  */
-  lto_output_tree (ob, DECL_INITIAL (function), true);
+  stream_write_tree (ob, DECL_INITIAL (function), true);
 
   /* We will renumber the statements.  The code that does this uses
      the same ordering that we use for serializing them so we can use
@@ -838,8 +954,8 @@  output_unreferenced_globals (cgraph_node_set set, varpool_node_set vset)
   FOR_EACH_VEC_ELT (alias_pair, alias_pairs, i, p)
     if (output_alias_pair_p (p, defined, set, vset))
       {
-	lto_output_tree_ref (ob, p->decl);
-	lto_output_tree_ref (ob, p->target);
+	stream_write_tree (ob, p->decl, true);
+	stream_write_tree (ob, p->target, true);
       }
   symbol_alias_set_destroy (defined);
 
@@ -1009,7 +1125,7 @@  write_global_stream (struct output_block *ob,
     {
       t = lto_tree_ref_encoder_get_tree (encoder, index);
       if (!lto_streamer_cache_lookup (ob->writer_cache, t, NULL))
-	lto_output_tree (ob, t, false);
+	stream_write_tree (ob, t, false);
     }
 }
 
diff --git a/gcc/lto-streamer.c b/gcc/lto-streamer.c
index 328e654..01a681f 100644
--- a/gcc/lto-streamer.c
+++ b/gcc/lto-streamer.c
@@ -257,86 +257,6 @@  print_lto_report (void)
 }
 
 
-/* Record NODE in CACHE.  */
-
-static void
-lto_record_common_node (struct lto_streamer_cache_d *cache, tree node)
-{
-  /* We have to make sure to fill exactly the same number of
-     elements for all frontends.  That can include NULL trees.
-     As our hash table can't deal with zero entries we'll simply stream
-     a random other tree.  A NULL tree never will be looked up so it
-     doesn't matter which tree we replace it with, just to be sure
-     use error_mark_node.  */
-  if (!node)
-    node = error_mark_node;
-
-  lto_streamer_cache_append (cache, node);
-
-  if (POINTER_TYPE_P (node)
-      || TREE_CODE (node) == COMPLEX_TYPE
-      || TREE_CODE (node) == ARRAY_TYPE)
-    lto_record_common_node (cache, TREE_TYPE (node));
-  else if (TREE_CODE (node) == RECORD_TYPE)
-    {
-      /* The FIELD_DECLs of structures should be shared, so that every
-	 COMPONENT_REF uses the same tree node when referencing a field.
-	 Pointer equality between FIELD_DECLs is used by the alias
-	 machinery to compute overlapping memory references (See
-	 nonoverlapping_component_refs_p).  */
-      tree f;
-      for (f = TYPE_FIELDS (node); f; f = TREE_CHAIN (f))
-	lto_record_common_node (cache, f);
-    }
-}
-
-/* Preload common nodes into CACHE and make sure they are merged
-   properly according to the gimple type table.  */
-
-static void
-lto_preload_common_nodes (struct lto_streamer_cache_d *cache)
-{
-  unsigned i;
-
-  /* The MAIN_IDENTIFIER_NODE is normally set up by the front-end, but the
-     LTO back-end must agree. Currently, the only languages that set this
-     use the name "main".  */
-  if (main_identifier_node)
-    {
-      const char *main_name = IDENTIFIER_POINTER (main_identifier_node);
-      gcc_assert (strcmp (main_name, "main") == 0);
-    }
-  else
-    main_identifier_node = get_identifier ("main");
-
-  gcc_assert (ptrdiff_type_node == integer_type_node);
-
-  /* FIXME lto.  In the C++ front-end, fileptr_type_node is defined as a
-     variant copy of of ptr_type_node, rather than ptr_node itself.  The
-     distinction should only be relevant to the front-end, so we always
-     use the C definition here in lto1.
-
-     These should be assured in pass_ipa_free_lang_data.  */
-  gcc_assert (fileptr_type_node == ptr_type_node);
-  gcc_assert (TYPE_MAIN_VARIANT (fileptr_type_node) == ptr_type_node);
-
-  for (i = 0; i < itk_none; i++)
-    /* Skip itk_char.  char_type_node is dependent on -f[un]signed-char.  */
-    if (i != itk_char)
-      lto_record_common_node (cache, integer_types[i]);
-
-  for (i = 0; i < TYPE_KIND_LAST; i++)
-    lto_record_common_node (cache, sizetype_tab[i]);
-
-  for (i = 0; i < TI_MAX; i++)
-    /* Skip boolean type and constants, they are frontend dependent.  */
-    if (i != TI_BOOLEAN_TYPE
-	&& i != TI_BOOLEAN_FALSE
-	&& i != TI_BOOLEAN_TRUE)
-      lto_record_common_node (cache, global_trees[i]);
-}
-
-
 #ifdef LTO_STREAMER_DEBUG
 static htab_t tree_htab;
 
@@ -464,41 +384,12 @@  lto_check_version (int major, int minor)
 }
 
 
-/* Return true if EXPR is a tree node that can be written to disk.  */
-static inline bool
-lto_is_streamable (tree expr)
-{
-  enum tree_code code = TREE_CODE (expr);
-
-  /* Notice that we reject SSA_NAMEs as well.  We only emit the SSA
-     name version in lto_output_tree_ref (see output_ssa_names).  */
-  return !is_lang_specific (expr)
-	 && code != SSA_NAME
-	 && code != CALL_EXPR
-	 && code != LANG_TYPE
-	 && code != MODIFY_EXPR
-	 && code != INIT_EXPR
-	 && code != TARGET_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);
-}
-
-
 /* Initialize all the streamer hooks used for streaming GIMPLE.  */
 
 void
 lto_streamer_hooks_init (void)
 {
   streamer_hooks_init ();
-  streamer_hooks.name = "gimple";
-  streamer_hooks.preload_common_nodes = lto_preload_common_nodes;
-  streamer_hooks.is_streamable = lto_is_streamable;
-  streamer_hooks.write_tree = lto_streamer_write_tree;
-  streamer_hooks.read_tree = lto_streamer_read_tree;
+  streamer_hooks.write_tree = lto_output_tree;
+  streamer_hooks.read_tree = lto_input_tree;
 }
diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h
index 30688ad..fc0255f 100644
--- a/gcc/lto-streamer.h
+++ b/gcc/lto-streamer.h
@@ -821,6 +821,7 @@  tree lto_input_tree_ref (struct lto_input_block *, struct data_in *,
 			 struct function *, enum LTO_tags);
 void lto_tag_check_set (enum LTO_tags, int, ...);
 void lto_init_eh (void);
+tree lto_input_tree (struct lto_input_block *, struct data_in *);
 
 
 /* In lto-streamer-out.c  */
@@ -836,7 +837,6 @@  void lto_output_decl_state_streams (struct output_block *,
 void lto_output_decl_state_refs (struct output_block *,
 			         struct lto_output_stream *,
 			         struct lto_out_decl_state *);
-void lto_output_tree_ref (struct output_block *, tree);
 void lto_output_location (struct output_block *, location_t);
 
 
@@ -1030,17 +1030,6 @@  emit_label_in_global_context_p (tree label)
   return DECL_NONLOCAL (label) || FORCED_LABEL (label);
 }
 
-/* Return true if tree node EXPR should be streamed as a builtin.  For
-   these nodes, we just emit the class and function code.  */
-static inline bool
-lto_stream_as_builtin_p (tree expr)
-{
-  return (TREE_CODE (expr) == FUNCTION_DECL
-	  && DECL_IS_BUILTIN (expr)
-	  && (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_NORMAL
-	      || DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD));
-}
-
 DEFINE_DECL_STREAM_FUNCS (TYPE, type)
 DEFINE_DECL_STREAM_FUNCS (FIELD_DECL, field_decl)
 DEFINE_DECL_STREAM_FUNCS (FN_DECL, fn_decl)
diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c
index 3574da0..83c41e6 100644
--- a/gcc/lto/lto-lang.c
+++ b/gcc/lto/lto-lang.c
@@ -1099,6 +1099,7 @@  lto_init (void)
      distinction should only be relevant to the front-end, so we
      always use the C definition here in lto1.  */
   gcc_assert (fileptr_type_node == ptr_type_node);
+  gcc_assert (TYPE_MAIN_VARIANT (fileptr_type_node) == ptr_type_node);
 
   ptrdiff_type_node = integer_type_node;
 
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index 93ff805..a50e777 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -832,7 +832,7 @@  lto_read_decls (struct lto_file_decl_data *decl_data, const void *data,
     {
       tree t;
       unsigned from = VEC_length (tree, data_in->reader_cache->nodes);
-      t = lto_input_tree (&ib_main, data_in);
+      t = stream_read_tree (&ib_main, data_in);
       gcc_assert (t && ib_main.p <= ib_main.len);
       uniquify_nodes (data_in, from);
     }
diff --git a/gcc/streamer-hooks.h b/gcc/streamer-hooks.h
index 6dc9020..16c7361 100644
--- a/gcc/streamer-hooks.h
+++ b/gcc/streamer-hooks.h
@@ -39,74 +39,20 @@  struct lto_streamer_cache_d;
    Hooks marked [REQ] are required to be set.  Those marked [OPT] may
    be NULL, if the streamer does not need to implement them.  */
 struct streamer_hooks {
-  /* [REQ] A string identifying this streamer.  */
-  const char *name;
-
-  /* [REQ] Called by lto_streamer_cache_create to instantiate a cache of
-     well-known nodes.  These are tree nodes that are always
-     instantiated by the compiler on startup.  Additionally, these
-     nodes need to be shared.  This function should call
-     lto_streamer_cache_append on every tree node that it wishes to
-     preload in the streamer cache.  This way, the writer will only
-     write out a reference to the tree and the reader will instantiate
-     the tree out of this pre-populated cache.  */
-  void (*preload_common_nodes) (struct lto_streamer_cache_d *);
-
-  /* [REQ] Return true if the given tree is supported by this streamer.  */
-  bool (*is_streamable) (tree);
-
-  /* [OPT] Called by lto_write_tree after writing all the common parts of
-     a tree.  If defined, the callback is in charge of writing all
-     the fields that lto_write_tree did not write out.  Arguments
-     are as in lto_write_tree.
-
-     The following tree fields are not handled by common code:
-
-	DECL_ABSTRACT_ORIGIN
-	DECL_INITIAL
-	DECL_SAVED_TREE
-
-     Callbacks may choose to ignore or handle them.  If handled,
-     the reader should read them in the exact same sequence written
-     by the writer.  */
+  /* [REQ] Called by every tree streaming routine that needs to write
+     a tree node.  The arguments are: output_block where to write the
+     node, the tree node to write and a boolean flag that should be true
+     if the caller wants to write a reference to the tree, instead of the
+     tree itself.  The referencing mechanism is up to each streamer to
+     implement.  */
   void (*write_tree) (struct output_block *, tree, bool);
 
-  /* [OPT] Called by lto_read_tree after reading all the common parts of
-     a tree.  If defined, the callback is in charge of reading all
-     the fields that lto_read_tree did not read in.  Arguments
-     are as in lto_read_tree.  */
-  void (*read_tree) (struct lto_input_block *, struct data_in *, tree);
-
-  /* [OPT] 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 global declarations).  */
-  bool (*indexable_with_decls_p) (tree);
-
-  /* [OPT] 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);
-
-  /* [OPT] Called by unpack_value_fields to retrieve any non-pointer fields
-     in the tree structure.  The arguments are as in unpack_value_fields.  */
-  void (*unpack_value_fields) (struct bitpack_d *, tree);
-
-  /* [OPT] Called by lto_materialize_tree for tree nodes that it does not
-     know how to allocate memory for.  If defined, this hook should
-     return a new tree node of the given code.  The data_in and
-     input_block arguments are passed in case the hook needs to
-     read more data from the stream to allocate the node.
-     If this hook returns NULL, then lto_materialize_tree will attempt
-     to allocate the tree by calling make_node directly.  */
-  tree (*alloc_tree) (enum tree_code, struct lto_input_block *,
-                      struct data_in *);
-
-  /* [OPT] Called by lto_output_tree_header to write any streamer-specific
-     information needed to allocate the tree.  This hook may assume
-     that the basic header data (tree code, etc) has already been
-     written.  It should only write any extra data needed to allocate
-     the node (e.g., in the case of CALL_EXPR, this hook would write
-     the number of arguments to the CALL_EXPR).  */
-  void (*output_tree_header) (struct output_block *, tree);
+  /* [REQ] Called by every tree streaming routine that needs to read
+     a tree node.  It takes two arguments: an lto_input_block pointing
+     to the buffer where to read from and a data_in instance with tables
+     and descriptors needed by the unpickling routines.  It returns the
+     tree instantiated from the stream.  */
+  tree (*read_tree) (struct lto_input_block *, struct data_in *);
 
   /* [OPT] Called by lto_input_location to retrieve the source location of the
      tree currently being read. If this hook returns NULL, lto_input_location
@@ -117,14 +63,14 @@  struct streamer_hooks {
      tree currently being written. If this hook returns NULL,
      lto_output_location defaults to calling lto_output_location_bitpack.  */
   void (*output_location) (struct output_block *, location_t);
-
-  /* [OPT] Non-zero if the streamer has special constants that cannot be
-     shared and are used in pointer-equality tests (e.g., void_zero_node,
-     truthvalue_false_node, etc).  These constants will be present in
-     the streamer cache and should be streamed as references.  */
-  unsigned has_unique_integer_csts_p : 1;
 };
 
+#define stream_write_tree(OB, EXPR, REF_P) \
+    streamer_hooks.write_tree(OB, EXPR, REF_P)
+
+#define stream_read_tree(IB, DATA_IN) \
+    streamer_hooks.read_tree(IB, DATA_IN)
+
 /* Streamer hooks.  */
 extern struct streamer_hooks streamer_hooks;
 
diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c
index 25d076e..43bbe0e 100644
--- a/gcc/tree-streamer-in.c
+++ b/gcc/tree-streamer-in.c
@@ -75,7 +75,7 @@  lto_input_chain (struct lto_input_block *ib, struct data_in *data_in)
   count = lto_input_sleb128 (ib);
   for (i = 0; i < count; i++)
     {
-      curr = lto_input_tree (ib, data_in);
+      curr = stream_read_tree (ib, data_in);
       if (prev)
 	TREE_CHAIN (prev) = curr;
       else
@@ -404,9 +404,32 @@  unpack_value_fields (struct bitpack_d *bp, tree expr)
 
   if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
     unpack_ts_translation_unit_decl_value_fields (bp, expr);
+}
+
+
+/* Read all the language-independent bitfield values for EXPR from IB.
+   Return the partially unpacked bitpack so the caller can unpack any other
+   bitfield values that the writer may have written.  */
 
-  if (streamer_hooks.unpack_value_fields)
-    streamer_hooks.unpack_value_fields (bp, expr);
+struct bitpack_d
+tree_read_bitfields (struct lto_input_block *ib, tree expr)
+{
+  enum tree_code code;
+  struct bitpack_d bp;
+
+  /* Read the bitpack of non-pointer values from IB.  */
+  bp = lto_input_bitpack (ib);
+
+  /* The first word in BP contains the code of the tree that we
+     are about to read.  */
+  code = (enum tree_code) bp_unpack_value (&bp, 16);
+  lto_tag_check (lto_tree_code_to_tag (code),
+		 lto_tree_code_to_tag (TREE_CODE (expr)));
+
+  /* Unpack all the value fields from BP.  */
+  unpack_value_fields (&bp, expr);
+
+  return bp;
 }
 
 
@@ -414,11 +437,10 @@  unpack_value_fields (struct bitpack_d *bp, tree expr)
    DATA_IN.  The code for the new tree should match TAG.  Store in
    *IX_P the index into the reader cache where the new tree is stored.  */
 
-static tree
+tree
 lto_materialize_tree (struct lto_input_block *ib, struct data_in *data_in,
 		      enum LTO_tags tag)
 {
-  struct bitpack_d bp;
   enum tree_code code;
   tree result;
 #ifdef LTO_STREAMER_DEBUG
@@ -456,17 +478,16 @@  lto_materialize_tree (struct lto_input_block *ib, struct data_in *data_in,
       unsigned HOST_WIDE_INT len = lto_input_uleb128 (ib);
       result = make_tree_binfo (len);
     }
+  else if (code == CALL_EXPR)
+    {
+      unsigned HOST_WIDE_INT nargs = lto_input_uleb128 (ib);
+      return build_vl_exp (CALL_EXPR, nargs + 3);
+    }
   else
     {
-      /* For all other nodes, see if the streamer knows how to allocate
-	 it.  */
-      if (streamer_hooks.alloc_tree)
-	result = streamer_hooks.alloc_tree (code, ib, data_in);
-
-      /* If the hook did not handle it, materialize the tree with a raw
+      /* For all other nodes, materialize the tree with a raw
 	 make_node call.  */
-      if (result == NULL_TREE)
-	result = make_node (code);
+      result = make_node (code);
     }
 
 #ifdef LTO_STREAMER_DEBUG
@@ -478,22 +499,6 @@  lto_materialize_tree (struct lto_input_block *ib, struct data_in *data_in,
   lto_orig_address_map (result, (intptr_t) orig_address_in_writer);
 #endif
 
-  /* Read the bitpack of non-pointer values from IB.  */
-  bp = lto_input_bitpack (ib);
-
-  /* The first word in BP contains the code of the tree that we
-     are about to read.  */
-  code = (enum tree_code) bp_unpack_value (&bp, 16);
-  lto_tag_check (lto_tree_code_to_tag (code), tag);
-
-  /* Unpack all the value fields from BP.  */
-  unpack_value_fields (&bp, result);
-
-  /* Enter RESULT in the reader cache.  This will make RESULT
-     available so that circular references in the rest of the tree
-     structure can be resolved in subsequent calls to lto_input_tree.  */
-  lto_streamer_cache_append (data_in->reader_cache, result);
-
   return result;
 }
 
@@ -508,7 +513,7 @@  lto_input_ts_common_tree_pointers (struct lto_input_block *ib,
 				   struct data_in *data_in, tree expr)
 {
   if (TREE_CODE (expr) != IDENTIFIER_NODE)
-    TREE_TYPE (expr) = lto_input_tree (ib, data_in);
+    TREE_TYPE (expr) = stream_read_tree (ib, data_in);
 }
 
 
@@ -532,8 +537,8 @@  static void
 lto_input_ts_complex_tree_pointers (struct lto_input_block *ib,
 				    struct data_in *data_in, tree expr)
 {
-  TREE_REALPART (expr) = lto_input_tree (ib, data_in);
-  TREE_IMAGPART (expr) = lto_input_tree (ib, data_in);
+  TREE_REALPART (expr) = stream_read_tree (ib, data_in);
+  TREE_IMAGPART (expr) = stream_read_tree (ib, data_in);
 }
 
 
@@ -545,8 +550,8 @@  static void
 lto_input_ts_decl_minimal_tree_pointers (struct lto_input_block *ib,
 					 struct data_in *data_in, tree expr)
 {
-  DECL_NAME (expr) = lto_input_tree (ib, data_in);
-  DECL_CONTEXT (expr) = lto_input_tree (ib, data_in);
+  DECL_NAME (expr) = stream_read_tree (ib, data_in);
+  DECL_CONTEXT (expr) = stream_read_tree (ib, data_in);
   DECL_SOURCE_LOCATION (expr) = lto_input_location (ib, data_in);
 }
 
@@ -559,9 +564,9 @@  static void
 lto_input_ts_decl_common_tree_pointers (struct lto_input_block *ib,
 					struct data_in *data_in, tree expr)
 {
-  DECL_SIZE (expr) = lto_input_tree (ib, data_in);
-  DECL_SIZE_UNIT (expr) = lto_input_tree (ib, data_in);
-  DECL_ATTRIBUTES (expr) = lto_input_tree (ib, data_in);
+  DECL_SIZE (expr) = stream_read_tree (ib, data_in);
+  DECL_SIZE_UNIT (expr) = stream_read_tree (ib, data_in);
+  DECL_ATTRIBUTES (expr) = stream_read_tree (ib, data_in);
 
   /* Do not stream DECL_ABSTRACT_ORIGIN.  We cannot handle debug information
      for early inlining so drop it on the floor instead of ICEing in
@@ -573,11 +578,11 @@  lto_input_ts_decl_common_tree_pointers (struct lto_input_block *ib,
   if ((TREE_CODE (expr) == VAR_DECL
        || TREE_CODE (expr) == PARM_DECL)
       && DECL_HAS_VALUE_EXPR_P (expr))
-    SET_DECL_VALUE_EXPR (expr, lto_input_tree (ib, data_in));
+    SET_DECL_VALUE_EXPR (expr, stream_read_tree (ib, data_in));
 
   if (TREE_CODE (expr) == VAR_DECL)
     {
-      tree dexpr = lto_input_tree (ib, data_in);
+      tree dexpr = stream_read_tree (ib, data_in);
       if (dexpr)
 	SET_DECL_DEBUG_EXPR (expr, dexpr);
     }
@@ -594,10 +599,10 @@  lto_input_ts_decl_non_common_tree_pointers (struct lto_input_block *ib,
 {
   if (TREE_CODE (expr) == FUNCTION_DECL)
     {
-      DECL_ARGUMENTS (expr) = lto_input_tree (ib, data_in);
-      DECL_RESULT (expr) = lto_input_tree (ib, data_in);
+      DECL_ARGUMENTS (expr) = stream_read_tree (ib, data_in);
+      DECL_RESULT (expr) = stream_read_tree (ib, data_in);
     }
-  DECL_VINDEX (expr) = lto_input_tree (ib, data_in);
+  DECL_VINDEX (expr) = stream_read_tree (ib, data_in);
 }
 
 
@@ -611,15 +616,15 @@  lto_input_ts_decl_with_vis_tree_pointers (struct lto_input_block *ib,
 {
   tree id;
 
-  id = lto_input_tree (ib, data_in);
+  id = stream_read_tree (ib, data_in);
   if (id)
     {
       gcc_assert (TREE_CODE (id) == IDENTIFIER_NODE);
       SET_DECL_ASSEMBLER_NAME (expr, id);
     }
 
-  DECL_SECTION_NAME (expr) = lto_input_tree (ib, data_in);
-  DECL_COMDAT_GROUP (expr) = lto_input_tree (ib, data_in);
+  DECL_SECTION_NAME (expr) = stream_read_tree (ib, data_in);
+  DECL_COMDAT_GROUP (expr) = stream_read_tree (ib, data_in);
 }
 
 
@@ -631,11 +636,11 @@  static void
 lto_input_ts_field_decl_tree_pointers (struct lto_input_block *ib,
 				       struct data_in *data_in, tree expr)
 {
-  DECL_FIELD_OFFSET (expr) = lto_input_tree (ib, data_in);
-  DECL_BIT_FIELD_TYPE (expr) = lto_input_tree (ib, data_in);
-  DECL_QUALIFIER (expr) = lto_input_tree (ib, data_in);
-  DECL_FIELD_BIT_OFFSET (expr) = lto_input_tree (ib, data_in);
-  DECL_FCONTEXT (expr) = lto_input_tree (ib, data_in);
+  DECL_FIELD_OFFSET (expr) = stream_read_tree (ib, data_in);
+  DECL_BIT_FIELD_TYPE (expr) = stream_read_tree (ib, data_in);
+  DECL_QUALIFIER (expr) = stream_read_tree (ib, data_in);
+  DECL_FIELD_BIT_OFFSET (expr) = stream_read_tree (ib, data_in);
+  DECL_FCONTEXT (expr) = stream_read_tree (ib, data_in);
   TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
 }
 
@@ -650,9 +655,9 @@  lto_input_ts_function_decl_tree_pointers (struct lto_input_block *ib,
 {
   /* DECL_STRUCT_FUNCTION is handled by lto_input_function.  FIXME lto,
      maybe it should be handled here?  */
-  DECL_FUNCTION_PERSONALITY (expr) = lto_input_tree (ib, data_in);
-  DECL_FUNCTION_SPECIFIC_TARGET (expr) = lto_input_tree (ib, data_in);
-  DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr) = lto_input_tree (ib, data_in);
+  DECL_FUNCTION_PERSONALITY (expr) = stream_read_tree (ib, data_in);
+  DECL_FUNCTION_SPECIFIC_TARGET (expr) = stream_read_tree (ib, data_in);
+  DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr) = stream_read_tree (ib, data_in);
 
   /* If the file contains a function with an EH personality set,
      then it was compiled with -fexceptions.  In that case, initialize
@@ -670,19 +675,19 @@  static void
 lto_input_ts_type_common_tree_pointers (struct lto_input_block *ib,
 					struct data_in *data_in, tree expr)
 {
-  TYPE_SIZE (expr) = lto_input_tree (ib, data_in);
-  TYPE_SIZE_UNIT (expr) = lto_input_tree (ib, data_in);
-  TYPE_ATTRIBUTES (expr) = lto_input_tree (ib, data_in);
-  TYPE_NAME (expr) = lto_input_tree (ib, data_in);
+  TYPE_SIZE (expr) = stream_read_tree (ib, data_in);
+  TYPE_SIZE_UNIT (expr) = stream_read_tree (ib, data_in);
+  TYPE_ATTRIBUTES (expr) = stream_read_tree (ib, data_in);
+  TYPE_NAME (expr) = stream_read_tree (ib, data_in);
   /* Do not stream TYPE_POINTER_TO or TYPE_REFERENCE_TO.  They will be
      reconstructed during fixup.  */
   /* Do not stream TYPE_NEXT_VARIANT, we reconstruct the variant lists
      during fixup.  */
-  TYPE_MAIN_VARIANT (expr) = lto_input_tree (ib, data_in);
-  TYPE_CONTEXT (expr) = lto_input_tree (ib, data_in);
+  TYPE_MAIN_VARIANT (expr) = stream_read_tree (ib, data_in);
+  TYPE_CONTEXT (expr) = stream_read_tree (ib, data_in);
   /* TYPE_CANONICAL gets re-computed during type merging.  */
   TYPE_CANONICAL (expr) = NULL_TREE;
-  TYPE_STUB_DECL (expr) = lto_input_tree (ib, data_in);
+  TYPE_STUB_DECL (expr) = stream_read_tree (ib, data_in);
 }
 
 /* Read all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
@@ -695,20 +700,20 @@  lto_input_ts_type_non_common_tree_pointers (struct lto_input_block *ib,
 					    tree expr)
 {
   if (TREE_CODE (expr) == ENUMERAL_TYPE)
-    TYPE_VALUES (expr) = lto_input_tree (ib, data_in);
+    TYPE_VALUES (expr) = stream_read_tree (ib, data_in);
   else if (TREE_CODE (expr) == ARRAY_TYPE)
-    TYPE_DOMAIN (expr) = lto_input_tree (ib, data_in);
+    TYPE_DOMAIN (expr) = stream_read_tree (ib, data_in);
   else if (RECORD_OR_UNION_TYPE_P (expr))
-    TYPE_FIELDS (expr) = lto_input_tree (ib, data_in);
+    TYPE_FIELDS (expr) = stream_read_tree (ib, data_in);
   else if (TREE_CODE (expr) == FUNCTION_TYPE
 	   || TREE_CODE (expr) == METHOD_TYPE)
-    TYPE_ARG_TYPES (expr) = lto_input_tree (ib, data_in);
+    TYPE_ARG_TYPES (expr) = stream_read_tree (ib, data_in);
 
   if (!POINTER_TYPE_P (expr))
-    TYPE_MINVAL (expr) = lto_input_tree (ib, data_in);
-  TYPE_MAXVAL (expr) = lto_input_tree (ib, data_in);
+    TYPE_MINVAL (expr) = stream_read_tree (ib, data_in);
+  TYPE_MAXVAL (expr) = stream_read_tree (ib, data_in);
   if (RECORD_OR_UNION_TYPE_P (expr))
-    TYPE_BINFO (expr) = lto_input_tree (ib, data_in);
+    TYPE_BINFO (expr) = stream_read_tree (ib, data_in);
 }
 
 
@@ -720,8 +725,8 @@  static void
 lto_input_ts_list_tree_pointers (struct lto_input_block *ib,
 				 struct data_in *data_in, tree expr)
 {
-  TREE_PURPOSE (expr) = lto_input_tree (ib, data_in);
-  TREE_VALUE (expr) = lto_input_tree (ib, data_in);
+  TREE_PURPOSE (expr) = stream_read_tree (ib, data_in);
+  TREE_VALUE (expr) = stream_read_tree (ib, data_in);
   TREE_CHAIN (expr) = lto_input_chain (ib, data_in);
 }
 
@@ -739,7 +744,7 @@  lto_input_ts_vec_tree_pointers (struct lto_input_block *ib,
   /* Note that TREE_VEC_LENGTH was read by lto_materialize_tree to
      instantiate EXPR.  */
   for (i = 0; i < TREE_VEC_LENGTH (expr); i++)
-    TREE_VEC_ELT (expr, i) = lto_input_tree (ib, data_in);
+    TREE_VEC_ELT (expr, i) = stream_read_tree (ib, data_in);
 }
 
 
@@ -759,11 +764,11 @@  lto_input_ts_exp_tree_pointers (struct lto_input_block *ib,
   gcc_assert (length == TREE_OPERAND_LENGTH (expr));
 
   for (i = 0; i < length; i++)
-    TREE_OPERAND (expr, i) = lto_input_tree (ib, data_in);
+    TREE_OPERAND (expr, i) = stream_read_tree (ib, data_in);
 
   loc = lto_input_location (ib, data_in);
   SET_EXPR_LOCATION (expr, loc);
-  TREE_BLOCK (expr) = lto_input_tree (ib, data_in);
+  TREE_BLOCK (expr) = stream_read_tree (ib, data_in);
 }
 
 
@@ -784,13 +789,13 @@  lto_input_ts_block_tree_pointers (struct lto_input_block *ib,
      for early inlining so drop it on the floor instead of ICEing in
      dwarf2out.c.  */
 
-  BLOCK_SUPERCONTEXT (expr) = lto_input_tree (ib, data_in);
+  BLOCK_SUPERCONTEXT (expr) = stream_read_tree (ib, data_in);
 
   /* Do not stream BLOCK_ABSTRACT_ORIGIN.  We cannot handle debug information
      for early inlining so drop it on the floor instead of ICEing in
      dwarf2out.c.  */
-  BLOCK_FRAGMENT_ORIGIN (expr) = lto_input_tree (ib, data_in);
-  BLOCK_FRAGMENT_CHAIN (expr) = lto_input_tree (ib, data_in);
+  BLOCK_FRAGMENT_ORIGIN (expr) = stream_read_tree (ib, data_in);
+  BLOCK_FRAGMENT_CHAIN (expr) = stream_read_tree (ib, data_in);
 
   /* We re-compute BLOCK_SUBBLOCKS of our parent here instead
      of streaming it.  For non-BLOCK BLOCK_SUPERCONTEXTs we still
@@ -831,16 +836,16 @@  lto_input_ts_binfo_tree_pointers (struct lto_input_block *ib,
      list on the writer side.  */
   do
     {
-      t = lto_input_tree (ib, data_in);
+      t = stream_read_tree (ib, data_in);
       if (t)
 	VEC_quick_push (tree, BINFO_BASE_BINFOS (expr), t);
     }
   while (t);
 
-  BINFO_OFFSET (expr) = lto_input_tree (ib, data_in);
-  BINFO_VTABLE (expr) = lto_input_tree (ib, data_in);
-  BINFO_VIRTUALS (expr) = lto_input_tree (ib, data_in);
-  BINFO_VPTR_FIELD (expr) = lto_input_tree (ib, data_in);
+  BINFO_OFFSET (expr) = stream_read_tree (ib, data_in);
+  BINFO_VTABLE (expr) = stream_read_tree (ib, data_in);
+  BINFO_VIRTUALS (expr) = stream_read_tree (ib, data_in);
+  BINFO_VPTR_FIELD (expr) = stream_read_tree (ib, data_in);
 
   len = lto_input_uleb128 (ib);
   if (len > 0)
@@ -848,14 +853,14 @@  lto_input_ts_binfo_tree_pointers (struct lto_input_block *ib,
       VEC_reserve_exact (tree, gc, BINFO_BASE_ACCESSES (expr), len);
       for (i = 0; i < len; i++)
 	{
-	  tree a = lto_input_tree (ib, data_in);
+	  tree a = stream_read_tree (ib, data_in);
 	  VEC_quick_push (tree, BINFO_BASE_ACCESSES (expr), a);
 	}
     }
 
-  BINFO_INHERITANCE_CHAIN (expr) = lto_input_tree (ib, data_in);
-  BINFO_SUBVTT_INDEX (expr) = lto_input_tree (ib, data_in);
-  BINFO_VPTR_INDEX (expr) = lto_input_tree (ib, data_in);
+  BINFO_INHERITANCE_CHAIN (expr) = stream_read_tree (ib, data_in);
+  BINFO_SUBVTT_INDEX (expr) = stream_read_tree (ib, data_in);
+  BINFO_VPTR_INDEX (expr) = stream_read_tree (ib, data_in);
 }
 
 
@@ -874,8 +879,8 @@  lto_input_ts_constructor_tree_pointers (struct lto_input_block *ib,
     {
       tree index, value;
 
-      index = lto_input_tree (ib, data_in);
-      value = lto_input_tree (ib, data_in);
+      index = stream_read_tree (ib, data_in);
+      value = stream_read_tree (ib, data_in);
       CONSTRUCTOR_APPEND_ELT (CONSTRUCTOR_ELTS (expr), index, value);
     }
 }
@@ -909,11 +914,10 @@  lto_input_ts_translation_unit_decl_tree_pointers (struct lto_input_block *ib,
   VEC_safe_push (tree, gc, all_translation_units, expr);
 }
 
-/* Helper for lto_input_tree.  Read all pointer fields in EXPR from
-   input block IB.  DATA_IN contains tables and descriptors for the
-   file being read.  */
+/* Read all pointer fields in EXPR from input block IB.  DATA_IN
+   contains tables and descriptors for the file being read.  */
 
-static void
+void
 lto_input_tree_pointers (struct lto_input_block *ib, struct data_in *data_in,
 			 tree expr)
 {
@@ -980,52 +984,17 @@  lto_input_tree_pointers (struct lto_input_block *ib, struct data_in *data_in,
 }
 
 
-/* Read the physical representation of a tree node with tag TAG from
-   input block IB using the per-file context in DATA_IN.  */
-
-static tree
-lto_read_tree (struct lto_input_block *ib, struct data_in *data_in,
-	       enum LTO_tags tag)
-{
-  tree result;
-
-  result = lto_materialize_tree (ib, data_in, tag);
-
-  /* Read all the pointer fields in RESULT.  */
-  lto_input_tree_pointers (ib, data_in, result);
-
-  /* Call back into the streaming module to read anything else it
-     may need.  */
-  if (streamer_hooks.read_tree)
-    streamer_hooks.read_tree (ib, data_in, result);
-
-  /* We should never try to instantiate an MD or NORMAL builtin here.  */
-  if (TREE_CODE (result) == FUNCTION_DECL)
-    gcc_assert (!lto_stream_as_builtin_p (result));
-
-  /* end_marker = */ lto_input_1_unsigned (ib);
-
-#ifdef LTO_STREAMER_DEBUG
-  /* Remove the mapping to RESULT's original address set by
-     lto_materialize_tree.  */
-  lto_orig_address_remove (result);
-#endif
-
-  return result;
-}
-
-
 /* Read and INTEGER_CST node from input block IB using the per-file
    context in DATA_IN.  */
 
-static tree
+tree
 lto_input_integer_cst (struct lto_input_block *ib, struct data_in *data_in)
 {
   tree result, type;
   HOST_WIDE_INT low, high;
   bool overflow_p;
 
-  type = lto_input_tree (ib, data_in);
+  type = stream_read_tree (ib, data_in);
   overflow_p = (lto_input_1_unsigned (ib) != 0);
   low = lto_input_uleb128 (ib);
   high = lto_input_uleb128 (ib);
@@ -1046,7 +1015,7 @@  lto_input_integer_cst (struct lto_input_block *ib, struct data_in *data_in)
 /* Read an index IX from input block IB and return the tree node at
    DATA_IN->FILE_DATA->GLOBALS_INDEX[IX].  */
 
-static tree
+tree
 lto_get_pickled_tree (struct lto_input_block *ib, struct data_in *data_in)
 {
   unsigned HOST_WIDE_INT ix;
@@ -1065,9 +1034,9 @@  lto_get_pickled_tree (struct lto_input_block *ib, struct data_in *data_in)
 
 
 /* Read a code and class from input block IB and return the
-   corresponding builtin.  DATA_IN is as in lto_input_tree.  */
+   corresponding builtin.  DATA_IN is as in stream_read_tree.  */
 
-static tree
+tree
 lto_get_builtin_tree (struct lto_input_block *ib, struct data_in *data_in)
 {
   enum built_in_class fclass;
@@ -1104,53 +1073,3 @@  lto_get_builtin_tree (struct lto_input_block *ib, struct data_in *data_in)
 
   return result;
 }
-
-
-/* Read a tree from input block IB using the per-file context in
-   DATA_IN.  This context is used, for example, to resolve references
-   to previously read nodes.  */
-
-tree
-lto_input_tree (struct lto_input_block *ib, struct data_in *data_in)
-{
-  enum LTO_tags tag;
-  tree result;
-
-  tag = input_record_start (ib);
-  gcc_assert ((unsigned) tag < (unsigned) LTO_NUM_TAGS);
-
-  if (tag == LTO_null)
-    result = NULL_TREE;
-  else if (tag >= LTO_field_decl_ref && tag <= LTO_global_decl_ref)
-    {
-      /* If TAG is a reference to an indexable tree, the next value
-	 in IB is the index into the table where we expect to find
-	 that tree.  */
-      result = lto_input_tree_ref (ib, data_in, cfun, tag);
-    }
-  else if (tag == LTO_tree_pickle_reference)
-    {
-      /* If TAG is a reference to a previously read tree, look it up in
-	 the reader cache.  */
-      result = lto_get_pickled_tree (ib, data_in);
-    }
-  else if (tag == LTO_builtin_decl)
-    {
-      /* If we are going to read a built-in function, all we need is
-	 the code and class.  */
-      result = lto_get_builtin_tree (ib, data_in);
-    }
-  else if (tag == lto_tree_code_to_tag (INTEGER_CST))
-    {
-      /* For integer constants we only need the type and its hi/low
-	 words.  */
-      result = lto_input_integer_cst (ib, data_in);
-    }
-  else
-    {
-      /* Otherwise, materialize a new node from IB.  */
-      result = lto_read_tree (ib, data_in, tag);
-    }
-
-  return result;
-}
diff --git a/gcc/tree-streamer-out.c b/gcc/tree-streamer-out.c
index b4ec28d..08af52a 100644
--- a/gcc/tree-streamer-out.c
+++ b/gcc/tree-streamer-out.c
@@ -308,7 +308,7 @@  pack_ts_translation_unit_decl_value_fields (struct bitpack_d *bp ATTRIBUTE_UNUSE
 
 /* Pack all the non-pointer fields in EXPR into a bit pack.  */
 
-static void
+void
 pack_value_fields (struct bitpack_d *bp, tree expr)
 {
   enum tree_code code;
@@ -345,29 +345,13 @@  pack_value_fields (struct bitpack_d *bp, tree expr)
 
   if (CODE_CONTAINS_STRUCT (code, TS_TRANSLATION_UNIT_DECL))
     pack_ts_translation_unit_decl_value_fields (bp, expr);
-
-  if (streamer_hooks.pack_value_fields)
-    streamer_hooks.pack_value_fields (bp, expr);
-}
-
-
-/* If REF_P is true, emit a reference to EXPR in output block OB,
-   otherwise emit the physical representation of EXPR in OB.  */
-
-static inline void
-lto_output_tree_or_ref (struct output_block *ob, tree expr, bool ref_p)
-{
-  if (ref_p)
-    lto_output_tree_ref (ob, expr);
-  else
-    lto_output_tree (ob, expr, false);
 }
 
 
 /* Write the code and class of builtin EXPR to output block OB.  IX is
    the index into the streamer cache where EXPR is stored.*/
 
-static void
+void
 lto_output_builtin_tree (struct output_block *ob, tree expr)
 {
   gcc_assert (lto_stream_as_builtin_p (expr));
@@ -399,39 +383,6 @@  lto_output_builtin_tree (struct output_block *ob, tree expr)
 }
 
 
-/* GIMPLE hook for writing GIMPLE-specific parts of trees.  OB, EXPR
-   and REF_P are as in lto_write_tree.  */
-
-void
-lto_streamer_write_tree (struct output_block *ob, tree expr, bool ref_p)
-{
-  if (DECL_P (expr)
-      && TREE_CODE (expr) != FUNCTION_DECL
-      && TREE_CODE (expr) != TRANSLATION_UNIT_DECL)
-    {
-      /* Handle DECL_INITIAL for symbols.  */
-      tree initial = DECL_INITIAL (expr);
-      if (TREE_CODE (expr) == VAR_DECL
-	  && (TREE_STATIC (expr) || DECL_EXTERNAL (expr))
-	  && initial)
-	{
-	  lto_varpool_encoder_t varpool_encoder;
-	  struct varpool_node *vnode;
-
-	  varpool_encoder = ob->decl_state->varpool_node_encoder;
-	  vnode = varpool_get_node (expr);
-	  if (!vnode)
-	    initial = error_mark_node;
-	  else if (!lto_varpool_encoder_encode_initializer_p (varpool_encoder,
-							      vnode))
-	    initial = NULL;
-	}
-
-      lto_output_tree_or_ref (ob, initial, ref_p);
-    }
-}
-
-
 /* Emit the chain of tree nodes starting at T.  OB is the output block
    to write to.  REF_P is true if chain elements should be emitted
    as references.  */
@@ -452,7 +403,7 @@  lto_output_chain (struct output_block *ob, tree t, bool ref_p)
       saved_chain = TREE_CHAIN (t);
       TREE_CHAIN (t) = NULL_TREE;
 
-      lto_output_tree_or_ref (ob, t, ref_p);
+      stream_write_tree (ob, t, ref_p);
 
       TREE_CHAIN (t) = saved_chain;
       t = TREE_CHAIN (t);
@@ -469,7 +420,7 @@  lto_output_ts_common_tree_pointers (struct output_block *ob, tree expr,
 				    bool ref_p)
 {
   if (TREE_CODE (expr) != IDENTIFIER_NODE)
-    lto_output_tree_or_ref (ob, TREE_TYPE (expr), ref_p);
+    stream_write_tree (ob, TREE_TYPE (expr), ref_p);
 }
 
 
@@ -493,8 +444,8 @@  static void
 lto_output_ts_complex_tree_pointers (struct output_block *ob, tree expr,
 				     bool ref_p)
 {
-  lto_output_tree_or_ref (ob, TREE_REALPART (expr), ref_p);
-  lto_output_tree_or_ref (ob, TREE_IMAGPART (expr), ref_p);
+  stream_write_tree (ob, TREE_REALPART (expr), ref_p);
+  stream_write_tree (ob, TREE_IMAGPART (expr), ref_p);
 }
 
 
@@ -506,8 +457,8 @@  static void
 lto_output_ts_decl_minimal_tree_pointers (struct output_block *ob, tree expr,
 					  bool ref_p)
 {
-  lto_output_tree_or_ref (ob, DECL_NAME (expr), ref_p);
-  lto_output_tree_or_ref (ob, DECL_CONTEXT (expr), ref_p);
+  stream_write_tree (ob, DECL_NAME (expr), ref_p);
+  stream_write_tree (ob, DECL_CONTEXT (expr), ref_p);
   lto_output_location (ob, DECL_SOURCE_LOCATION (expr));
 }
 
@@ -520,13 +471,13 @@  static void
 lto_output_ts_decl_common_tree_pointers (struct output_block *ob, tree expr,
 					 bool ref_p)
 {
-  lto_output_tree_or_ref (ob, DECL_SIZE (expr), ref_p);
-  lto_output_tree_or_ref (ob, DECL_SIZE_UNIT (expr), ref_p);
+  stream_write_tree (ob, DECL_SIZE (expr), ref_p);
+  stream_write_tree (ob, DECL_SIZE_UNIT (expr), ref_p);
 
   /* Note, DECL_INITIAL is not handled here.  Since DECL_INITIAL needs
      special handling in LTO, it must be handled by streamer hooks.  */
 
-  lto_output_tree_or_ref (ob, DECL_ATTRIBUTES (expr), ref_p);
+  stream_write_tree (ob, DECL_ATTRIBUTES (expr), ref_p);
 
   /* Do not stream DECL_ABSTRACT_ORIGIN.  We cannot handle debug information
      for early inlining so drop it on the floor instead of ICEing in
@@ -538,10 +489,10 @@  lto_output_ts_decl_common_tree_pointers (struct output_block *ob, tree expr,
   if ((TREE_CODE (expr) == VAR_DECL
        || TREE_CODE (expr) == PARM_DECL)
       && DECL_HAS_VALUE_EXPR_P (expr))
-    lto_output_tree_or_ref (ob, DECL_VALUE_EXPR (expr), ref_p);
+    stream_write_tree (ob, DECL_VALUE_EXPR (expr), ref_p);
 
   if (TREE_CODE (expr) == VAR_DECL)
-    lto_output_tree_or_ref (ob, DECL_DEBUG_EXPR (expr), ref_p);
+    stream_write_tree (ob, DECL_DEBUG_EXPR (expr), ref_p);
 }
 
 
@@ -555,10 +506,10 @@  lto_output_ts_decl_non_common_tree_pointers (struct output_block *ob,
 {
   if (TREE_CODE (expr) == FUNCTION_DECL)
     {
-      lto_output_tree_or_ref (ob, DECL_ARGUMENTS (expr), ref_p);
-      lto_output_tree_or_ref (ob, DECL_RESULT (expr), ref_p);
+      stream_write_tree (ob, DECL_ARGUMENTS (expr), ref_p);
+      stream_write_tree (ob, DECL_RESULT (expr), ref_p);
     }
-  lto_output_tree_or_ref (ob, DECL_VINDEX (expr), ref_p);
+  stream_write_tree (ob, DECL_VINDEX (expr), ref_p);
 }
 
 
@@ -572,12 +523,12 @@  lto_output_ts_decl_with_vis_tree_pointers (struct output_block *ob, tree expr,
 {
   /* Make sure we don't inadvertently set the assembler name.  */
   if (DECL_ASSEMBLER_NAME_SET_P (expr))
-    lto_output_tree_or_ref (ob, DECL_ASSEMBLER_NAME (expr), ref_p);
+    stream_write_tree (ob, DECL_ASSEMBLER_NAME (expr), ref_p);
   else
-    output_record_start (ob, LTO_null);
+    stream_write_tree (ob, NULL_TREE, false);
 
-  lto_output_tree_or_ref (ob, DECL_SECTION_NAME (expr), ref_p);
-  lto_output_tree_or_ref (ob, DECL_COMDAT_GROUP (expr), ref_p);
+  stream_write_tree (ob, DECL_SECTION_NAME (expr), ref_p);
+  stream_write_tree (ob, DECL_COMDAT_GROUP (expr), ref_p);
 }
 
 
@@ -589,11 +540,11 @@  static void
 lto_output_ts_field_decl_tree_pointers (struct output_block *ob, tree expr,
 					bool ref_p)
 {
-  lto_output_tree_or_ref (ob, DECL_FIELD_OFFSET (expr), ref_p);
-  lto_output_tree_or_ref (ob, DECL_BIT_FIELD_TYPE (expr), ref_p);
-  lto_output_tree_or_ref (ob, DECL_QUALIFIER (expr), ref_p);
-  lto_output_tree_or_ref (ob, DECL_FIELD_BIT_OFFSET (expr), ref_p);
-  lto_output_tree_or_ref (ob, DECL_FCONTEXT (expr), ref_p);
+  stream_write_tree (ob, DECL_FIELD_OFFSET (expr), ref_p);
+  stream_write_tree (ob, DECL_BIT_FIELD_TYPE (expr), ref_p);
+  stream_write_tree (ob, DECL_QUALIFIER (expr), ref_p);
+  stream_write_tree (ob, DECL_FIELD_BIT_OFFSET (expr), ref_p);
+  stream_write_tree (ob, DECL_FCONTEXT (expr), ref_p);
   lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
 }
 
@@ -608,10 +559,9 @@  lto_output_ts_function_decl_tree_pointers (struct output_block *ob, tree expr,
 {
   /* DECL_STRUCT_FUNCTION is handled by lto_streamer-out.c:output_function
      or by pph-specific code.  */
-  lto_output_tree_or_ref (ob, DECL_FUNCTION_PERSONALITY (expr), ref_p);
-  lto_output_tree_or_ref (ob, DECL_FUNCTION_SPECIFIC_TARGET (expr), ref_p);
-  lto_output_tree_or_ref (ob, DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr),
-			  ref_p);
+  stream_write_tree (ob, DECL_FUNCTION_PERSONALITY (expr), ref_p);
+  stream_write_tree (ob, DECL_FUNCTION_SPECIFIC_TARGET (expr), ref_p);
+  stream_write_tree (ob, DECL_FUNCTION_SPECIFIC_OPTIMIZATION (expr), ref_p);
 }
 
 
@@ -623,19 +573,19 @@  static void
 lto_output_ts_type_common_tree_pointers (struct output_block *ob, tree expr,
 					 bool ref_p)
 {
-  lto_output_tree_or_ref (ob, TYPE_SIZE (expr), ref_p);
-  lto_output_tree_or_ref (ob, TYPE_SIZE_UNIT (expr), ref_p);
-  lto_output_tree_or_ref (ob, TYPE_ATTRIBUTES (expr), ref_p);
-  lto_output_tree_or_ref (ob, TYPE_NAME (expr), ref_p);
+  stream_write_tree (ob, TYPE_SIZE (expr), ref_p);
+  stream_write_tree (ob, TYPE_SIZE_UNIT (expr), ref_p);
+  stream_write_tree (ob, TYPE_ATTRIBUTES (expr), ref_p);
+  stream_write_tree (ob, TYPE_NAME (expr), ref_p);
   /* Do not stream TYPE_POINTER_TO or TYPE_REFERENCE_TO.  They will be
      reconstructed during fixup.  */
   /* Do not stream TYPE_NEXT_VARIANT, we reconstruct the variant lists
      during fixup.  */
-  lto_output_tree_or_ref (ob, TYPE_MAIN_VARIANT (expr), ref_p);
-  lto_output_tree_or_ref (ob, TYPE_CONTEXT (expr), ref_p);
+  stream_write_tree (ob, TYPE_MAIN_VARIANT (expr), ref_p);
+  stream_write_tree (ob, TYPE_CONTEXT (expr), ref_p);
   /* TYPE_CANONICAL is re-computed during type merging, so no need
      to stream it here.  */
-  lto_output_tree_or_ref (ob, TYPE_STUB_DECL (expr), ref_p);
+  stream_write_tree (ob, TYPE_STUB_DECL (expr), ref_p);
 }
 
 /* Write all pointer fields in the TS_TYPE_NON_COMMON structure of EXPR
@@ -647,20 +597,20 @@  lto_output_ts_type_non_common_tree_pointers (struct output_block *ob,
 					     tree expr, bool ref_p)
 {
   if (TREE_CODE (expr) == ENUMERAL_TYPE)
-    lto_output_tree_or_ref (ob, TYPE_VALUES (expr), ref_p);
+    stream_write_tree (ob, TYPE_VALUES (expr), ref_p);
   else if (TREE_CODE (expr) == ARRAY_TYPE)
-    lto_output_tree_or_ref (ob, TYPE_DOMAIN (expr), ref_p);
+    stream_write_tree (ob, TYPE_DOMAIN (expr), ref_p);
   else if (RECORD_OR_UNION_TYPE_P (expr))
-    lto_output_tree_or_ref (ob, TYPE_FIELDS (expr), ref_p);
+    stream_write_tree (ob, TYPE_FIELDS (expr), ref_p);
   else if (TREE_CODE (expr) == FUNCTION_TYPE
 	   || TREE_CODE (expr) == METHOD_TYPE)
-    lto_output_tree_or_ref (ob, TYPE_ARG_TYPES (expr), ref_p);
+    stream_write_tree (ob, TYPE_ARG_TYPES (expr), ref_p);
 
   if (!POINTER_TYPE_P (expr))
-    lto_output_tree_or_ref (ob, TYPE_MINVAL (expr), ref_p);
-  lto_output_tree_or_ref (ob, TYPE_MAXVAL (expr), ref_p);
+    stream_write_tree (ob, TYPE_MINVAL (expr), ref_p);
+  stream_write_tree (ob, TYPE_MAXVAL (expr), ref_p);
   if (RECORD_OR_UNION_TYPE_P (expr))
-    lto_output_tree_or_ref (ob, TYPE_BINFO (expr), ref_p);
+    stream_write_tree (ob, TYPE_BINFO (expr), ref_p);
 }
 
 
@@ -672,8 +622,8 @@  static void
 lto_output_ts_list_tree_pointers (struct output_block *ob, tree expr,
 				  bool ref_p)
 {
-  lto_output_tree_or_ref (ob, TREE_PURPOSE (expr), ref_p);
-  lto_output_tree_or_ref (ob, TREE_VALUE (expr), ref_p);
+  stream_write_tree (ob, TREE_PURPOSE (expr), ref_p);
+  stream_write_tree (ob, TREE_VALUE (expr), ref_p);
   lto_output_chain (ob, TREE_CHAIN (expr), ref_p);
 }
 
@@ -690,7 +640,7 @@  lto_output_ts_vec_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
   /* Note that the number of slots for EXPR has already been emitted
      in EXPR's header (see lto_output_tree_header).  */
   for (i = 0; i < TREE_VEC_LENGTH (expr); i++)
-    lto_output_tree_or_ref (ob, TREE_VEC_ELT (expr, i), ref_p);
+    stream_write_tree (ob, TREE_VEC_ELT (expr, i), ref_p);
 }
 
 
@@ -705,9 +655,9 @@  lto_output_ts_exp_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
 
   output_sleb128 (ob, TREE_OPERAND_LENGTH (expr));
   for (i = 0; i < TREE_OPERAND_LENGTH (expr); i++)
-    lto_output_tree_or_ref (ob, TREE_OPERAND (expr, i), ref_p);
+    stream_write_tree (ob, TREE_OPERAND (expr, i), ref_p);
   lto_output_location (ob, EXPR_LOCATION (expr));
-  lto_output_tree_or_ref (ob, TREE_BLOCK (expr), ref_p);
+  stream_write_tree (ob, TREE_BLOCK (expr), ref_p);
 }
 
 
@@ -728,12 +678,12 @@  lto_output_ts_block_tree_pointers (struct output_block *ob, tree expr,
      for early inlining so drop it on the floor instead of ICEing in
      dwarf2out.c.  */
 
-  lto_output_tree_or_ref (ob, BLOCK_SUPERCONTEXT (expr), ref_p);
+  stream_write_tree (ob, BLOCK_SUPERCONTEXT (expr), ref_p);
   /* Do not stream BLOCK_ABSTRACT_ORIGIN.  We cannot handle debug information
      for early inlining so drop it on the floor instead of ICEing in
      dwarf2out.c.  */
-  lto_output_tree_or_ref (ob, BLOCK_FRAGMENT_ORIGIN (expr), ref_p);
-  lto_output_tree_or_ref (ob, BLOCK_FRAGMENT_CHAIN (expr), ref_p);
+  stream_write_tree (ob, BLOCK_FRAGMENT_ORIGIN (expr), ref_p);
+  stream_write_tree (ob, BLOCK_FRAGMENT_CHAIN (expr), ref_p);
   /* Do not output BLOCK_SUBBLOCKS.  Instead on streaming-in this
      list is re-constructed from BLOCK_SUPERCONTEXT.  */
 }
@@ -754,25 +704,25 @@  lto_output_ts_binfo_tree_pointers (struct output_block *ob, tree expr,
      EXPR's header (see lto_output_tree_header) because this length
      is needed to build the empty BINFO node on the reader side.  */
   FOR_EACH_VEC_ELT (tree, BINFO_BASE_BINFOS (expr), i, t)
-    lto_output_tree_or_ref (ob, t, ref_p);
-  output_record_start (ob, LTO_null);
+    stream_write_tree (ob, t, ref_p);
+  stream_write_tree (ob, NULL_TREE, false);
 
-  lto_output_tree_or_ref (ob, BINFO_OFFSET (expr), ref_p);
-  lto_output_tree_or_ref (ob, BINFO_VTABLE (expr), ref_p);
+  stream_write_tree (ob, BINFO_OFFSET (expr), ref_p);
+  stream_write_tree (ob, BINFO_VTABLE (expr), ref_p);
   /* BINFO_VIRTUALS is used to drive type based devirtualizatoin.  It often links
      together large portions of programs making it harder to partition.  Becuase
      devirtualization is interesting before inlining, only, there is no real
      need to ship it into ltrans partition.  */
-  lto_output_tree_or_ref (ob, flag_wpa ? NULL : BINFO_VIRTUALS (expr), ref_p);
-  lto_output_tree_or_ref (ob, BINFO_VPTR_FIELD (expr), ref_p);
+  stream_write_tree (ob, flag_wpa ? NULL : BINFO_VIRTUALS (expr), ref_p);
+  stream_write_tree (ob, BINFO_VPTR_FIELD (expr), ref_p);
 
   output_uleb128 (ob, VEC_length (tree, BINFO_BASE_ACCESSES (expr)));
   FOR_EACH_VEC_ELT (tree, BINFO_BASE_ACCESSES (expr), i, t)
-    lto_output_tree_or_ref (ob, t, ref_p);
+    stream_write_tree (ob, t, ref_p);
 
-  lto_output_tree_or_ref (ob, BINFO_INHERITANCE_CHAIN (expr), ref_p);
-  lto_output_tree_or_ref (ob, BINFO_SUBVTT_INDEX (expr), ref_p);
-  lto_output_tree_or_ref (ob, BINFO_VPTR_INDEX (expr), ref_p);
+  stream_write_tree (ob, BINFO_INHERITANCE_CHAIN (expr), ref_p);
+  stream_write_tree (ob, BINFO_SUBVTT_INDEX (expr), ref_p);
+  stream_write_tree (ob, BINFO_VPTR_INDEX (expr), ref_p);
 }
 
 
@@ -790,8 +740,8 @@  lto_output_ts_constructor_tree_pointers (struct output_block *ob, tree expr,
   output_uleb128 (ob, CONSTRUCTOR_NELTS (expr));
   FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (expr), i, index, value)
     {
-      lto_output_tree_or_ref (ob, index, ref_p);
-      lto_output_tree_or_ref (ob, value, ref_p);
+      stream_write_tree (ob, index, ref_p);
+      stream_write_tree (ob, value, ref_p);
     }
 }
 
@@ -826,11 +776,10 @@  lto_output_ts_translation_unit_decl_tree_pointers (struct output_block *ob,
 		     TRANSLATION_UNIT_LANGUAGE (expr), true);
 }
 
-/* Helper for lto_output_tree.  Write all pointer fields in EXPR to output
-   block OB.  If REF_P is true, the leaves of EXPR are emitted as
-   references.  */
+/* Write all pointer fields in EXPR to output block OB.  If REF_P is true,
+   the leaves of EXPR are emitted as references.  */
 
-static void
+void
 lto_output_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
 {
   enum tree_code code;
@@ -899,9 +848,9 @@  lto_output_tree_pointers (struct output_block *ob, tree expr, bool ref_p)
 /* Emit header information for tree EXPR to output block OB.  The header
    contains everything needed to instantiate an empty skeleton for
    EXPR on the reading side.  IX is the index into the streamer cache
-   where EXPR is stored.  REF_P is as in lto_output_tree.  */
+   where EXPR is stored.  */
 
-static void
+void
 lto_output_tree_header (struct output_block *ob, tree expr)
 {
   enum LTO_tags tag;
@@ -909,9 +858,6 @@  lto_output_tree_header (struct output_block *ob, tree expr)
 
   /* We should not see any tree nodes not handled by the streamer.  */
   code = TREE_CODE (expr);
-  if (!streamer_hooks.is_streamable (expr))
-    internal_error ("tree code %qs is not supported in %s streams",
-		    tree_code_name[code], streamer_hooks.name);
 
   /* The header of a tree node consists of its tag, the size of
      the node, and any other information needed to instantiate
@@ -940,128 +886,20 @@  lto_output_tree_header (struct output_block *ob, tree expr)
     output_sleb128 (ob, TREE_VEC_LENGTH (expr));
   else if (CODE_CONTAINS_STRUCT (code, TS_BINFO))
     output_uleb128 (ob, BINFO_N_BASE_BINFOS (expr));
-
-  /* Allow the streamer to write any streamer-specific information
-     needed to instantiate the node when reading.  */
-  if (streamer_hooks.output_tree_header)
-    streamer_hooks.output_tree_header (ob, expr);
+  else if (TREE_CODE (expr) == CALL_EXPR)
+    output_uleb128 (ob, call_expr_nargs (expr));
 }
 
 
 /* Emit the integer constant CST to output block OB.  If REF_P is true,
    CST's type will be emitted as a reference.  */
 
-static void
+void
 lto_output_integer_cst (struct output_block *ob, tree cst, bool ref_p)
 {
   output_record_start (ob, lto_tree_code_to_tag (INTEGER_CST));
-  lto_output_tree_or_ref (ob, TREE_TYPE (cst), ref_p);
+  stream_write_tree (ob, TREE_TYPE (cst), ref_p);
   lto_output_1_stream (ob->main_stream, TREE_OVERFLOW_P (cst));
   output_uleb128 (ob, TREE_INT_CST_LOW (cst));
   output_uleb128 (ob, TREE_INT_CST_HIGH (cst));
 }
-
-
-/* Write a physical representation of tree node EXPR to output block
-   OB.  If REF_P is true, the leaves of EXPR are emitted as references
-   via lto_output_tree_ref.  IX is the index into the streamer cache
-   where EXPR is stored.  */
-
-static void
-lto_write_tree (struct output_block *ob, tree expr, bool ref_p)
-{
-  struct bitpack_d bp;
-
-  /* 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);
-  pack_value_fields (&bp, expr);
-  lto_output_bitpack (&bp);
-
-  /* Write all the pointer fields in EXPR.  */
-  lto_output_tree_pointers (ob, expr, ref_p);
-
-  /* Call back into the streaming module to see if it needs to write
-     anything that was not written by the common streamer.  */
-  if (streamer_hooks.write_tree)
-    streamer_hooks.write_tree (ob, expr, ref_p);
-
-  /* Mark the end of EXPR.  */
-  output_zero (ob);
-}
-
-
-/* Emit the physical representation of tree node EXPR to output block
-   OB.  If REF_P is true, the leaves of EXPR are emitted as references
-   via lto_output_tree_ref.  */
-
-void
-lto_output_tree (struct output_block *ob, tree expr, bool ref_p)
-{
-  unsigned ix;
-  bool existed_p;
-
-  if (expr == NULL_TREE)
-    {
-      output_record_start (ob, LTO_null);
-      return;
-    }
-
-  /* INTEGER_CST nodes are special because they need their original type
-     to be materialized by the reader (to implement TYPE_CACHED_VALUES).  */
-  if (TREE_CODE (expr) == INTEGER_CST)
-    {
-      bool is_special;
-
-     /* There are some constants that are special to the streamer
-	(e.g., void_zero_node, truthvalue_false_node).
-	These constants cannot be rematerialized with
-	build_int_cst_wide because they may actually lack a type (like
-	void_zero_node) and they need to be pointer-identical to trees
-	materialized by the compiler tables like global_trees or
-	c_global_trees.
-
-	If the streamer told us that it has special constants, they
-	will be preloaded in the streamer cache.  If we find a match,
-	then stream the constant as a reference so the reader can
-	re-materialize it from the cache.  */
-      is_special = streamer_hooks.has_unique_integer_csts_p
-		   && lto_streamer_cache_lookup (ob->writer_cache, expr, NULL);
-      if (!is_special)
-	{
-	  lto_output_integer_cst (ob, expr, ref_p);
-	  return;
-	}
-    }
-
-  existed_p = lto_streamer_cache_insert (ob->writer_cache, expr, &ix);
-  if (existed_p)
-    {
-      /* If a node has already been streamed out, make sure that
-	 we don't write it more than once.  Otherwise, the reader
-	 will instantiate two different nodes for the same object.  */
-      output_record_start (ob, LTO_tree_pickle_reference);
-      output_uleb128 (ob, ix);
-      lto_output_enum (ob->main_stream, LTO_tags, LTO_NUM_TAGS,
-		       lto_tree_code_to_tag (TREE_CODE (expr)));
-    }
-  else 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
-    {
-      /* This is the first time we see EXPR, write its fields
-	 to OB.  */
-      lto_write_tree (ob, expr, ref_p);
-    }
-}
diff --git a/gcc/tree-streamer.c b/gcc/tree-streamer.c
index d5fe93a..0517441 100644
--- a/gcc/tree-streamer.c
+++ b/gcc/tree-streamer.c
@@ -245,6 +245,66 @@  lto_streamer_cache_get (struct lto_streamer_cache_d *cache, unsigned ix)
   return VEC_index (tree, cache->nodes, ix);
 }
 
+
+/* Record NODE in CACHE.  */
+
+static void
+lto_record_common_node (struct lto_streamer_cache_d *cache, tree node)
+{
+  /* We have to make sure to fill exactly the same number of
+     elements for all frontends.  That can include NULL trees.
+     As our hash table can't deal with zero entries we'll simply stream
+     a random other tree.  A NULL tree never will be looked up so it
+     doesn't matter which tree we replace it with, just to be sure
+     use error_mark_node.  */
+  if (!node)
+    node = error_mark_node;
+
+  lto_streamer_cache_append (cache, node);
+
+  if (POINTER_TYPE_P (node)
+      || TREE_CODE (node) == COMPLEX_TYPE
+      || TREE_CODE (node) == ARRAY_TYPE)
+    lto_record_common_node (cache, TREE_TYPE (node));
+  else if (TREE_CODE (node) == RECORD_TYPE)
+    {
+      /* The FIELD_DECLs of structures should be shared, so that every
+	 COMPONENT_REF uses the same tree node when referencing a field.
+	 Pointer equality between FIELD_DECLs is used by the alias
+	 machinery to compute overlapping memory references (See
+	 nonoverlapping_component_refs_p).  */
+      tree f;
+      for (f = TYPE_FIELDS (node); f; f = TREE_CHAIN (f))
+	lto_record_common_node (cache, f);
+    }
+}
+
+
+/* Preload common nodes into CACHE and make sure they are merged
+   properly according to the gimple type table.  */
+
+static void
+preload_common_nodes (struct lto_streamer_cache_d *cache)
+{
+  unsigned i;
+
+  for (i = 0; i < itk_none; i++)
+    /* Skip itk_char.  char_type_node is dependent on -f[un]signed-char.  */
+    if (i != itk_char)
+      lto_record_common_node (cache, integer_types[i]);
+
+  for (i = 0; i < TYPE_KIND_LAST; i++)
+    lto_record_common_node (cache, sizetype_tab[i]);
+
+  for (i = 0; i < TI_MAX; i++)
+    /* Skip boolean type and constants, they are frontend dependent.  */
+    if (i != TI_BOOLEAN_TYPE
+	&& i != TI_BOOLEAN_FALSE
+	&& i != TI_BOOLEAN_TRUE)
+      lto_record_common_node (cache, global_trees[i]);
+}
+
+
 /* Create a cache of pickled nodes.  */
 
 struct lto_streamer_cache_d *
@@ -259,7 +319,7 @@  lto_streamer_cache_create (void)
   /* Load all the well-known tree nodes that are always created by
      the compiler on startup.  This prevents writing them out
      unnecessarily.  */
-  streamer_hooks.preload_common_nodes (cache);
+  preload_common_nodes (cache);
 
   return cache;
 }
diff --git a/gcc/tree-streamer.h b/gcc/tree-streamer.h
index 652659c..a3de831 100644
--- a/gcc/tree-streamer.h
+++ b/gcc/tree-streamer.h
@@ -23,6 +23,7 @@  along with GCC; see the file COPYING3.  If not see
 #define GCC_TREE_STREAMER_H
 
 #include "tree.h"
+#include "streamer-hooks.h"
 #include "lto-streamer.h"
 
 /* Cache of pickled nodes.  Used to avoid writing the same node more
@@ -51,16 +52,36 @@  struct lto_streamer_cache_d
   VEC(tree,heap) *nodes;
 };
 
+/* Return true if tree node EXPR should be streamed as a builtin.  For
+   these nodes, we just emit the class and function code.  */
+static inline bool
+lto_stream_as_builtin_p (tree expr)
+{
+  return (TREE_CODE (expr) == FUNCTION_DECL
+	  && DECL_IS_BUILTIN (expr)
+	  && (DECL_BUILT_IN_CLASS (expr) == BUILT_IN_NORMAL
+	      || DECL_BUILT_IN_CLASS (expr) == BUILT_IN_MD));
+}
+
 /* In tree-streamer-in.c.  */
 tree input_string_cst (struct data_in *, struct lto_input_block *);
-tree lto_input_tree (struct lto_input_block *, struct data_in *);
 void lto_streamer_read_tree (struct lto_input_block *, struct data_in *, tree);
 tree lto_input_chain (struct lto_input_block *, struct data_in *);
+tree lto_materialize_tree (struct lto_input_block *, struct data_in *,
+			   enum LTO_tags);
+void lto_input_tree_pointers (struct lto_input_block *, struct data_in *, tree);
+tree lto_get_pickled_tree (struct lto_input_block *, struct data_in *);
+tree lto_get_builtin_tree (struct lto_input_block *, struct data_in *);
+tree lto_input_integer_cst (struct lto_input_block *, struct data_in *);
+struct bitpack_d tree_read_bitfields (struct lto_input_block *, tree);
 
 /* In tree-streamer-out.c.  */
-void lto_streamer_write_tree (struct output_block *, tree, bool);
-void lto_output_chain (struct output_block *, tree, bool);
 void lto_output_chain (struct output_block *, tree, bool);
+void lto_output_tree_header (struct output_block *, tree);
+void pack_value_fields (struct bitpack_d *, tree);
+void lto_output_tree_pointers (struct output_block *, tree, bool);
+void lto_output_integer_cst (struct output_block *, tree, bool);
+void lto_output_builtin_tree (struct output_block *, tree);
 
 /* In tree-streamer.c.  */
 void check_handled_ts_structures (void);